Importing rustc-1.60.0
Test: ./build.py --lto=thin
Bug: 218368713
Change-Id: Id769ad47aab28ec7b551d06785fb811cdf441aec
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index 277cf0f..696c003 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -15,11 +15,7 @@
optional = true
features = ['unprefixed_malloc_on_supported_platforms']
-[dependencies.tikv-jemallocator]
-version = '0.4.0'
-optional = true
-
[features]
-jemalloc = ['tikv-jemalloc-sys', 'tikv-jemallocator']
+jemalloc = ['tikv-jemalloc-sys']
llvm = ['rustc_driver/llvm']
max_level_info = ['rustc_driver/max_level_info']
diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml
index 33ccd04..ee3a7b5 100644
--- a/compiler/rustc_arena/Cargo.toml
+++ b/compiler/rustc_arena/Cargo.toml
@@ -4,5 +4,4 @@
edition = "2021"
[dependencies]
-rustc_data_structures = { path = "../rustc_data_structures" }
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 6f9ecb9c..3928d70 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -45,24 +45,24 @@
end: Cell<*mut T>,
/// A vector of arena chunks.
- chunks: RefCell<Vec<TypedArenaChunk<T>>>,
+ chunks: RefCell<Vec<ArenaChunk<T>>>,
/// Marker indicating that dropping the arena causes its owned
/// instances of `T` to be dropped.
_own: PhantomData<T>,
}
-struct TypedArenaChunk<T> {
+struct ArenaChunk<T = u8> {
/// The raw storage for the arena chunk.
storage: Box<[MaybeUninit<T>]>,
/// The number of valid entries in the chunk.
entries: usize,
}
-impl<T> TypedArenaChunk<T> {
+impl<T> ArenaChunk<T> {
#[inline]
- unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
- TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
+ unsafe fn new(capacity: usize) -> ArenaChunk<T> {
+ ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
}
/// Destroys this arena chunk.
@@ -125,6 +125,11 @@
where
I: IntoIterator<Item = T>,
{
+ // This default collects into a `SmallVec` and then allocates by copying
+ // from it. The specializations below for types like `Vec` are more
+ // efficient, copying directly without the intermediate collecting step.
+ // This default could be made more efficient, like
+ // `DroplessArena::alloc_from_iter`, but it's not hot enough to bother.
#[inline]
default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
let vec: SmallVec<[_; 8]> = self.into_iter().collect();
@@ -139,7 +144,7 @@
if len == 0 {
return &mut [];
}
- // Move the content to the arena by copying and then forgetting it
+ // Move the content to the arena by copying and then forgetting it.
unsafe {
let start_ptr = arena.alloc_raw_slice(len);
self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len);
@@ -156,7 +161,7 @@
if len == 0 {
return &mut [];
}
- // Move the content to the arena by copying and then forgetting it
+ // Move the content to the arena by copying and then forgetting it.
unsafe {
let start_ptr = arena.alloc_raw_slice(len);
self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
@@ -173,7 +178,7 @@
if len == 0 {
return &mut [];
}
- // Move the content to the arena by copying and then forgetting it
+ // Move the content to the arena by copying and then forgetting it.
unsafe {
let start_ptr = arena.alloc_raw_slice(len);
self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
@@ -272,7 +277,7 @@
// Also ensure that this chunk can fit `additional`.
new_cap = cmp::max(additional, new_cap);
- let mut chunk = TypedArenaChunk::<T>::new(new_cap);
+ let mut chunk = ArenaChunk::<T>::new(new_cap);
self.ptr.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
@@ -281,7 +286,7 @@
// Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
// chunks.
- fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
+ fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk<T>) {
// Determine how much was filled.
let start = last_chunk.start() as usize;
// We obtain the value of the pointer to the first uninitialized element.
@@ -340,7 +345,7 @@
end: Cell<*mut u8>,
/// A vector of arena chunks.
- chunks: RefCell<Vec<TypedArenaChunk<u8>>>,
+ chunks: RefCell<Vec<ArenaChunk>>,
}
unsafe impl Send for DroplessArena {}
@@ -378,7 +383,7 @@
// Also ensure that this chunk can fit `additional`.
new_cap = cmp::max(additional, new_cap);
- let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
+ let mut chunk = ArenaChunk::new(new_cap);
self.start.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
@@ -520,10 +525,19 @@
}
}
-// Declare an `Arena` containing one dropless arena and many typed arenas (the
-// types of the typed arenas are specified by the arguments). The dropless
-// arena will be used for any types that impl `Copy`, and also for any of the
-// specified types that satisfy `!mem::needs_drop`.
+/// Declare an `Arena` containing one dropless arena and many typed arenas (the
+/// types of the typed arenas are specified by the arguments).
+///
+/// There are three cases of interest.
+/// - Types that are `Copy`: these need not be specified in the arguments. They
+/// will use the `DroplessArena`.
+/// - Types that are `!Copy` and `!Drop`: these must be specified in the
+/// arguments. An empty `TypedArena` will be created for each one, but the
+/// `DroplessArena` will always be used and the `TypedArena` will stay empty.
+/// This is odd but harmless, because an empty arena allocates no memory.
+/// - Types that are `!Copy` and `Drop`: these must be specified in the
+/// arguments. The `TypedArena` will be used for them.
+///
#[rustc_macro_transparency = "semitransparent"]
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
#[derive(Default)]
@@ -532,7 +546,7 @@
$($name: $crate::TypedArena<$ty>,)*
}
- pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
+ pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized {
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
fn allocate_from_iter<'a>(
arena: &'a Arena<'tcx>,
@@ -541,7 +555,7 @@
}
// Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
- impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
+ impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T {
#[inline]
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
arena.dropless.alloc(self)
@@ -555,7 +569,7 @@
}
}
$(
- impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty {
+ impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty {
#[inline]
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
if !::std::mem::needs_drop::<Self>() {
@@ -581,7 +595,7 @@
impl<'tcx> Arena<'tcx> {
#[inline]
- pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
+ pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&self, value: T) -> &mut T {
value.allocate_on(self)
}
@@ -594,7 +608,7 @@
self.dropless.alloc_slice(value)
}
- pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
+ pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>(
&'a self,
iter: impl ::std::iter::IntoIterator<Item = T>,
) -> &'a mut [T] {
@@ -603,5 +617,10 @@
}
}
+// Marker types that let us give different behaviour for arenas allocating
+// `Copy` types vs `!Copy` types.
+pub struct IsCopy;
+pub struct IsNotCopy;
+
#[cfg(test)]
mod tests;
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index a2d32cd..e9135b7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -39,6 +39,7 @@
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt;
+use std::mem;
#[cfg(test)]
mod tests;
@@ -53,7 +54,7 @@
/// ```
///
/// `'outer` is a label.
-#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic, Eq, PartialEq)]
pub struct Label {
pub ident: Ident,
}
@@ -224,7 +225,7 @@
/// Argument for a generic parameter.
Arg(GenericArg),
/// Constraint for an associated item.
- Constraint(AssocTyConstraint),
+ Constraint(AssocConstraint),
}
impl AngleBracketedArg {
@@ -1266,7 +1267,7 @@
ExprKind::Break(..) => ExprPrecedence::Break,
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
- ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
+ ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
@@ -1276,6 +1277,19 @@
ExprKind::Err => ExprPrecedence::Err,
}
}
+
+ pub fn take(&mut self) -> Self {
+ mem::replace(
+ self,
+ Expr {
+ id: DUMMY_NODE_ID,
+ kind: ExprKind::Err,
+ span: DUMMY_SP,
+ attrs: ThinVec::new(),
+ tokens: None,
+ },
+ )
+ }
}
/// Limit types of a range (inclusive or exclusive)
@@ -1423,8 +1437,6 @@
/// Output of the `asm!()` macro.
InlineAsm(P<InlineAsm>),
- /// Output of the `llvm_asm!()` macro.
- LlvmInlineAsm(P<LlvmInlineAsm>),
/// A macro invocation; pre-expansion.
MacCall(MacCall),
@@ -1845,19 +1857,38 @@
/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct AssocTyConstraint {
+pub struct AssocConstraint {
pub id: NodeId,
pub ident: Ident,
pub gen_args: Option<GenericArgs>,
- pub kind: AssocTyConstraintKind,
+ pub kind: AssocConstraintKind,
pub span: Span,
}
-/// The kinds of an `AssocTyConstraint`.
+/// The kinds of an `AssocConstraint`.
#[derive(Clone, Encodable, Decodable, Debug)]
-pub enum AssocTyConstraintKind {
- /// E.g., `A = Bar` in `Foo<A = Bar>`.
- Equality { ty: P<Ty> },
+pub enum Term {
+ Ty(P<Ty>),
+ Const(AnonConst),
+}
+
+impl From<P<Ty>> for Term {
+ fn from(v: P<Ty>) -> Self {
+ Term::Ty(v)
+ }
+}
+
+impl From<AnonConst> for Term {
+ fn from(v: AnonConst) -> Self {
+ Term::Const(v)
+ }
+}
+
+/// The kinds of an `AssocConstraint`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AssocConstraintKind {
+ /// E.g., `A = Bar`, `A = 3` in `Foo<A = Bar>` where A is an associated type.
+ Equality { term: Term },
/// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
Bound { bounds: GenericBounds },
}
@@ -1989,7 +2020,7 @@
}
}
-#[derive(Clone, PartialEq, PartialOrd, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
pub enum InlineAsmTemplatePiece {
String(String),
Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
@@ -2076,41 +2107,6 @@
pub line_spans: Vec<Span>,
}
-/// Inline assembly dialect.
-///
-/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Hash, HashStable_Generic)]
-pub enum LlvmAsmDialect {
- Att,
- Intel,
-}
-
-/// LLVM-style inline assembly.
-///
-/// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct LlvmInlineAsmOutput {
- pub constraint: Symbol,
- pub expr: P<Expr>,
- pub is_rw: bool,
- pub is_indirect: bool,
-}
-
-/// LLVM-style inline assembly.
-///
-/// E.g., `llvm_asm!("NOP");`.
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct LlvmInlineAsm {
- pub asm: Symbol,
- pub asm_str_style: StrStyle,
- pub outputs: Vec<LlvmInlineAsmOutput>,
- pub inputs: Vec<(Symbol, P<Expr>)>,
- pub clobbers: Vec<Symbol>,
- pub volatile: bool,
- pub alignstack: bool,
- pub dialect: LlvmAsmDialect,
-}
-
/// A parameter in a function header.
///
/// E.g., `bar: usize` as in `fn foo(bar: usize)`.
@@ -2229,7 +2225,7 @@
No,
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
#[derive(HashStable_Generic)]
pub enum Unsafe {
Yes(Span),
@@ -2422,8 +2418,9 @@
}
impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId {
- fn decode(d: &mut D) -> Result<AttrId, D::Error> {
- d.read_nil().map(|_| crate::attr::mk_attr_id())
+ fn decode(d: &mut D) -> AttrId {
+ d.read_unit();
+ crate::attr::mk_attr_id()
}
}
diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs
index b9c3979..9a24158 100644
--- a/compiler/rustc_ast/src/ast_like.rs
+++ b/compiler/rustc_ast/src/ast_like.rs
@@ -6,12 +6,13 @@
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
use super::{AttrVec, Attribute, Stmt, StmtKind};
-use std::fmt::Debug;
+use std::fmt;
+use std::marker::PhantomData;
/// An `AstLike` represents an AST node (or some wrapper around
/// and AST node) which stores some combination of attributes
/// and tokens.
-pub trait AstLike: Sized + Debug {
+pub trait AstLike: Sized + fmt::Debug {
/// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
/// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
/// considered 'custom' attributes
@@ -285,3 +286,37 @@
derive_has_tokens_no_attrs! {
Ty, Block, AttrItem, Pat, Path, Visibility
}
+
+/// A newtype around an `AstLike` node that implements `AstLike` itself.
+pub struct AstLikeWrapper<Wrapped, Tag> {
+ pub wrapped: Wrapped,
+ pub tag: PhantomData<Tag>,
+}
+
+impl<Wrapped, Tag> AstLikeWrapper<Wrapped, Tag> {
+ pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper<Wrapped, Tag> {
+ AstLikeWrapper { wrapped, tag: Default::default() }
+ }
+}
+
+impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstLikeWrapper<Wrapped, Tag> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("AstLikeWrapper")
+ .field("wrapped", &self.wrapped)
+ .field("tag", &self.tag)
+ .finish()
+ }
+}
+
+impl<Wrapped: AstLike, Tag> AstLike for AstLikeWrapper<Wrapped, Tag> {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS;
+ fn attrs(&self) -> &[Attribute] {
+ self.wrapped.attrs()
+ }
+ fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+ self.wrapped.visit_attrs(f)
+ }
+ fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
+ self.wrapped.tokens_mut()
+ }
+}
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index d667740..b94b8c8 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -230,7 +230,7 @@
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
- Some(MetaItemKind::from_mac_args(&self.args)?)
+ MetaItemKind::from_mac_args(&self.args)
}
}
@@ -242,6 +242,17 @@
}
}
+ pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
+ match self.kind {
+ AttrKind::DocComment(kind, data) => Some((data, kind)),
+ AttrKind::Normal(ref item, _) if item.path == sym::doc => item
+ .meta_kind()
+ .and_then(|kind| kind.value_str())
+ .map(|data| (data, CommentKind::Line)),
+ _ => None,
+ }
+ }
+
pub fn doc_str(&self) -> Option<Symbol> {
match self.kind {
AttrKind::DocComment(.., data) => Some(data),
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index ff3b501..84fe9ad 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -41,7 +41,7 @@
pub mod visit;
pub use self::ast::*;
-pub use self::ast_like::AstLike;
+pub use self::ast_like::{AstLike, AstLikeWrapper};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 9ef78aa..a81a227 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -165,8 +165,8 @@
noop_visit_lifetime(l, self);
}
- fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
- noop_visit_ty_constraint(t, self);
+ fn visit_constraint(&mut self, t: &mut AssocConstraint) {
+ noop_visit_constraint(t, self);
}
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
@@ -430,8 +430,8 @@
smallvec![arm]
}
-pub fn noop_visit_ty_constraint<T: MutVisitor>(
- AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
+pub fn noop_visit_constraint<T: MutVisitor>(
+ AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
vis: &mut T,
) {
vis.visit_id(id);
@@ -440,12 +440,11 @@
vis.visit_generic_args(gen_args);
}
match kind {
- AssocTyConstraintKind::Equality { ref mut ty } => {
- vis.visit_ty(ty);
- }
- AssocTyConstraintKind::Bound { ref mut bounds } => {
- visit_bounds(bounds, vis);
- }
+ AssocConstraintKind::Equality { ref mut term } => match term {
+ Term::Ty(ty) => vis.visit_ty(ty),
+ Term::Const(c) => vis.visit_anon_const(c),
+ },
+ AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
}
vis.visit_span(span);
}
@@ -555,7 +554,7 @@
let AngleBracketedArgs { args, span } = data;
visit_vec(args, |arg| match arg {
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
- AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
+ AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
});
vis.visit_span(span);
}
@@ -1350,23 +1349,6 @@
visit_opt(expr, |expr| vis.visit_expr(expr));
}
ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
- ExprKind::LlvmInlineAsm(asm) => {
- let LlvmInlineAsm {
- asm: _,
- asm_str_style: _,
- outputs,
- inputs,
- clobbers: _,
- volatile: _,
- alignstack: _,
- dialect: _,
- } = asm.deref_mut();
- for out in outputs {
- let LlvmInlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out;
- vis.visit_expr(expr);
- }
- visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
- }
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
ExprKind::Struct(se) => {
let StructExpr { qself, path, fields, rest } = se.deref_mut();
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 9fe87a0..70dbda8 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -115,8 +115,8 @@
}
impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> {
- fn decode(d: &mut D) -> Result<P<T>, D::Error> {
- Decodable::decode(d).map(P)
+ fn decode(d: &mut D) -> P<T> {
+ P(Decodable::decode(d))
}
}
@@ -204,8 +204,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> {
- fn decode(d: &mut D) -> Result<P<[T]>, D::Error> {
- Ok(P::from_vec(Decodable::decode(d)?))
+ fn decode(d: &mut D) -> P<[T]> {
+ P::from_vec(Decodable::decode(d))
}
}
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 51cabb5..2174378 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -163,7 +163,7 @@
}
impl<D: Decoder> Decodable<D> for LazyTokenStream {
- fn decode(_d: &mut D) -> Result<Self, D::Error> {
+ fn decode(_d: &mut D) -> Self {
panic!("Attempted to decode LazyTokenStream");
}
}
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index 80a06fa..f51b0086 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -1,3 +1,4 @@
+use crate::token::CommentKind;
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
@@ -25,7 +26,7 @@
/// Makes a doc string more presentable to users.
/// Used by rustdoc and perhaps other tools, but not by rustc.
-pub fn beautify_doc_string(data: Symbol) -> Symbol {
+pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
let mut i = 0;
let mut j = lines.len();
@@ -34,25 +35,37 @@
i += 1;
}
- while i < j && lines[i].trim().is_empty() {
- i += 1;
- }
// like the first, a last line of all stars should be omitted
if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
j -= 1;
}
- while j > i && lines[j - 1].trim().is_empty() {
- j -= 1;
- }
-
if i != 0 || j != lines.len() { Some((i, j)) } else { None }
}
- fn get_horizontal_trim(lines: &[&str]) -> Option<usize> {
+ fn get_horizontal_trim<'a>(lines: &'a [&str], kind: CommentKind) -> Option<String> {
let mut i = usize::MAX;
let mut first = true;
+ // In case we have doc comments like `/**` or `/*!`, we want to remove stars if they are
+ // present. However, we first need to strip the empty lines so they don't get in the middle
+ // when we try to compute the "horizontal trim".
+ let lines = if kind == CommentKind::Block {
+ // Whatever happens, we skip the first line.
+ let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 };
+ let mut j = lines.len();
+
+ while i < j && lines[i].trim().is_empty() {
+ i += 1;
+ }
+ while j > i && lines[j - 1].trim().is_empty() {
+ j -= 1;
+ }
+ &lines[i..j]
+ } else {
+ lines
+ };
+
for line in lines {
for (j, c) in line.chars().enumerate() {
if j > i || !"* \t".contains(c) {
@@ -72,7 +85,7 @@
return None;
}
}
- Some(i)
+ if lines.is_empty() { None } else { Some(lines[0][..i].into()) }
}
let data_s = data.as_str();
@@ -86,11 +99,18 @@
} else {
&mut lines
};
- if let Some(horizontal) = get_horizontal_trim(&lines) {
+ if let Some(horizontal) = get_horizontal_trim(&lines, kind) {
changes = true;
// remove a "[ \t]*\*" block from each line, if possible
for line in lines.iter_mut() {
- *line = &line[horizontal + 1..];
+ if let Some(tmp) = line.strip_prefix(&horizontal) {
+ *line = tmp;
+ if kind == CommentKind::Block
+ && (*line == "*" || line.starts_with("* ") || line.starts_with("**"))
+ {
+ *line = &line[1..];
+ }
+ }
}
}
if changes {
diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs
index 6d137f3..11d5060 100644
--- a/compiler/rustc_ast/src/util/comments/tests.rs
+++ b/compiler/rustc_ast/src/util/comments/tests.rs
@@ -5,7 +5,7 @@
fn test_block_doc_comment_1() {
create_default_session_globals_then(|| {
let comment = "\n * Test \n ** Test\n * Test\n";
- let stripped = beautify_doc_string(Symbol::intern(comment));
+ let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
assert_eq!(stripped.as_str(), " Test \n* Test\n Test");
})
}
@@ -14,7 +14,7 @@
fn test_block_doc_comment_2() {
create_default_session_globals_then(|| {
let comment = "\n * Test\n * Test\n";
- let stripped = beautify_doc_string(Symbol::intern(comment));
+ let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
assert_eq!(stripped.as_str(), " Test\n Test");
})
}
@@ -23,21 +23,39 @@
fn test_block_doc_comment_3() {
create_default_session_globals_then(|| {
let comment = "\n let a: *i32;\n *a = 5;\n";
- let stripped = beautify_doc_string(Symbol::intern(comment));
- assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
+ let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
+ assert_eq!(stripped.as_str(), "let a: *i32;\n*a = 5;");
})
}
#[test]
fn test_line_doc_comment() {
create_default_session_globals_then(|| {
- let stripped = beautify_doc_string(Symbol::intern(" test"));
+ let stripped = beautify_doc_string(Symbol::intern(" test"), CommentKind::Line);
assert_eq!(stripped.as_str(), " test");
- let stripped = beautify_doc_string(Symbol::intern("! test"));
+ let stripped = beautify_doc_string(Symbol::intern("! test"), CommentKind::Line);
assert_eq!(stripped.as_str(), "! test");
- let stripped = beautify_doc_string(Symbol::intern("test"));
+ let stripped = beautify_doc_string(Symbol::intern("test"), CommentKind::Line);
assert_eq!(stripped.as_str(), "test");
- let stripped = beautify_doc_string(Symbol::intern("!test"));
+ let stripped = beautify_doc_string(Symbol::intern("!test"), CommentKind::Line);
assert_eq!(stripped.as_str(), "!test");
})
}
+
+#[test]
+fn test_doc_blocks() {
+ create_default_session_globals_then(|| {
+ let stripped =
+ beautify_doc_string(Symbol::intern(" # Returns\n *\n "), CommentKind::Block);
+ assert_eq!(stripped.as_str(), " # Returns\n\n");
+
+ let stripped = beautify_doc_string(
+ Symbol::intern("\n * # Returns\n *\n "),
+ CommentKind::Block,
+ );
+ assert_eq!(stripped.as_str(), " # Returns\n\n");
+
+ let stripped = beautify_doc_string(Symbol::intern("\n * a\n "), CommentKind::Block);
+ assert_eq!(stripped.as_str(), " a\n");
+ })
+}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 6840f09..73e9297 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -190,8 +190,8 @@
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
walk_generic_arg(self, generic_arg)
}
- fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
- walk_assoc_ty_constraint(self, constraint)
+ fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+ walk_assoc_constraint(self, constraint)
}
fn visit_attribute(&mut self, attr: &'ast Attribute) {
walk_attribute(self, attr)
@@ -464,7 +464,7 @@
for arg in &data.args {
match arg {
AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
- AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
+ AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c),
}
}
}
@@ -486,19 +486,17 @@
}
}
-pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
- visitor: &mut V,
- constraint: &'a AssocTyConstraint,
-) {
+pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
visitor.visit_ident(constraint.ident);
if let Some(ref gen_args) = constraint.gen_args {
visitor.visit_generic_args(gen_args.span(), gen_args);
}
match constraint.kind {
- AssocTyConstraintKind::Equality { ref ty } => {
- visitor.visit_ty(ty);
- }
- AssocTyConstraintKind::Bound { ref bounds } => {
+ AssocConstraintKind::Equality { ref term } => match term {
+ Term::Ty(ty) => visitor.visit_ty(ty),
+ Term::Const(c) => visitor.visit_anon_const(c),
+ },
+ AssocConstraintKind::Bound { ref bounds } => {
walk_list!(visitor, visit_param_bound, bounds);
}
}
@@ -864,14 +862,6 @@
ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
- ExprKind::LlvmInlineAsm(ref ia) => {
- for &(_, ref input) in &ia.inputs {
- visitor.visit_expr(input)
- }
- for output in &ia.outputs {
- visitor.visit_expr(&output.expr)
- }
- }
ExprKind::Yield(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 9c28f3c..18fcc99 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -6,7 +6,7 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_session::parse::feature_err;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;
@@ -66,7 +66,7 @@
for (abi_name, abi_span) in &asm.clobber_abis {
match asm::InlineAsmClobberAbi::parse(
asm_arch,
- |feature| self.sess.target_features.contains(&Symbol::intern(feature)),
+ &self.sess.target_features,
&self.sess.target,
*abi_name,
) {
@@ -129,13 +129,14 @@
.operands
.iter()
.map(|(op, op_sp)| {
- let lower_reg = |reg| match reg {
+ let lower_reg = |reg, is_clobber| match reg {
InlineAsmRegOrRegClass::Reg(s) => {
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
asm::InlineAsmReg::parse(
asm_arch,
- |feature| sess.target_features.contains(&Symbol::intern(feature)),
+ &sess.target_features,
&sess.target,
+ is_clobber,
s,
)
.unwrap_or_else(|e| {
@@ -162,24 +163,24 @@
let op = match *op {
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
- reg: lower_reg(reg),
+ reg: lower_reg(reg, false),
expr: self.lower_expr_mut(expr),
},
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
- reg: lower_reg(reg),
+ reg: lower_reg(reg, expr.is_none()),
late,
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
},
InlineAsmOperand::InOut { reg, late, ref expr } => {
hir::InlineAsmOperand::InOut {
- reg: lower_reg(reg),
+ reg: lower_reg(reg, false),
late,
expr: self.lower_expr_mut(expr),
}
}
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
hir::InlineAsmOperand::SplitInOut {
- reg: lower_reg(reg),
+ reg: lower_reg(reg, false),
late,
in_expr: self.lower_expr_mut(in_expr),
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
@@ -373,7 +374,9 @@
err.emit();
}
Entry::Vacant(v) => {
- v.insert(idx);
+ if r == reg {
+ v.insert(idx);
+ }
}
}
};
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 082c5bb..3a7e0a7 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -97,7 +97,7 @@
let ty = l
.ty
.as_ref()
- .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
+ .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
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);
@@ -127,7 +127,7 @@
let ty = local
.ty
.as_ref()
- .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
+ .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
let span = self.lower_span(local.span);
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
let init = self.lower_expr(init);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 75f3844..d48ff10 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,3 +1,5 @@
+use crate::{FnDeclKind, ImplTraitPosition};
+
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
use rustc_ast::attr;
@@ -11,7 +13,7 @@
use rustc_hir::definitions::DefPathData;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident};
use rustc_span::DUMMY_SP;
impl<'hir> LoweringContext<'_, 'hir> {
@@ -53,15 +55,10 @@
ParamMode::Optional,
0,
ParenthesizedGenericArgs::Err,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
let args = self.lower_exprs(args);
- hir::ExprKind::MethodCall(
- hir_seg,
- self.lower_span(seg.ident.span),
- args,
- self.lower_span(span),
- )
+ hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
let binop = self.lower_binop(binop);
@@ -79,12 +76,14 @@
}
ExprKind::Cast(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
- let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+ let ty =
+ self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ExprKind::Cast(expr, ty)
}
ExprKind::Type(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
- let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+ let ty =
+ self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ExprKind::Type(expr, ty)
}
ExprKind::AddrOf(k, m, ref ohs) => {
@@ -208,7 +207,7 @@
qself,
path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
hir::ExprKind::Path(qpath)
}
@@ -226,7 +225,6 @@
ExprKind::InlineAsm(ref asm) => {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
}
- ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
ExprKind::Struct(ref se) => {
let rest = match &se.rest {
StructRest::Base(e) => Some(self.lower_expr(e)),
@@ -245,7 +243,7 @@
&se.qself,
&se.path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)),
self.arena
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@@ -393,14 +391,20 @@
// 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())
+ fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
+ match expr.kind {
+ hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+ hir::ExprKind::Let(..) => true,
+ _ => false,
}
}
+ if has_let_expr(cond) {
+ cond
+ } else {
+ let reason = DesugaringKind::CondTemporary;
+ let span_block = self.mark_span_with_reason(reason, cond.span, None);
+ self.expr_drop_temps(span_block, cond, AttrVec::new())
+ }
}
// We desugar: `'label: while $cond $body` into:
@@ -538,7 +542,9 @@
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
let output = match ret_ty {
- Some(ty) => hir::FnRetTy::Return(self.lower_ty(&ty, ImplTraitContext::disallowed())),
+ Some(ty) => hir::FnRetTy::Return(
+ self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
+ ),
None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
};
@@ -625,18 +631,18 @@
/// }
/// }
/// ```
- fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
- let dot_await_span = expr.span.shrink_to_hi().to(await_span);
+ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+ let full_span = expr.span.to(dot_await_span);
match self.generator_kind {
Some(hir::GeneratorKind::Async(_)) => {}
Some(hir::GeneratorKind::Gen) | None => {
let mut err = struct_span_err!(
self.sess,
- await_span,
+ dot_await_span,
E0728,
"`await` is only allowed inside `async` functions and blocks"
);
- err.span_label(await_span, "only allowed inside `async` functions and blocks");
+ err.span_label(dot_await_span, "only allowed inside `async` functions and blocks");
if let Some(item_sp) = self.current_item {
err.span_label(item_sp, "this is not `async`");
}
@@ -646,7 +652,7 @@
let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
- await_span,
+ full_span,
self.allow_gen_future.clone(),
);
let expr = self.lower_expr_mut(expr);
@@ -699,9 +705,9 @@
let loop_hir_id = self.lower_node_id(loop_node_id);
let ready_arm = {
let x_ident = Ident::with_dummy_span(sym::result);
- let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
- let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
- let ready_field = self.single_pat_field(span, x_pat);
+ let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
+ let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
+ let ready_field = self.single_pat_field(gen_future_span, x_pat);
let ready_pat = self.pat_lang_item_variant(
span,
hir::LangItem::PollReady,
@@ -711,7 +717,7 @@
let break_x = self.with_loop_scope(loop_node_id, move |this| {
let expr_break =
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
- this.arena.alloc(this.expr(span, expr_break, ThinVec::new()))
+ this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new()))
});
self.arm(ready_pat, break_x)
};
@@ -783,7 +789,7 @@
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
let into_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
- await_span,
+ dot_await_span,
self.allow_into_future.clone(),
);
let into_future_expr = self.expr_call_lang_item_fn(
@@ -827,7 +833,7 @@
});
// Lower outside new scope to preserve `is_in_loop_condition`.
- let fn_decl = self.lower_fn_decl(decl, None, false, None);
+ let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
hir::ExprKind::Closure(
capture_clause,
@@ -919,7 +925,7 @@
// We need to lower the declaration outside the new scope, because we
// have to conserve the state of being inside a loop condition for the
// closure argument types.
- let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
+ let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
hir::ExprKind::Closure(
capture_clause,
@@ -1064,7 +1070,7 @@
qself,
path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
// Destructure like a tuple struct.
let tuple_struct_pat =
@@ -1089,7 +1095,7 @@
&se.qself,
&se.path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let fields_omitted = match &se.rest {
StructRest::Base(e) => {
@@ -1204,11 +1210,13 @@
};
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), self.lower_span(e.span));
- self.expr_field(ident, expr, e.span)
- }),
+ e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
+ |(s, e)| {
+ let expr = self.lower_expr(&e);
+ let ident = Ident::new(s, self.lower_span(e.span));
+ self.expr_field(ident, expr, e.span)
+ },
+ ),
);
hir::ExprKind::Struct(
@@ -1284,38 +1292,6 @@
result
}
- fn lower_expr_llvm_asm(&mut self, asm: &LlvmInlineAsm) -> hir::ExprKind<'hir> {
- let inner = hir::LlvmInlineAsmInner {
- inputs: asm.inputs.iter().map(|&(c, _)| c).collect(),
- outputs: asm
- .outputs
- .iter()
- .map(|out| hir::LlvmInlineAsmOutput {
- constraint: out.constraint,
- is_rw: out.is_rw,
- is_indirect: out.is_indirect,
- span: self.lower_span(out.expr.span),
- })
- .collect(),
- asm: asm.asm,
- asm_str_style: asm.asm_str_style,
- clobbers: asm.clobbers.clone(),
- volatile: asm.volatile,
- alignstack: asm.alignstack,
- dialect: asm.dialect,
- };
- let hir_asm = hir::LlvmInlineAsm {
- inner,
- inputs_exprs: self.arena.alloc_from_iter(
- asm.inputs.iter().map(|&(_, ref input)| self.lower_expr_mut(input)),
- ),
- outputs_exprs: self
- .arena
- .alloc_from_iter(asm.outputs.iter().map(|out| self.lower_expr_mut(&out.expr))),
- };
- hir::ExprKind::LlvmInlineAsm(self.arena.alloc(hir_asm))
- }
-
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
hir::ExprField {
hir_id: self.next_id(),
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 8a9dad2..62935a2 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -3,7 +3,7 @@
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::definitions;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::*;
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::Session;
@@ -101,16 +101,10 @@
}
impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
- type Map = !;
-
/// Because we want to track parent items and so forth, enable
/// deep walking so that we walk nested items in the context of
/// their outer items.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- panic!("`visit_nested_xxx` must be manually implemented in this visitor");
- }
-
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
self.insert_nested(item.def_id);
@@ -335,7 +329,8 @@
fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
// Do not visit the duplicate information in ImplItemRef. We want to
// map the actual nodes, not the duplicate ones in the *Ref.
- let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+ let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ } =
+ *ii;
self.visit_nested_impl_item(id);
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 92cae4d..6489c72 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,6 +1,6 @@
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
use super::{ImplTraitContext, ImplTraitPosition};
-use crate::Arena;
+use crate::{Arena, FnDeclKind};
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
@@ -105,12 +105,11 @@
) -> T {
let old_len = self.in_scope_lifetimes.len();
- let parent_generics =
- match self.owners[parent_hir_id].as_ref().unwrap().node().expect_item().kind {
- hir::ItemKind::Impl(hir::Impl { ref generics, .. })
- | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
- _ => &[],
- };
+ let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
+ hir::ItemKind::Impl(hir::Impl { ref generics, .. })
+ | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
+ _ => &[],
+ };
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()),
_ => None,
@@ -247,7 +246,12 @@
AnonymousLifetimeMode::PassThrough,
|this, idty| {
let ret_id = asyncness.opt_return_id();
- this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
+ this.lower_fn_decl(
+ &decl,
+ Some((fn_def_id, idty)),
+ FnDeclKind::Fn,
+ ret_id,
+ )
},
);
let sig = hir::FnSig {
@@ -288,12 +292,18 @@
capturable_lifetimes: &mut FxHashSet::default(),
},
);
- let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
+ let generics = self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ );
hir::ItemKind::TyAlias(ty, generics)
}
ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
- let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
+ let generics = self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ );
hir::ItemKind::TyAlias(ty, generics)
}
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
@@ -302,20 +312,29 @@
enum_definition.variants.iter().map(|x| self.lower_variant(x)),
),
},
- self.lower_generics(generics, ImplTraitContext::disallowed()),
+ self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
),
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(hir_id, struct_def);
hir::ItemKind::Struct(
struct_def,
- self.lower_generics(generics, ImplTraitContext::disallowed()),
+ self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(hir_id, vdata);
hir::ItemKind::Union(
vdata,
- self.lower_generics(generics, ImplTraitContext::disallowed()),
+ self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
)
}
ItemKind::Impl(box Impl {
@@ -348,10 +367,14 @@
AnonymousLifetimeMode::CreateParameter,
|this, _| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
- this.lower_trait_ref(trait_ref, ImplTraitContext::disallowed())
+ this.lower_trait_ref(
+ trait_ref,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+ )
});
- let lowered_ty = this.lower_ty(ty, ImplTraitContext::disallowed());
+ let lowered_ty = this
+ .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(trait_ref, lowered_ty)
},
@@ -391,21 +414,33 @@
ref bounds,
ref items,
}) => {
- let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
+ let bounds = self.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ );
let items = self
.arena
.alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item)));
hir::ItemKind::Trait(
is_auto,
self.lower_unsafety(unsafety),
- self.lower_generics(generics, ImplTraitContext::disallowed()),
+ self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
bounds,
items,
)
}
ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
- self.lower_generics(generics, ImplTraitContext::disallowed()),
- self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
+ self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
+ self.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ ),
),
ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
let body = P(self.lower_mac_args(body));
@@ -424,7 +459,7 @@
span: Span,
body: Option<&Expr>,
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
- let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Binding));
+ let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(ty, self.lower_const_body(span, body))
}
@@ -472,14 +507,18 @@
// two imports.
for new_node_id in [id1, id2] {
let new_id = self.resolver.local_def_id(new_node_id);
- let res = if let Some(res) = resolutions.next() {
- res
- } else {
+ let Some(res) = resolutions.next() else {
// Associate an HirId to both ids even if there is no resolution.
let _old = self
.node_id_to_hir_id
.insert(new_node_id, hir::HirId::make_owner(new_id));
debug_assert!(_old.is_none());
+ self.owners.ensure_contains_elem(new_id, || hir::MaybeOwner::Phantom);
+ let _old = std::mem::replace(
+ &mut self.owners[new_id],
+ hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)),
+ );
+ debug_assert!(matches!(_old, hir::MaybeOwner::Phantom));
continue;
};
let ident = *ident;
@@ -664,7 +703,7 @@
|this, _| {
(
// Disallow `impl Trait` in foreign items.
- this.lower_fn_decl(fdec, None, false, None),
+ this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
this.lower_fn_params_to_names(fdec),
)
},
@@ -673,7 +712,8 @@
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m, _) => {
- let ty = self.lower_ty(t, ImplTraitContext::disallowed());
+ let ty =
+ self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ForeignItemKind::Static(ty, m)
}
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
@@ -741,11 +781,11 @@
qself,
path,
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
self.arena.alloc(t)
} else {
- self.lower_ty(&f.ty, ImplTraitContext::disallowed())
+ self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
};
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs);
@@ -768,14 +808,19 @@
let (generics, kind) = match i.kind {
AssocItemKind::Const(_, ref ty, ref default) => {
- let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+ let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
}
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: 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);
+ let (generics, sig) = self.lower_method_sig(
+ generics,
+ sig,
+ trait_item_def_id,
+ FnDeclKind::Trait,
+ None,
+ );
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
@@ -786,16 +831,24 @@
generics,
sig,
trait_item_def_id,
- false,
+ FnDeclKind::Trait,
asyncness.opt_return_id(),
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
- let ty = ty.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
- let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
+ let ty = ty.as_ref().map(|x| {
+ self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ });
+ let generics = self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ );
let kind = hir::TraitItemKind::Type(
- self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
+ self.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ ),
ty,
);
@@ -847,7 +900,7 @@
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
- let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+ let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(
hir::Generics::empty(),
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
@@ -858,19 +911,21 @@
let asyncness = sig.header.asyncness;
let body_id =
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
- let impl_trait_return_allow = !self.is_in_trait_impl;
let (generics, sig) = self.lower_method_sig(
generics,
sig,
impl_item_def_id,
- impl_trait_return_allow,
+ if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
asyncness.opt_return_id(),
);
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
- let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
+ let generics = self.lower_generics(
+ generics,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ );
let kind = match ty {
None => {
let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
@@ -891,9 +946,6 @@
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
};
- // Since `default impl` is not yet implemented, this is always true in impls.
- let has_value = true;
- let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
let hir_id = self.lower_node_id(i.id);
self.lower_attrs(hir_id, &i.attrs);
let item = hir::ImplItem {
@@ -901,7 +953,6 @@
ident: self.lower_ident(i.ident),
generics,
vis: self.lower_visibility(&i.vis),
- defaultness,
kind,
span: self.lower_span(i.span),
};
@@ -925,6 +976,7 @@
}
AssocItemKind::MacCall(..) => unimplemented!(),
},
+ trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
}
}
@@ -1248,7 +1300,7 @@
generics: &Generics,
sig: &FnSig,
fn_def_id: LocalDefId,
- impl_trait_return_allow: bool,
+ kind: FnDeclKind,
is_async: Option<NodeId>,
) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header);
@@ -1256,14 +1308,7 @@
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
- |this, idty| {
- this.lower_fn_decl(
- &sig.decl,
- Some((fn_def_id, idty)),
- impl_trait_return_allow,
- is_async,
- )
- },
+ |this, idty| this.lower_fn_decl(&sig.decl, Some((fn_def_id, idty)), kind, is_async),
);
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
@@ -1409,11 +1454,19 @@
span,
}) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
- bound_generic_params: this
- .lower_generic_params(bound_generic_params, ImplTraitContext::disallowed()),
- bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
+ bound_generic_params: this.lower_generic_params(
+ bound_generic_params,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
+ bounded_ty: this.lower_ty(
+ bounded_ty,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+ ),
bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| {
- this.lower_param_bound(bound, ImplTraitContext::disallowed())
+ this.lower_param_bound(
+ bound,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ )
})),
span: this.lower_span(span),
})
@@ -1425,13 +1478,18 @@
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span: self.lower_span(span),
lifetime: self.lower_lifetime(lifetime),
- bounds: self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
+ bounds: self.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ ),
}),
WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
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()),
+ lhs_ty: self
+ .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+ rhs_ty: self
+ .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
span: self.lower_span(span),
})
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 35eb716..ae7f229 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -32,8 +32,10 @@
#![feature(crate_visibility_modifier)]
#![feature(box_patterns)]
+#![feature(let_else)]
#![feature(never_type)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
@@ -98,7 +100,7 @@
arena: &'hir Arena<'hir>,
/// The items being lowered are collected here.
- owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
+ owners: IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
/// Bodies inside the owner being lowered.
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
/// Attributes inside the owner being lowered.
@@ -254,19 +256,28 @@
/// Position in which `impl Trait` is disallowed.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ImplTraitPosition {
- /// Disallowed in `let` / `const` / `static` bindings.
- Binding,
-
- /// All other positions.
- Other,
+ Path,
+ Variable,
+ Type,
+ Trait,
+ AsyncBlock,
+ Bound,
+ Generic,
+ ExternFnParam,
+ ClosureParam,
+ PointerParam,
+ FnTraitParam,
+ TraitParam,
+ ImplParam,
+ ExternFnReturn,
+ ClosureReturn,
+ PointerReturn,
+ FnTraitReturn,
+ TraitReturn,
+ ImplReturn,
}
impl<'a> ImplTraitContext<'_, 'a> {
- #[inline]
- fn disallowed() -> Self {
- ImplTraitContext::Disallowed(ImplTraitPosition::Other)
- }
-
fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
use self::ImplTraitContext::*;
match self {
@@ -282,6 +293,54 @@
}
}
+impl std::fmt::Display for ImplTraitPosition {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let name = match self {
+ ImplTraitPosition::Path => "path",
+ ImplTraitPosition::Variable => "variable binding",
+ ImplTraitPosition::Type => "type",
+ ImplTraitPosition::Trait => "trait",
+ ImplTraitPosition::AsyncBlock => "async block",
+ ImplTraitPosition::Bound => "bound",
+ ImplTraitPosition::Generic => "generic",
+ ImplTraitPosition::ExternFnParam => "`extern fn` param",
+ ImplTraitPosition::ClosureParam => "closure param",
+ ImplTraitPosition::PointerParam => "`fn` pointer param",
+ ImplTraitPosition::FnTraitParam => "`Fn` trait param",
+ ImplTraitPosition::TraitParam => "trait method param",
+ ImplTraitPosition::ImplParam => "`impl` method param",
+ ImplTraitPosition::ExternFnReturn => "`extern fn` return",
+ ImplTraitPosition::ClosureReturn => "closure return",
+ ImplTraitPosition::PointerReturn => "`fn` pointer return",
+ ImplTraitPosition::FnTraitReturn => "`Fn` trait return",
+ ImplTraitPosition::TraitReturn => "trait method return",
+ ImplTraitPosition::ImplReturn => "`impl` method return",
+ };
+
+ write!(f, "{}", name)
+ }
+}
+
+#[derive(Debug)]
+enum FnDeclKind {
+ Fn,
+ Inherent,
+ ExternFn,
+ Closure,
+ Pointer,
+ Trait,
+ Impl,
+}
+
+impl FnDeclKind {
+ fn impl_trait_return_allowed(&self) -> bool {
+ match self {
+ FnDeclKind::Fn | FnDeclKind::Inherent => true,
+ _ => false,
+ }
+ }
+}
+
pub fn lower_crate<'a, 'hir>(
sess: &'a Session,
krate: &'a Crate,
@@ -291,7 +350,8 @@
) -> &'hir hir::Crate<'hir> {
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
- let owners = IndexVec::from_fn_n(|_| None, resolver.definitions().def_index_count());
+ let owners =
+ IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count());
LoweringContext {
sess,
resolver,
@@ -402,19 +462,6 @@
let hir_hash = self.compute_hir_hash();
- let mut def_id_to_hir_id = IndexVec::default();
-
- for (node_id, hir_id) in self.node_id_to_hir_id.into_iter_enumerated() {
- if let Some(def_id) = self.resolver.opt_local_def_id(node_id) {
- if def_id_to_hir_id.len() <= def_id.index() {
- def_id_to_hir_id.resize(def_id.index() + 1, None);
- }
- def_id_to_hir_id[def_id] = hir_id;
- }
- }
-
- self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
-
let krate = hir::Crate { owners: self.owners, hir_hash };
self.arena.alloc(krate)
}
@@ -427,7 +474,7 @@
.owners
.iter_enumerated()
.filter_map(|(def_id, info)| {
- let info = info.as_ref()?;
+ let info = info.as_owner()?;
let def_path_hash = definitions.def_path_hash(def_id);
Some((def_path_hash, info))
})
@@ -469,8 +516,8 @@
self.current_hir_id_owner = current_owner;
self.item_local_id_counter = current_local_counter;
- let _old = self.owners.insert(def_id, info);
- debug_assert!(_old.is_none());
+ self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+ self.owners[def_id] = hir::MaybeOwner::Owner(self.arena.alloc(info));
def_id
}
@@ -479,6 +526,25 @@
let attrs = std::mem::take(&mut self.attrs);
let mut bodies = std::mem::take(&mut self.bodies);
let local_node_ids = std::mem::take(&mut self.local_node_ids);
+
+ let local_id_to_def_id = local_node_ids
+ .iter()
+ .filter_map(|&node_id| {
+ let hir_id = self.node_id_to_hir_id[node_id]?;
+ if hir_id.local_id == hir::ItemLocalId::new(0) {
+ None
+ } else {
+ let def_id = self.resolver.opt_local_def_id(node_id)?;
+ self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+ if let o @ hir::MaybeOwner::Phantom = &mut self.owners[def_id] {
+ // Do not override a `MaybeOwner::Owner` that may already here.
+ *o = hir::MaybeOwner::NonOwner(hir_id);
+ }
+ Some((hir_id.local_id, def_id))
+ }
+ })
+ .collect();
+
let trait_map = local_node_ids
.into_iter()
.filter_map(|node_id| {
@@ -501,7 +567,13 @@
let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
let (nodes, parenting) =
index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
- let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
+ let nodes = hir::OwnerNodes {
+ hash_including_bodies,
+ hash_without_bodies,
+ nodes,
+ bodies,
+ local_id_to_def_id,
+ };
let attrs = {
let mut hcx = self.resolver.create_stable_hashing_context();
let mut stable_hasher = StableHasher::new();
@@ -960,7 +1032,7 @@
/// returns a `hir::TypeBinding` representing `Item`.
fn lower_assoc_ty_constraint(
&mut self,
- constraint: &AssocTyConstraint,
+ constraint: &AssocConstraint,
mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@@ -997,10 +1069,14 @@
};
let kind = match constraint.kind {
- AssocTyConstraintKind::Equality { ref ty } => {
- hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
+ AssocConstraintKind::Equality { ref term } => {
+ let term = match term {
+ Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
+ Term::Const(ref c) => self.lower_anon_const(c).into(),
+ };
+ hir::TypeBindingKind::Equality { term }
}
- AssocTyConstraintKind::Bound { ref bounds } => {
+ AssocConstraintKind::Bound { ref bounds } => {
let mut capturable_lifetimes;
let mut parent_def_id = self.current_hir_id_owner;
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
@@ -1078,7 +1154,7 @@
itctx,
);
- hir::TypeBindingKind::Equality { ty }
+ hir::TypeBindingKind::Equality { term: ty.into() }
})
} else {
// Desugar `AssocTy: Bounds` into a type binding where the
@@ -1213,11 +1289,11 @@
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
generic_params: this.lower_generic_params(
&f.generic_params,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
),
unsafety: this.lower_unsafety(f.unsafety),
abi: this.lower_extern(f.ext),
- decl: this.lower_fn_decl(&f.decl, None, false, None),
+ decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
param_names: this.lower_fn_params_to_names(&f.decl),
}))
})
@@ -1338,13 +1414,13 @@
}),
))
}
- ImplTraitContext::Disallowed(_) => {
+ ImplTraitContext::Disallowed(position) => {
let mut err = struct_span_err!(
self.sess,
t.span,
E0562,
- "`impl Trait` not allowed outside of {}",
- "function and method return types",
+ "`impl Trait` only allowed in function and inherent method return types, not in {}",
+ position
);
err.emit();
hir::TyKind::Err
@@ -1509,16 +1585,16 @@
&mut self,
decl: &FnDecl,
mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>,
- impl_trait_return_allow: bool,
+ kind: FnDeclKind,
make_ret_async: Option<NodeId>,
) -> &'hir hir::FnDecl<'hir> {
debug!(
"lower_fn_decl(\
fn_decl: {:?}, \
in_band_ty_params: {:?}, \
- impl_trait_return_allow: {}, \
+ kind: {:?}, \
make_ret_async: {:?})",
- decl, in_band_ty_params, impl_trait_return_allow, make_ret_async,
+ decl, in_band_ty_params, kind, make_ret_async,
);
let lt_mode = if make_ret_async.is_some() {
// In `async fn`, argument-position elided lifetimes
@@ -1548,7 +1624,19 @@
ImplTraitContext::Universal(ibty, this.current_hir_id_owner),
)
} else {
- this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed())
+ this.lower_ty_direct(
+ ¶m.ty,
+ ImplTraitContext::Disallowed(match kind {
+ FnDeclKind::Fn | FnDeclKind::Inherent => {
+ unreachable!("fn should allow in-band lifetimes")
+ }
+ FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
+ FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
+ FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
+ FnDeclKind::Trait => ImplTraitPosition::TraitParam,
+ FnDeclKind::Impl => ImplTraitPosition::ImplParam,
+ }),
+ )
}
}))
});
@@ -1563,13 +1651,22 @@
match decl.output {
FnRetTy::Ty(ref ty) => {
let context = match in_band_ty_params {
- Some((def_id, _)) if impl_trait_return_allow => {
+ Some((def_id, _)) if kind.impl_trait_return_allowed() => {
ImplTraitContext::ReturnPositionOpaqueTy {
fn_def_id: def_id,
origin: hir::OpaqueTyOrigin::FnReturn(def_id),
}
}
- _ => ImplTraitContext::disallowed(),
+ _ => ImplTraitContext::Disallowed(match kind {
+ FnDeclKind::Fn | FnDeclKind::Inherent => {
+ unreachable!("fn should allow in-band lifetimes")
+ }
+ FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn,
+ FnDeclKind::Closure => ImplTraitPosition::ClosureReturn,
+ FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
+ FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
+ FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
+ }),
};
hir::FnRetTy::Return(self.lower_ty(ty, context))
}
@@ -1927,7 +2024,7 @@
GenericParamKind::Type { ref default, .. } => {
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
- self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other))
+ self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
}),
synthetic: false,
};
@@ -1935,9 +2032,9 @@
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
- let ty = self
- .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
- this.lower_ty(&ty, ImplTraitContext::disallowed())
+ let ty =
+ self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
+ this.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
});
let default = default.as_ref().map(|def| self.lower_anon_const(def));
(
@@ -2436,12 +2533,6 @@
}
impl<'r, 'v> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
-
fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) {
// Don't collect elided lifetimes used inside of `Fn()` syntax.
if parameters.parenthesized {
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index ebae779..2c33176 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -1,3 +1,5 @@
+use crate::ImplTraitPosition;
+
use super::{ImplTraitContext, LoweringContext, ParamMode};
use rustc_ast::ptr::P;
@@ -33,7 +35,7 @@
qself,
path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
@@ -49,7 +51,7 @@
qself,
path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
break hir::PatKind::Path(qpath);
}
@@ -59,7 +61,7 @@
qself,
path,
ParamMode::Optional,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 46928a1..b35e3a0 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -1,3 +1,5 @@
+use crate::ImplTraitPosition;
+
use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
use super::{GenericArgsCtor, ParenthesizedGenericArgs};
@@ -184,7 +186,7 @@
param_mode,
0,
ParenthesizedGenericArgs::Err,
- ImplTraitContext::disallowed(),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)
})),
span: self.lower_span(p.span),
@@ -392,11 +394,15 @@
// we generally don't permit such things (see #51008).
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
- let inputs = this.arena.alloc_from_iter(
- inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
- );
+ let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
+ this.lower_ty_direct(
+ ty,
+ ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
+ )
+ }));
let output_ty = match output {
- FnRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
+ FnRetTy::Ty(ty) => this
+ .lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
@@ -420,7 +426,7 @@
ty: &'hir hir::Ty<'hir>,
) -> hir::TypeBinding<'hir> {
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
- let kind = hir::TypeBindingKind::Equality { ty };
+ let kind = hir::TypeBindingKind::Equality { term: ty.into() };
let args = arena_vec![self;];
let bindings = arena_vec![self;];
let gen_args = self.arena.alloc(hir::GenericArgs {
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml
index 9312a68b..45b7042 100644
--- a/compiler/rustc_ast_passes/Cargo.toml
+++ b/compiler/rustc_ast_passes/Cargo.toml
@@ -4,7 +4,7 @@
edition = "2021"
[dependencies]
-itertools = "0.9"
+itertools = "0.10"
tracing = "0.1"
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 6237a01..eb7c75c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -138,10 +138,10 @@
self.outer_impl_trait = old;
}
- fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
+ fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
match constraint.kind {
- AssocTyConstraintKind::Equality { .. } => {}
- AssocTyConstraintKind::Bound { .. } => {
+ AssocConstraintKind::Equality { .. } => {}
+ AssocConstraintKind::Bound { .. } => {
if self.is_assoc_ty_bound_banned {
self.err_handler().span_err(
constraint.span,
@@ -150,7 +150,7 @@
}
}
}
- self.visit_assoc_ty_constraint(constraint);
+ self.visit_assoc_constraint(constraint);
}
// Mirrors `visit::walk_ty`, but tracks relevant state.
@@ -960,15 +960,6 @@
return;
}
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
- ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => {
- struct_span_err!(
- this.session,
- expr.span,
- E0472,
- "llvm_asm! is unsupported on this target"
- )
- .emit();
- }
ExprKind::Match(expr, arms) => {
this.visit_expr(expr);
for arm in arms {
@@ -1286,7 +1277,7 @@
// are allowed to contain nested `impl Trait`.
AngleBracketedArg::Constraint(constraint) => {
self.with_impl_trait(None, |this| {
- this.visit_assoc_ty_constraint_from_generic_args(constraint);
+ this.visit_assoc_constraint_from_generic_args(constraint);
});
}
}
@@ -1595,12 +1586,12 @@
let len = assoc_path.segments.len() - 1;
let gen_args = args.as_ref().map(|p| (**p).clone());
// Build `<Bar = RhsTy>`.
- let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
+ let arg = AngleBracketedArg::Constraint(AssocConstraint {
id: rustc_ast::node_id::DUMMY_NODE_ID,
ident: *ident,
gen_args,
- kind: AssocTyConstraintKind::Equality {
- ty: predicate.rhs_ty.clone(),
+ kind: AssocConstraintKind::Equality {
+ term: predicate.rhs_ty.clone().into(),
},
span: ident.span,
});
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 85e35c9..6c44fb0 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,6 +1,6 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
+use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -196,6 +196,54 @@
"thiscall-unwind ABI is experimental and subject to change"
);
}
+ "cdecl-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "cdecl-unwind ABI is experimental and subject to change"
+ );
+ }
+ "fastcall-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "fastcall-unwind ABI is experimental and subject to change"
+ );
+ }
+ "vectorcall-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "vectorcall-unwind ABI is experimental and subject to change"
+ );
+ }
+ "aapcs-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "aapcs-unwind ABI is experimental and subject to change"
+ );
+ }
+ "win64-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "win64-unwind ABI is experimental and subject to change"
+ );
+ }
+ "sysv64-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "sysv64-unwind ABI is experimental and subject to change"
+ );
+ }
"wasm" => {
gate_feature_post!(
&self,
@@ -622,8 +670,8 @@
visit::walk_fn(self, fn_kind, span)
}
- fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
- if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
+ fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
+ if let AssocConstraintKind::Bound { .. } = constraint.kind {
gate_feature_post!(
&self,
associated_type_bounds,
@@ -631,7 +679,7 @@
"associated type bounds are unstable"
)
}
- visit::walk_assoc_ty_constraint(self, constraint)
+ visit::walk_assoc_constraint(self, constraint)
}
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
@@ -707,11 +755,7 @@
"`if let` guards are experimental",
"you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
);
- gate_all!(
- let_chains,
- "`let` expressions in this position are experimental",
- "you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`"
- );
+ gate_all!(let_chains, "`let` expressions in this position are unstable");
gate_all!(
async_closure,
"async closures are unstable",
@@ -724,6 +768,7 @@
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
+ gate_all!(associated_const_equality, "associated const equality is incomplete");
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
@@ -778,7 +823,7 @@
);
let mut all_stable = true;
for ident in
- attr.meta_item_list().into_iter().flatten().map(|nested| nested.ident()).flatten()
+ attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
{
let name = ident.name;
let stable_since = lang_features
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index adc4d11..f486313 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -8,6 +8,7 @@
#![feature(box_patterns)]
#![feature(let_else)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
pub mod ast_validation;
pub mod feature_gate;
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 3980e6d..a4a48cc 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -126,9 +126,9 @@
self.count += 1;
walk_generic_args(self, path_span, generic_args)
}
- fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
+ fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
self.count += 1;
- walk_assoc_ty_constraint(self, constraint)
+ walk_assoc_constraint(self, constraint)
}
fn visit_attribute(&mut self, _attr: &Attribute) {
self.count += 1;
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 29f2be4..5ad8714 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -7,6 +7,5 @@
doctest = false
[dependencies]
-tracing = "0.1"
rustc_span = { path = "../rustc_span" }
rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index ea298d2..ddce86f 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -132,10 +132,14 @@
//! methods called `Printer::scan_*`, and the 'PRINT' process is the
//! method called `Printer::print`.
+mod convenience;
+mod ring;
+
+use ring::RingBuffer;
use std::borrow::Cow;
+use std::cmp;
use std::collections::VecDeque;
-use std::fmt;
-use tracing::debug;
+use std::iter;
/// How to break. Described in more detail in the module docs.
#[derive(Clone, Copy, PartialEq)]
@@ -144,19 +148,36 @@
Inconsistent,
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
+enum IndentStyle {
+ /// Vertically aligned under whatever column this block begins at.
+ ///
+ /// fn demo(arg1: usize,
+ /// arg2: usize);
+ Visual,
+ /// Indented relative to the indentation level of the previous line.
+ ///
+ /// fn demo(
+ /// arg1: usize,
+ /// arg2: usize,
+ /// );
+ Block { offset: isize },
+}
+
+#[derive(Clone, Copy, Default, PartialEq)]
pub struct BreakToken {
offset: isize,
blank_space: isize,
+ pre_break: Option<char>,
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
pub struct BeginToken {
- offset: isize,
+ indent: IndentStyle,
breaks: Breaks,
}
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
pub enum Token {
// In practice a string token contains either a `&'static str` or a
// `String`. `Cow` is overkill for this because we never modify the data,
@@ -165,99 +186,27 @@
Break(BreakToken),
Begin(BeginToken),
End,
- Eof,
-}
-
-impl Token {
- crate fn is_eof(&self) -> bool {
- matches!(self, Token::Eof)
- }
-
- pub fn is_hardbreak_tok(&self) -> bool {
- matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
- }
-}
-
-impl fmt::Display for Token {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
- Token::Break(_) => f.write_str("BREAK"),
- Token::Begin(_) => f.write_str("BEGIN"),
- Token::End => f.write_str("END"),
- Token::Eof => f.write_str("EOF"),
- }
- }
-}
-
-fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
- let n = buf.len();
- let mut i = left;
- let mut l = lim;
- let mut s = String::from("[");
- while i != right && l != 0 {
- l -= 1;
- if i != left {
- s.push_str(", ");
- }
- s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
- i += 1;
- i %= n;
- }
- s.push(']');
- s
}
#[derive(Copy, Clone)]
-enum PrintStackBreak {
+enum PrintFrame {
Fits,
- Broken(Breaks),
-}
-
-#[derive(Copy, Clone)]
-struct PrintStackElem {
- offset: isize,
- pbreak: PrintStackBreak,
+ Broken { indent: usize, breaks: Breaks },
}
const SIZE_INFINITY: isize = 0xffff;
-pub fn mk_printer() -> Printer {
- let linewidth = 78;
- // Yes 55, it makes the ring buffers big enough to never fall behind.
- let n: usize = 55 * linewidth;
- debug!("mk_printer {}", linewidth);
- Printer {
- out: String::new(),
- buf_max_len: n,
- margin: linewidth as isize,
- space: linewidth as isize,
- left: 0,
- right: 0,
- // Initialize a single entry; advance_right() will extend it on demand
- // up to `buf_max_len` elements.
- buf: vec![BufEntry::default()],
- left_total: 0,
- right_total: 0,
- scan_stack: VecDeque::new(),
- print_stack: Vec::new(),
- pending_indentation: 0,
- }
-}
+/// Target line width.
+const MARGIN: isize = 78;
+/// Every line is allowed at least this much space, even if highly indented.
+const MIN_SPACE: isize = 60;
pub struct Printer {
out: String,
- buf_max_len: usize,
- /// Width of lines we're constrained to
- margin: isize,
/// Number of spaces left on line
space: isize,
- /// Index of left side of input stream
- left: usize,
- /// Index of right side of input stream
- right: usize,
/// Ring-buffer of tokens and calculated sizes
- buf: Vec<BufEntry>,
+ buf: RingBuffer<BufEntry>,
/// Running size of stream "...left"
left_total: isize,
/// Running size of stream "...right"
@@ -270,9 +219,14 @@
/// advancing.
scan_stack: VecDeque<usize>,
/// Stack of blocks-in-progress being flushed by print
- print_stack: Vec<PrintStackElem>,
+ print_stack: Vec<PrintFrame>,
+ /// Level of indentation of current line
+ indent: usize,
/// Buffered indentation to avoid writing trailing whitespace
pending_indentation: isize,
+ /// The token most recently popped from the left boundary of the
+ /// ring-buffer for printing
+ last_printed: Option<Token>,
}
#[derive(Clone)]
@@ -281,20 +235,33 @@
size: isize,
}
-impl Default for BufEntry {
- fn default() -> Self {
- BufEntry { token: Token::Eof, size: 0 }
- }
-}
-
impl Printer {
- pub fn last_token(&self) -> Token {
- self.buf[self.right].token.clone()
+ pub fn new() -> Self {
+ Printer {
+ out: String::new(),
+ space: MARGIN,
+ buf: RingBuffer::new(),
+ left_total: 0,
+ right_total: 0,
+ scan_stack: VecDeque::new(),
+ print_stack: Vec::new(),
+ indent: 0,
+ pending_indentation: 0,
+ last_printed: None,
+ }
+ }
+
+ pub fn last_token(&self) -> Option<&Token> {
+ self.last_token_still_buffered().or_else(|| self.last_printed.as_ref())
+ }
+
+ pub fn last_token_still_buffered(&self) -> Option<&Token> {
+ self.buf.last().map(|last| &last.token)
}
/// Be very careful with this!
- pub fn replace_last_token(&mut self, t: Token) {
- self.buf[self.right].token = t;
+ pub fn replace_last_token_still_buffered(&mut self, token: Token) {
+ self.buf.last_mut().unwrap().token = token;
}
fn scan_eof(&mut self) {
@@ -304,242 +271,170 @@
}
}
- fn scan_begin(&mut self, b: BeginToken) {
+ fn scan_begin(&mut self, token: BeginToken) {
if self.scan_stack.is_empty() {
self.left_total = 1;
self.right_total = 1;
- self.left = 0;
- self.right = 0;
- } else {
- self.advance_right();
+ self.buf.clear();
}
- debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
- self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
+ let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total });
+ self.scan_stack.push_back(right);
}
fn scan_end(&mut self) {
if self.scan_stack.is_empty() {
- debug!("pp End/print Vec<{},{}>", self.left, self.right);
self.print_end();
} else {
- debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
- self.advance_right();
- self.scan_push(BufEntry { token: Token::End, size: -1 });
+ let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
+ self.scan_stack.push_back(right);
}
}
- fn scan_break(&mut self, b: BreakToken) {
+ fn scan_break(&mut self, token: BreakToken) {
if self.scan_stack.is_empty() {
self.left_total = 1;
self.right_total = 1;
- self.left = 0;
- self.right = 0;
+ self.buf.clear();
} else {
- self.advance_right();
+ self.check_stack(0);
}
- debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
- self.check_stack(0);
- self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
- self.right_total += b.blank_space;
+ let right = self.buf.push(BufEntry { token: Token::Break(token), size: -self.right_total });
+ self.scan_stack.push_back(right);
+ self.right_total += token.blank_space;
}
- fn scan_string(&mut self, s: Cow<'static, str>) {
+ fn scan_string(&mut self, string: Cow<'static, str>) {
if self.scan_stack.is_empty() {
- debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right);
- self.print_string(s);
+ self.print_string(&string);
} else {
- debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right);
- self.advance_right();
- let len = s.len() as isize;
- self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
+ let len = string.len() as isize;
+ self.buf.push(BufEntry { token: Token::String(string), size: len });
self.right_total += len;
self.check_stream();
}
}
+ pub fn offset(&mut self, offset: isize) {
+ if let Some(BufEntry { token: Token::Break(token), .. }) = &mut self.buf.last_mut() {
+ token.offset += offset;
+ }
+ }
+
fn check_stream(&mut self) {
- debug!(
- "check_stream Vec<{}, {}> with left_total={}, right_total={}",
- self.left, self.right, self.left_total, self.right_total
- );
- if self.right_total - self.left_total > self.space {
- debug!(
- "scan window is {}, longer than space on line ({})",
- self.right_total - self.left_total,
- self.space
- );
- if Some(&self.left) == self.scan_stack.back() {
- debug!("setting {} to infinity and popping", self.left);
- let scanned = self.scan_pop_bottom();
- self.buf[scanned].size = SIZE_INFINITY;
+ while self.right_total - self.left_total > self.space {
+ if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
+ self.scan_stack.pop_front().unwrap();
+ self.buf.first_mut().unwrap().size = SIZE_INFINITY;
}
self.advance_left();
- if self.left != self.right {
- self.check_stream();
+ if self.buf.is_empty() {
+ break;
}
}
}
- fn scan_push(&mut self, entry: BufEntry) {
- debug!("scan_push {}", self.right);
- self.buf[self.right] = entry;
- self.scan_stack.push_front(self.right);
- }
-
- fn scan_pop(&mut self) -> usize {
- self.scan_stack.pop_front().unwrap()
- }
-
- fn scan_top(&self) -> usize {
- *self.scan_stack.front().unwrap()
- }
-
- fn scan_pop_bottom(&mut self) -> usize {
- self.scan_stack.pop_back().unwrap()
- }
-
- fn advance_right(&mut self) {
- self.right += 1;
- self.right %= self.buf_max_len;
- // Extend the buf if necessary.
- if self.right == self.buf.len() {
- self.buf.push(BufEntry::default());
- }
- assert_ne!(self.right, self.left);
- }
-
fn advance_left(&mut self) {
- debug!(
- "advance_left Vec<{},{}>, sizeof({})={}",
- self.left, self.right, self.left, self.buf[self.left].size
- );
+ while self.buf.first().unwrap().size >= 0 {
+ let left = self.buf.pop_first().unwrap();
- let mut left_size = self.buf[self.left].size;
-
- while left_size >= 0 {
- let left = self.buf[self.left].token.clone();
-
- let len = match left {
- Token::Break(b) => b.blank_space,
- Token::String(ref s) => {
- let len = s.len() as isize;
- assert_eq!(len, left_size);
- len
+ match &left.token {
+ Token::String(string) => {
+ self.left_total += string.len() as isize;
+ self.print_string(string);
}
- _ => 0,
- };
-
- self.print(left, left_size);
-
- self.left_total += len;
-
- if self.left == self.right {
- break;
+ Token::Break(token) => {
+ self.left_total += token.blank_space;
+ self.print_break(*token, left.size);
+ }
+ Token::Begin(token) => self.print_begin(*token, left.size),
+ Token::End => self.print_end(),
}
- self.left += 1;
- self.left %= self.buf_max_len;
+ self.last_printed = Some(left.token);
- left_size = self.buf[self.left].size;
+ if self.buf.is_empty() {
+ break;
+ }
}
}
- fn check_stack(&mut self, k: usize) {
- if !self.scan_stack.is_empty() {
- let x = self.scan_top();
- match self.buf[x].token {
+ fn check_stack(&mut self, mut depth: usize) {
+ while let Some(&index) = self.scan_stack.back() {
+ let mut entry = &mut self.buf[index];
+ match entry.token {
Token::Begin(_) => {
- if k > 0 {
- self.scan_pop();
- self.buf[x].size += self.right_total;
- self.check_stack(k - 1);
+ if depth == 0 {
+ break;
}
+ self.scan_stack.pop_back().unwrap();
+ entry.size += self.right_total;
+ depth -= 1;
}
Token::End => {
// paper says + not =, but that makes no sense.
- self.scan_pop();
- self.buf[x].size = 1;
- self.check_stack(k + 1);
+ self.scan_stack.pop_back().unwrap();
+ entry.size = 1;
+ depth += 1;
}
_ => {
- self.scan_pop();
- self.buf[x].size += self.right_total;
- if k > 0 {
- self.check_stack(k);
+ self.scan_stack.pop_back().unwrap();
+ entry.size += self.right_total;
+ if depth == 0 {
+ break;
}
}
}
}
}
- fn print_newline(&mut self, amount: isize) {
- debug!("NEWLINE {}", amount);
- self.out.push('\n');
- self.pending_indentation = 0;
- self.indent(amount);
+ fn get_top(&self) -> PrintFrame {
+ *self
+ .print_stack
+ .last()
+ .unwrap_or(&PrintFrame::Broken { indent: 0, breaks: Breaks::Inconsistent })
}
- fn indent(&mut self, amount: isize) {
- debug!("INDENT {}", amount);
- self.pending_indentation += amount;
- }
-
- fn get_top(&self) -> PrintStackElem {
- *self.print_stack.last().unwrap_or({
- &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
- })
- }
-
- fn print_begin(&mut self, b: BeginToken, l: isize) {
- if l > self.space {
- let col = self.margin - self.space + b.offset;
- debug!("print Begin -> push broken block at col {}", col);
- self.print_stack
- .push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
+ fn print_begin(&mut self, token: BeginToken, size: isize) {
+ if size > self.space {
+ self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
+ self.indent = match token.indent {
+ IndentStyle::Block { offset } => {
+ usize::try_from(self.indent as isize + offset).unwrap()
+ }
+ IndentStyle::Visual => (MARGIN - self.space) as usize,
+ };
} else {
- debug!("print Begin -> push fitting block");
- self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
+ self.print_stack.push(PrintFrame::Fits);
}
}
fn print_end(&mut self) {
- debug!("print End -> pop End");
- self.print_stack.pop().unwrap();
- }
-
- fn print_break(&mut self, b: BreakToken, l: isize) {
- let top = self.get_top();
- match top.pbreak {
- PrintStackBreak::Fits => {
- debug!("print Break({}) in fitting block", b.blank_space);
- self.space -= b.blank_space;
- self.indent(b.blank_space);
- }
- PrintStackBreak::Broken(Breaks::Consistent) => {
- debug!("print Break({}+{}) in consistent block", top.offset, b.offset);
- self.print_newline(top.offset + b.offset);
- self.space = self.margin - (top.offset + b.offset);
- }
- PrintStackBreak::Broken(Breaks::Inconsistent) => {
- if l > self.space {
- debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset);
- self.print_newline(top.offset + b.offset);
- self.space = self.margin - (top.offset + b.offset);
- } else {
- debug!("print Break({}) w/o newline in inconsistent", b.blank_space);
- self.indent(b.blank_space);
- self.space -= b.blank_space;
- }
- }
+ if let PrintFrame::Broken { indent, .. } = self.print_stack.pop().unwrap() {
+ self.indent = indent;
}
}
- fn print_string(&mut self, s: Cow<'static, str>) {
- let len = s.len() as isize;
- debug!("print String({})", s);
- // assert!(len <= space);
- self.space -= len;
+ fn print_break(&mut self, token: BreakToken, size: isize) {
+ let fits = match self.get_top() {
+ PrintFrame::Fits => true,
+ PrintFrame::Broken { breaks: Breaks::Consistent, .. } => false,
+ PrintFrame::Broken { breaks: Breaks::Inconsistent, .. } => size <= self.space,
+ };
+ if fits {
+ self.pending_indentation += token.blank_space;
+ self.space -= token.blank_space;
+ } else {
+ if let Some(pre_break) = token.pre_break {
+ self.out.push(pre_break);
+ }
+ self.out.push('\n');
+ let indent = self.indent as isize + token.offset;
+ self.pending_indentation = indent;
+ self.space = cmp::max(MARGIN - indent, MIN_SPACE);
+ }
+ }
+ fn print_string(&mut self, string: &str) {
// Write the pending indent. A more concise way of doing this would be:
//
// write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?;
@@ -547,83 +442,10 @@
// But that is significantly slower. This code is sufficiently hot, and indents can get
// sufficiently large, that the difference is significant on some workloads.
self.out.reserve(self.pending_indentation as usize);
- self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
+ self.out.extend(iter::repeat(' ').take(self.pending_indentation as usize));
self.pending_indentation = 0;
- self.out.push_str(&s);
- }
- fn print(&mut self, token: Token, l: isize) {
- debug!("print {} {} (remaining line space={})", token, l, self.space);
- debug!("{}", buf_str(&self.buf, self.left, self.right, 6));
- match token {
- Token::Begin(b) => self.print_begin(b, l),
- Token::End => self.print_end(),
- Token::Break(b) => self.print_break(b, l),
- Token::String(s) => {
- let len = s.len() as isize;
- assert_eq!(len, l);
- self.print_string(s);
- }
- Token::Eof => panic!(), // Eof should never get here.
- }
- }
-
- // Convenience functions to talk to the printer.
-
- /// "raw box"
- pub fn rbox(&mut self, indent: usize, b: Breaks) {
- self.scan_begin(BeginToken { offset: indent as isize, breaks: b })
- }
-
- /// Inconsistent breaking box
- pub fn ibox(&mut self, indent: usize) {
- self.rbox(indent, Breaks::Inconsistent)
- }
-
- /// Consistent breaking box
- pub fn cbox(&mut self, indent: usize) {
- self.rbox(indent, Breaks::Consistent)
- }
-
- pub fn break_offset(&mut self, n: usize, off: isize) {
- self.scan_break(BreakToken { offset: off, blank_space: n as isize })
- }
-
- pub fn end(&mut self) {
- self.scan_end()
- }
-
- pub fn eof(mut self) -> String {
- self.scan_eof();
- self.out
- }
-
- pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
- let s = wrd.into();
- self.scan_string(s)
- }
-
- fn spaces(&mut self, n: usize) {
- self.break_offset(n, 0)
- }
-
- crate fn zerobreak(&mut self) {
- self.spaces(0)
- }
-
- pub fn space(&mut self) {
- self.spaces(1)
- }
-
- pub fn hardbreak(&mut self) {
- self.spaces(SIZE_INFINITY as usize)
- }
-
- pub fn is_beginning_of_line(&self) -> bool {
- self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
- }
-
- pub fn hardbreak_tok_offset(off: isize) -> Token {
- Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
+ self.out.push_str(string);
+ self.space -= string.len() as isize;
}
}
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
new file mode 100644
index 0000000..93310dd
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs
@@ -0,0 +1,94 @@
+use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY};
+use std::borrow::Cow;
+
+impl Printer {
+ /// "raw box"
+ pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
+ self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
+ }
+
+ /// Inconsistent breaking box
+ pub fn ibox(&mut self, indent: isize) {
+ self.rbox(indent, Breaks::Inconsistent)
+ }
+
+ /// Consistent breaking box
+ pub fn cbox(&mut self, indent: isize) {
+ self.rbox(indent, Breaks::Consistent)
+ }
+
+ pub fn visual_align(&mut self) {
+ self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
+ }
+
+ pub fn break_offset(&mut self, n: usize, off: isize) {
+ self.scan_break(BreakToken {
+ offset: off,
+ blank_space: n as isize,
+ ..BreakToken::default()
+ });
+ }
+
+ pub fn end(&mut self) {
+ self.scan_end()
+ }
+
+ pub fn eof(mut self) -> String {
+ self.scan_eof();
+ self.out
+ }
+
+ pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
+ let string = wrd.into();
+ self.scan_string(string)
+ }
+
+ fn spaces(&mut self, n: usize) {
+ self.break_offset(n, 0)
+ }
+
+ pub fn zerobreak(&mut self) {
+ self.spaces(0)
+ }
+
+ pub fn space(&mut self) {
+ self.spaces(1)
+ }
+
+ pub fn hardbreak(&mut self) {
+ self.spaces(SIZE_INFINITY as usize)
+ }
+
+ pub fn is_beginning_of_line(&self) -> bool {
+ match self.last_token() {
+ Some(last_token) => last_token.is_hardbreak_tok(),
+ None => true,
+ }
+ }
+
+ pub fn hardbreak_tok_offset(off: isize) -> Token {
+ Token::Break(BreakToken {
+ offset: off,
+ blank_space: SIZE_INFINITY,
+ ..BreakToken::default()
+ })
+ }
+
+ pub fn trailing_comma(&mut self) {
+ self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
+ }
+
+ pub fn trailing_comma_or_space(&mut self) {
+ self.scan_break(BreakToken {
+ blank_space: 1,
+ pre_break: Some(','),
+ ..BreakToken::default()
+ });
+ }
+}
+
+impl Token {
+ pub fn is_hardbreak_tok(&self) -> bool {
+ *self == Printer::hardbreak_tok_offset(0)
+ }
+}
diff --git a/compiler/rustc_ast_pretty/src/pp/ring.rs b/compiler/rustc_ast_pretty/src/pp/ring.rs
new file mode 100644
index 0000000..8187394
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pp/ring.rs
@@ -0,0 +1,77 @@
+use std::collections::VecDeque;
+use std::ops::{Index, IndexMut};
+
+/// A view onto a finite range of an infinitely long sequence of T.
+///
+/// The Ts are indexed 0..infinity. A RingBuffer begins as a view of elements
+/// 0..0 (i.e. nothing). The user of the RingBuffer advances its left and right
+/// position independently, although only in the positive direction, and only
+/// with left <= right at all times.
+///
+/// Holding a RingBuffer whose view is elements left..right gives the ability to
+/// use Index and IndexMut to access elements i in the infinitely long queue for
+/// which left <= i < right.
+pub struct RingBuffer<T> {
+ data: VecDeque<T>,
+ // Abstract index of data[0] in the infinitely sized queue.
+ offset: usize,
+}
+
+impl<T> RingBuffer<T> {
+ pub fn new() -> Self {
+ RingBuffer { data: VecDeque::new(), offset: 0 }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.data.is_empty()
+ }
+
+ pub fn push(&mut self, value: T) -> usize {
+ let index = self.offset + self.data.len();
+ self.data.push_back(value);
+ index
+ }
+
+ pub fn clear(&mut self) {
+ self.data.clear();
+ }
+
+ pub fn index_of_first(&self) -> usize {
+ self.offset
+ }
+
+ pub fn first(&self) -> Option<&T> {
+ self.data.front()
+ }
+
+ pub fn first_mut(&mut self) -> Option<&mut T> {
+ self.data.front_mut()
+ }
+
+ pub fn pop_first(&mut self) -> Option<T> {
+ let first = self.data.pop_front()?;
+ self.offset += 1;
+ Some(first)
+ }
+
+ pub fn last(&self) -> Option<&T> {
+ self.data.back()
+ }
+
+ pub fn last_mut(&mut self) -> Option<&mut T> {
+ self.data.back_mut()
+ }
+}
+
+impl<T> Index<usize> for RingBuffer<T> {
+ type Output = T;
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.data[index.checked_sub(self.offset).unwrap()]
+ }
+}
+
+impl<T> IndexMut<usize> for RingBuffer<T> {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ &mut self.data[index.checked_sub(self.offset).unwrap()]
+ }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index fa9a20f..b2c6238 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1,15 +1,19 @@
+mod delimited;
+mod expr;
+mod item;
+
use crate::pp::Breaks::{Consistent, Inconsistent};
use crate::pp::{self, Breaks};
-use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::util::classify;
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
-use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::util::parser;
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs, ModKind};
+use rustc_ast::{attr, Term};
+use rustc_ast::{GenericArg, MacArgs};
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -20,6 +24,8 @@
use std::borrow::Cow;
+pub use self::delimited::IterDelimited;
+
pub enum MacHeader<'a> {
Path(&'a ast::Path),
Keyword(&'static str),
@@ -89,7 +95,7 @@
ann: &'a (dyn PpAnn + 'a),
}
-crate const INDENT_UNIT: usize = 4;
+crate const INDENT_UNIT: isize = 4;
/// Requires you to pass an input filename and reader so that
/// it can scan the input text for comments to copy forward.
@@ -103,7 +109,7 @@
edition: Edition,
) -> String {
let mut s =
- State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
+ State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
// We need to print `#![no_std]` (and its feature gate) so that
@@ -210,10 +216,6 @@
out
}
-fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
- format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
-}
-
impl std::ops::Deref for State<'_> {
type Target = pp::Printer;
fn deref(&self) -> &Self::Target {
@@ -316,7 +318,7 @@
self.word(cmnt.lines[0].clone());
self.hardbreak()
} else {
- self.ibox(0);
+ self.visual_align();
for line in &cmnt.lines {
if !line.is_empty() {
self.word(line.clone());
@@ -329,9 +331,9 @@
CommentStyle::BlankLine => {
// We need to do at least one, possibly two hardbreaks.
let twice = match self.last_token() {
- pp::Token::String(s) => ";" == s,
- pp::Token::Begin(_) => true,
- pp::Token::End => true,
+ Some(pp::Token::String(s)) => ";" == s,
+ Some(pp::Token::Begin(_)) => true,
+ Some(pp::Token::End) => true,
_ => false,
};
if twice {
@@ -608,7 +610,7 @@
&mut self,
macro_def: &ast::MacroDef,
ident: &Ident,
- sp: &Span,
+ sp: Span,
print_visibility: impl FnOnce(&mut Self),
) {
let (kw, has_bang) = if macro_def.macro_rules {
@@ -624,7 +626,7 @@
macro_def.body.delim(),
¯o_def.body.inner_tokens(),
true,
- *sp,
+ sp,
);
if macro_def.body.need_semicolon() {
self.word(";");
@@ -656,7 +658,7 @@
// Outer-box is consistent.
self.cbox(INDENT_UNIT);
// Head-box is inconsistent.
- self.ibox(w.len() + 1);
+ self.ibox(0);
// Keyword that starts the head.
if !w.is_empty() {
self.word_nbsp(w);
@@ -687,11 +689,15 @@
fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
if !self.is_beginning_of_line() {
self.break_offset(n, off)
- } else if off != 0 && self.last_token().is_hardbreak_tok() {
- // We do something pretty sketchy here: tuck the nonzero
- // offset-adjustment we were going to deposit along with the
- // break into the previous hardbreak.
- self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
+ } else if off != 0 {
+ if let Some(last_token) = self.last_token_still_buffered() {
+ if last_token.is_hardbreak_tok() {
+ // We do something pretty sketchy here: tuck the nonzero
+ // offset-adjustment we were going to deposit along with the
+ // break into the previous hardbreak.
+ self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
+ }
+ }
}
}
@@ -910,7 +916,7 @@
impl<'a> State<'a> {
pub fn new() -> State<'a> {
- State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
+ State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
}
crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
@@ -938,13 +944,6 @@
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
}
- crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
- self.print_inner_attributes(attrs);
- for item in &nmod.items {
- self.print_foreign_item(item);
- }
- }
-
pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
if let Some(lt) = *lifetime {
self.print_lifetime(lt);
@@ -952,18 +951,19 @@
}
}
- pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+ pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
self.space();
match &constraint.kind {
- ast::AssocTyConstraintKind::Equality { ty } => {
+ ast::AssocConstraintKind::Equality { term } => {
self.word_space("=");
- self.print_type(ty);
+ match term {
+ Term::Ty(ty) => self.print_type(ty),
+ Term::Const(c) => self.print_expr_anon_const(c),
+ }
}
- ast::AssocTyConstraintKind::Bound { bounds } => {
- self.print_type_bounds(":", &*bounds);
- }
+ ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
}
}
@@ -1056,343 +1056,6 @@
self.end();
}
- crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
- let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
- self.ann.pre(self, AnnNode::SubItem(id));
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(span.lo());
- self.print_outer_attributes(attrs);
- match kind {
- ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
- self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
- }
- ast::ForeignItemKind::Static(ty, mutbl, body) => {
- let def = ast::Defaultness::Final;
- self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
- }
- ast::ForeignItemKind::TyAlias(box ast::TyAlias {
- defaultness,
- generics,
- bounds,
- ty,
- }) => {
- self.print_associated_type(
- ident,
- generics,
- bounds,
- ty.as_deref(),
- vis,
- *defaultness,
- );
- }
- ast::ForeignItemKind::MacCall(m) => {
- self.print_mac(m);
- if m.args.need_semicolon() {
- self.word(";");
- }
- }
- }
- self.ann.post(self, AnnNode::SubItem(id))
- }
-
- fn print_item_const(
- &mut self,
- ident: Ident,
- mutbl: Option<ast::Mutability>,
- ty: &ast::Ty,
- body: Option<&ast::Expr>,
- vis: &ast::Visibility,
- defaultness: ast::Defaultness,
- ) {
- self.head("");
- self.print_visibility(vis);
- self.print_defaultness(defaultness);
- let leading = match mutbl {
- None => "const",
- Some(ast::Mutability::Not) => "static",
- Some(ast::Mutability::Mut) => "static mut",
- };
- self.word_space(leading);
- self.print_ident(ident);
- self.word_space(":");
- self.print_type(ty);
- if body.is_some() {
- self.space();
- }
- self.end(); // end the head-ibox
- if let Some(body) = body {
- self.word_space("=");
- self.print_expr(body);
- }
- self.word(";");
- self.end(); // end the outer cbox
- }
-
- fn print_associated_type(
- &mut self,
- ident: Ident,
- generics: &ast::Generics,
- bounds: &ast::GenericBounds,
- ty: Option<&ast::Ty>,
- vis: &ast::Visibility,
- defaultness: ast::Defaultness,
- ) {
- self.head("");
- self.print_visibility(vis);
- self.print_defaultness(defaultness);
- self.word_space("type");
- self.print_ident(ident);
- self.print_generic_params(&generics.params);
- self.print_type_bounds(":", bounds);
- self.print_where_clause(&generics.where_clause);
- if let Some(ty) = ty {
- self.space();
- self.word_space("=");
- self.print_type(ty);
- }
- self.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
-
- /// Pretty-prints an item.
- crate fn print_item(&mut self, item: &ast::Item) {
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(item.span.lo());
- self.print_outer_attributes(&item.attrs);
- self.ann.pre(self, AnnNode::Item(item));
- match item.kind {
- ast::ItemKind::ExternCrate(orig_name) => {
- self.head(visibility_qualified(&item.vis, "extern crate"));
- if let Some(orig_name) = orig_name {
- self.print_name(orig_name);
- self.space();
- self.word("as");
- self.space();
- }
- self.print_ident(item.ident);
- self.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
- ast::ItemKind::Use(ref tree) => {
- self.head(visibility_qualified(&item.vis, "use"));
- self.print_use_tree(tree);
- self.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
- ast::ItemKind::Static(ref ty, mutbl, ref body) => {
- let def = ast::Defaultness::Final;
- self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
- }
- ast::ItemKind::Const(def, ref ty, ref body) => {
- self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
- }
- ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
- let body = body.as_deref();
- self.print_fn_full(
- sig,
- item.ident,
- generics,
- &item.vis,
- defaultness,
- body,
- &item.attrs,
- );
- }
- ast::ItemKind::Mod(unsafety, ref mod_kind) => {
- self.head(Self::to_string(|s| {
- s.print_visibility(&item.vis);
- s.print_unsafety(unsafety);
- s.word("mod");
- }));
- self.print_ident(item.ident);
-
- match mod_kind {
- ModKind::Loaded(items, ..) => {
- self.nbsp();
- self.bopen();
- self.print_inner_attributes(&item.attrs);
- for item in items {
- self.print_item(item);
- }
- let empty = item.attrs.is_empty() && items.is_empty();
- self.bclose(item.span, empty);
- }
- ModKind::Unloaded => {
- self.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
- }
- }
- }
- ast::ItemKind::ForeignMod(ref nmod) => {
- self.head(Self::to_string(|s| {
- s.print_unsafety(nmod.unsafety);
- s.word("extern");
- }));
- if let Some(abi) = nmod.abi {
- self.print_literal(&abi.as_lit());
- self.nbsp();
- }
- self.bopen();
- self.print_foreign_mod(nmod, &item.attrs);
- let empty = item.attrs.is_empty() && nmod.items.is_empty();
- self.bclose(item.span, empty);
- }
- ast::ItemKind::GlobalAsm(ref asm) => {
- self.head(visibility_qualified(&item.vis, "global_asm!"));
- self.print_inline_asm(asm);
- self.end();
- }
- ast::ItemKind::TyAlias(box ast::TyAlias {
- defaultness,
- ref generics,
- ref bounds,
- ref ty,
- }) => {
- let ty = ty.as_deref();
- self.print_associated_type(
- item.ident,
- generics,
- bounds,
- ty,
- &item.vis,
- defaultness,
- );
- }
- ast::ItemKind::Enum(ref enum_definition, ref params) => {
- self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
- }
- ast::ItemKind::Struct(ref struct_def, ref generics) => {
- self.head(visibility_qualified(&item.vis, "struct"));
- self.print_struct(struct_def, generics, item.ident, item.span, true);
- }
- ast::ItemKind::Union(ref struct_def, ref generics) => {
- self.head(visibility_qualified(&item.vis, "union"));
- self.print_struct(struct_def, generics, item.ident, item.span, true);
- }
- ast::ItemKind::Impl(box ast::Impl {
- unsafety,
- polarity,
- defaultness,
- constness,
- ref generics,
- ref of_trait,
- ref self_ty,
- ref items,
- }) => {
- self.head("");
- self.print_visibility(&item.vis);
- self.print_defaultness(defaultness);
- self.print_unsafety(unsafety);
- self.word("impl");
-
- if generics.params.is_empty() {
- self.nbsp();
- } else {
- self.print_generic_params(&generics.params);
- self.space();
- }
-
- self.print_constness(constness);
-
- if let ast::ImplPolarity::Negative(_) = polarity {
- self.word("!");
- }
-
- if let Some(ref t) = *of_trait {
- self.print_trait_ref(t);
- self.space();
- self.word_space("for");
- }
-
- self.print_type(self_ty);
- self.print_where_clause(&generics.where_clause);
-
- self.space();
- self.bopen();
- self.print_inner_attributes(&item.attrs);
- for impl_item in items {
- self.print_assoc_item(impl_item);
- }
- let empty = item.attrs.is_empty() && items.is_empty();
- self.bclose(item.span, empty);
- }
- ast::ItemKind::Trait(box ast::Trait {
- is_auto,
- unsafety,
- ref generics,
- ref bounds,
- ref items,
- ..
- }) => {
- self.head("");
- self.print_visibility(&item.vis);
- self.print_unsafety(unsafety);
- self.print_is_auto(is_auto);
- self.word_nbsp("trait");
- self.print_ident(item.ident);
- self.print_generic_params(&generics.params);
- let mut real_bounds = Vec::with_capacity(bounds.len());
- for b in bounds.iter() {
- if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
- self.space();
- self.word_space("for ?");
- self.print_trait_ref(&ptr.trait_ref);
- } else {
- real_bounds.push(b.clone());
- }
- }
- self.print_type_bounds(":", &real_bounds);
- self.print_where_clause(&generics.where_clause);
- self.word(" ");
- self.bopen();
- self.print_inner_attributes(&item.attrs);
- for trait_item in items {
- self.print_assoc_item(trait_item);
- }
- let empty = item.attrs.is_empty() && items.is_empty();
- self.bclose(item.span, empty);
- }
- ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
- self.head("");
- self.print_visibility(&item.vis);
- self.word_nbsp("trait");
- self.print_ident(item.ident);
- self.print_generic_params(&generics.params);
- let mut real_bounds = Vec::with_capacity(bounds.len());
- // FIXME(durka) this seems to be some quite outdated syntax
- for b in bounds.iter() {
- if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
- self.space();
- self.word_space("for ?");
- self.print_trait_ref(&ptr.trait_ref);
- } else {
- real_bounds.push(b.clone());
- }
- }
- self.nbsp();
- self.print_type_bounds("=", &real_bounds);
- self.print_where_clause(&generics.where_clause);
- self.word(";");
- }
- ast::ItemKind::MacCall(ref mac) => {
- self.print_mac(mac);
- if mac.args.need_semicolon() {
- self.word(";");
- }
- }
- ast::ItemKind::MacroDef(ref macro_def) => {
- self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
- state.print_visibility(&item.vis)
- });
- }
- }
- self.ann.post(self, AnnNode::Item(item))
- }
-
fn print_trait_ref(&mut self, t: &ast::TraitRef) {
self.print_path(&t.path, false, 0)
}
@@ -1410,167 +1073,6 @@
self.print_trait_ref(&t.trait_ref)
}
- crate fn print_enum_def(
- &mut self,
- enum_definition: &ast::EnumDef,
- generics: &ast::Generics,
- ident: Ident,
- span: rustc_span::Span,
- visibility: &ast::Visibility,
- ) {
- self.head(visibility_qualified(visibility, "enum"));
- self.print_ident(ident);
- self.print_generic_params(&generics.params);
- self.print_where_clause(&generics.where_clause);
- self.space();
- self.print_variants(&enum_definition.variants, span)
- }
-
- crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
- self.bopen();
- for v in variants {
- self.space_if_not_bol();
- self.maybe_print_comment(v.span.lo());
- self.print_outer_attributes(&v.attrs);
- self.ibox(INDENT_UNIT);
- self.print_variant(v);
- self.word(",");
- self.end();
- self.maybe_print_trailing_comment(v.span, None);
- }
- let empty = variants.is_empty();
- self.bclose(span, empty)
- }
-
- crate fn print_visibility(&mut self, vis: &ast::Visibility) {
- match vis.kind {
- ast::VisibilityKind::Public => self.word_nbsp("pub"),
- ast::VisibilityKind::Crate(sugar) => match sugar {
- ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
- ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
- },
- ast::VisibilityKind::Restricted { ref path, .. } => {
- let path = Self::to_string(|s| s.print_path(path, false, 0));
- if path == "self" || path == "super" {
- self.word_nbsp(format!("pub({})", path))
- } else {
- self.word_nbsp(format!("pub(in {})", path))
- }
- }
- ast::VisibilityKind::Inherited => {}
- }
- }
-
- crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
- if let ast::Defaultness::Default(_) = defaultness {
- self.word_nbsp("default");
- }
- }
-
- crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
- self.nbsp();
- self.bopen();
-
- let empty = fields.is_empty();
- if !empty {
- self.hardbreak_if_not_bol();
-
- for field in fields {
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(field.span.lo());
- self.print_outer_attributes(&field.attrs);
- self.print_visibility(&field.vis);
- self.print_ident(field.ident.unwrap());
- self.word_nbsp(":");
- self.print_type(&field.ty);
- self.word(",");
- }
- }
-
- self.bclose(span, empty);
- }
-
- crate fn print_struct(
- &mut self,
- struct_def: &ast::VariantData,
- generics: &ast::Generics,
- ident: Ident,
- span: rustc_span::Span,
- print_finalizer: bool,
- ) {
- self.print_ident(ident);
- self.print_generic_params(&generics.params);
- match struct_def {
- ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
- if let ast::VariantData::Tuple(..) = struct_def {
- self.popen();
- self.commasep(Inconsistent, struct_def.fields(), |s, field| {
- s.maybe_print_comment(field.span.lo());
- s.print_outer_attributes(&field.attrs);
- s.print_visibility(&field.vis);
- s.print_type(&field.ty)
- });
- self.pclose();
- }
- self.print_where_clause(&generics.where_clause);
- if print_finalizer {
- self.word(";");
- }
- self.end();
- self.end(); // Close the outer-box.
- }
- ast::VariantData::Struct(ref fields, ..) => {
- self.print_where_clause(&generics.where_clause);
- self.print_record_struct_body(fields, span);
- }
- }
- }
-
- crate fn print_variant(&mut self, v: &ast::Variant) {
- self.head("");
- self.print_visibility(&v.vis);
- let generics = ast::Generics::default();
- self.print_struct(&v.data, &generics, v.ident, v.span, false);
- if let Some(ref d) = v.disr_expr {
- self.space();
- self.word_space("=");
- self.print_expr(&d.value)
- }
- }
-
- crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
- let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
- self.ann.pre(self, AnnNode::SubItem(id));
- self.hardbreak_if_not_bol();
- self.maybe_print_comment(span.lo());
- self.print_outer_attributes(attrs);
- match kind {
- ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
- self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
- }
- ast::AssocItemKind::Const(def, ty, body) => {
- self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
- }
- ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
- self.print_associated_type(
- ident,
- generics,
- bounds,
- ty.as_deref(),
- vis,
- *defaultness,
- );
- }
- ast::AssocItemKind::MacCall(m) => {
- self.print_mac(m);
- if m.args.need_semicolon() {
- self.word(";");
- }
- }
- }
- self.ann.post(self, AnnNode::SubItem(id))
- }
-
crate fn print_stmt(&mut self, st: &ast::Stmt) {
self.maybe_print_comment(st.span.lo());
match st.kind {
@@ -1681,42 +1183,6 @@
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
}
- fn print_else(&mut self, els: Option<&ast::Expr>) {
- if let Some(_else) = els {
- match _else.kind {
- // Another `else if` block.
- ast::ExprKind::If(ref i, ref then, ref e) => {
- self.cbox(INDENT_UNIT - 1);
- self.ibox(0);
- self.word(" else if ");
- self.print_expr_as_cond(i);
- self.space();
- self.print_block(then);
- self.print_else(e.as_deref())
- }
- // Final `else` block.
- ast::ExprKind::Block(ref b, _) => {
- self.cbox(INDENT_UNIT - 1);
- self.ibox(0);
- self.word(" else ");
- self.print_block(b)
- }
- // Constraints would be great here!
- _ => {
- panic!("print_if saw if with weird alternative");
- }
- }
- }
- }
-
- 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.space();
- self.print_block(blk);
- self.print_else(elseopt)
- }
-
crate fn print_mac(&mut self, m: &ast::MacCall) {
self.print_mac_common(
Some(MacHeader::Path(&m.path)),
@@ -1729,533 +1195,6 @@
);
}
- fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
- self.popen();
- self.commasep_exprs(Inconsistent, args);
- self.pclose()
- }
-
- crate fn print_expr_maybe_paren(&mut self, expr: &ast::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 { ... }`.
- crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
- self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
- }
-
- // Does `expr` need parentheses 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 {
- ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
- _ => parser::contains_exterior_struct_lit(expr),
- }
- }
-
- /// Prints `expr` or `(expr)` when `needs_par` holds.
- fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
- if needs_par {
- self.popen();
- }
- self.print_expr(expr);
- if needs_par {
- self.pclose();
- }
- }
-
- fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
- self.ibox(INDENT_UNIT);
- self.word("[");
- self.commasep_exprs(Inconsistent, exprs);
- self.word("]");
- self.end();
- }
-
- fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
- self.ibox(INDENT_UNIT);
- self.word("const");
- self.print_expr(&expr.value);
- self.end();
- }
-
- fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
- self.ibox(INDENT_UNIT);
- self.word("[");
- self.print_expr(element);
- self.word_space(";");
- self.print_expr(&count.value);
- self.word("]");
- self.end();
- }
-
- fn print_expr_struct(
- &mut self,
- qself: &Option<ast::QSelf>,
- path: &ast::Path,
- fields: &[ast::ExprField],
- rest: &ast::StructRest,
- ) {
- if let Some(qself) = qself {
- self.print_qpath(path, qself, true);
- } else {
- self.print_path(path, true, 0);
- }
- self.word("{");
- self.commasep_cmnt(
- Consistent,
- fields,
- |s, field| {
- s.print_outer_attributes(&field.attrs);
- s.ibox(INDENT_UNIT);
- if !field.is_shorthand {
- s.print_ident(field.ident);
- s.word_space(":");
- }
- s.print_expr(&field.expr);
- s.end();
- },
- |f| f.span,
- );
- match rest {
- ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
- self.ibox(INDENT_UNIT);
- if !fields.is_empty() {
- self.word(",");
- self.space();
- }
- self.word("..");
- if let ast::StructRest::Base(ref expr) = *rest {
- self.print_expr(expr);
- }
- self.end();
- }
- ast::StructRest::None if !fields.is_empty() => self.word(","),
- _ => {}
- }
- self.word("}");
- }
-
- fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
- self.popen();
- self.commasep_exprs(Inconsistent, exprs);
- if exprs.len() == 1 {
- self.word(",");
- }
- self.pclose()
- }
-
- fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
- let prec = match func.kind {
- ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
- _ => parser::PREC_POSTFIX,
- };
-
- self.print_expr_maybe_paren(func, prec);
- self.print_call_post(args)
- }
-
- fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
- let base_args = &args[1..];
- self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
- self.word(".");
- self.print_ident(segment.ident);
- if let Some(ref args) = segment.args {
- self.print_generic_args(args, true);
- }
- self.print_call_post(base_args)
- }
-
- fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
- let assoc_op = AssocOp::from_ast_binop(op.node);
- let prec = assoc_op.precedence() as i8;
- let fixity = assoc_op.fixity();
-
- let (left_prec, right_prec) = match fixity {
- Fixity::Left => (prec, prec + 1),
- Fixity::Right => (prec + 1, prec),
- Fixity::None => (prec + 1, prec + 1),
- };
-
- let left_prec = match (&lhs.kind, op.node) {
- // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
- // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
- // of `(x as i32) < ...`. We need to convince it _not_ to do that.
- (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
- parser::PREC_FORCE_PAREN
- }
- // We are given `(let _ = a) OP b`.
- //
- // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
- // as the parser will interpret this as `(let _ = a) OP b`.
- //
- // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
- // parens are required since the parser would interpret `let a = b < c` as
- // `let a = (b < c)`. To achieve this, we force parens.
- (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
- parser::PREC_FORCE_PAREN
- }
- _ => left_prec,
- };
-
- self.print_expr_maybe_paren(lhs, left_prec);
- self.space();
- self.word_space(op.node.to_string());
- self.print_expr_maybe_paren(rhs, right_prec)
- }
-
- fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
- self.word(ast::UnOp::to_string(op));
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
- }
-
- fn print_expr_addr_of(
- &mut self,
- kind: ast::BorrowKind,
- mutability: ast::Mutability,
- expr: &ast::Expr,
- ) {
- self.word("&");
- match kind {
- ast::BorrowKind::Ref => self.print_mutability(mutability, false),
- ast::BorrowKind::Raw => {
- self.word_nbsp("raw");
- self.print_mutability(mutability, true);
- }
- }
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
- }
-
- pub fn print_expr(&mut self, expr: &ast::Expr) {
- self.print_expr_outer_attr_style(expr, true)
- }
-
- fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
- self.maybe_print_comment(expr.span.lo());
-
- let attrs = &expr.attrs;
- if is_inline {
- self.print_outer_attributes_inline(attrs);
- } else {
- self.print_outer_attributes(attrs);
- }
-
- self.ibox(INDENT_UNIT);
- self.ann.pre(self, AnnNode::Expr(expr));
- match expr.kind {
- ast::ExprKind::Box(ref expr) => {
- self.word_space("box");
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
- }
- ast::ExprKind::Array(ref exprs) => {
- self.print_expr_vec(exprs);
- }
- ast::ExprKind::ConstBlock(ref anon_const) => {
- self.print_expr_anon_const(anon_const);
- }
- ast::ExprKind::Repeat(ref element, ref count) => {
- self.print_expr_repeat(element, count);
- }
- ast::ExprKind::Struct(ref se) => {
- self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
- }
- ast::ExprKind::Tup(ref exprs) => {
- self.print_expr_tup(exprs);
- }
- ast::ExprKind::Call(ref func, ref args) => {
- self.print_expr_call(func, &args);
- }
- ast::ExprKind::MethodCall(ref segment, ref args, _) => {
- self.print_expr_method_call(segment, &args);
- }
- ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
- self.print_expr_binary(op, lhs, rhs);
- }
- ast::ExprKind::Unary(op, ref expr) => {
- self.print_expr_unary(op, expr);
- }
- ast::ExprKind::AddrOf(k, m, ref expr) => {
- self.print_expr_addr_of(k, m, expr);
- }
- ast::ExprKind::Lit(ref lit) => {
- self.print_literal(lit);
- }
- ast::ExprKind::Cast(ref expr, ref ty) => {
- let prec = AssocOp::As.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
- self.space();
- self.word_space("as");
- self.print_type(ty);
- }
- ast::ExprKind::Type(ref expr, ref ty) => {
- let prec = AssocOp::Colon.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
- self.word_space(":");
- self.print_type(ty);
- }
- ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
- self.print_let(pat, scrutinee);
- }
- ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
- self.print_if(test, blk, elseopt.as_deref())
- }
- ast::ExprKind::While(ref test, ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- self.head("while");
- self.print_expr_as_cond(test);
- self.space();
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- self.head("for");
- self.print_pat(pat);
- self.space();
- self.word_space("in");
- self.print_expr_as_cond(iter);
- self.space();
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Loop(ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- self.head("loop");
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Match(ref expr, ref arms) => {
- self.cbox(INDENT_UNIT);
- self.ibox(INDENT_UNIT);
- self.word_nbsp("match");
- self.print_expr_as_cond(expr);
- self.space();
- self.bopen();
- self.print_inner_attributes_no_trailing_hardbreak(attrs);
- for arm in arms {
- self.print_arm(arm);
- }
- let empty = attrs.is_empty() && arms.is_empty();
- self.bclose(expr.span, empty);
- }
- ast::ExprKind::Closure(
- capture_clause,
- asyncness,
- movability,
- ref decl,
- ref body,
- _,
- ) => {
- self.print_movability(movability);
- self.print_asyncness(asyncness);
- self.print_capture_clause(capture_clause);
-
- self.print_fn_params_and_ret(decl, true);
- self.space();
- self.print_expr(body);
- self.end(); // need to close a box
-
- // a box will be closed by print_expr, but we didn't want an overall
- // wrapper so we closed the corresponding opening. so create an
- // empty box to satisfy the close.
- self.ibox(0);
- }
- ast::ExprKind::Block(ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
- // containing cbox, will be closed by print-block at }
- self.cbox(INDENT_UNIT);
- // head-box, will be closed by print-block after {
- self.ibox(0);
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Async(capture_clause, _, ref blk) => {
- self.word_nbsp("async");
- self.print_capture_clause(capture_clause);
- // cbox/ibox in analogy to the `ExprKind::Block` arm above
- self.cbox(INDENT_UNIT);
- self.ibox(0);
- self.print_block_with_attrs(blk, attrs);
- }
- ast::ExprKind::Await(ref expr) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.word(".await");
- }
- ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
- let prec = AssocOp::Assign.precedence() as i8;
- self.print_expr_maybe_paren(lhs, prec + 1);
- self.space();
- self.word_space("=");
- self.print_expr_maybe_paren(rhs, prec);
- }
- ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
- let prec = AssocOp::Assign.precedence() as i8;
- self.print_expr_maybe_paren(lhs, prec + 1);
- self.space();
- self.word(op.node.to_string());
- self.word_space("=");
- self.print_expr_maybe_paren(rhs, prec);
- }
- ast::ExprKind::Field(ref expr, ident) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.word(".");
- self.print_ident(ident);
- }
- ast::ExprKind::Index(ref expr, ref index) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.word("[");
- self.print_expr(index);
- self.word("]");
- }
- ast::ExprKind::Range(ref start, ref end, limits) => {
- // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
- // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
- // Here we use a fake precedence value so that any child with lower precedence than
- // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
- let fake_prec = AssocOp::LOr.precedence() as i8;
- if let Some(ref e) = *start {
- self.print_expr_maybe_paren(e, fake_prec);
- }
- if limits == ast::RangeLimits::HalfOpen {
- self.word("..");
- } else {
- self.word("..=");
- }
- if let Some(ref e) = *end {
- self.print_expr_maybe_paren(e, fake_prec);
- }
- }
- ast::ExprKind::Underscore => self.word("_"),
- ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
- ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
- ast::ExprKind::Break(opt_label, ref opt_expr) => {
- self.word("break");
- if let Some(label) = opt_label {
- self.space();
- self.print_ident(label.ident);
- }
- if let Some(ref expr) = *opt_expr {
- self.space();
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- }
- }
- ast::ExprKind::Continue(opt_label) => {
- self.word("continue");
- if let Some(label) = opt_label {
- self.space();
- self.print_ident(label.ident);
- }
- }
- ast::ExprKind::Ret(ref result) => {
- self.word("return");
- if let Some(ref expr) = *result {
- self.word(" ");
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- }
- }
- ast::ExprKind::InlineAsm(ref a) => {
- self.word("asm!");
- self.print_inline_asm(a);
- }
- ast::ExprKind::LlvmInlineAsm(ref a) => {
- self.word("llvm_asm!");
- self.popen();
- self.print_symbol(a.asm, a.asm_str_style);
- self.word_space(":");
-
- self.commasep(Inconsistent, &a.outputs, |s, out| {
- let constraint = out.constraint.as_str();
- let mut ch = constraint.chars();
- match ch.next() {
- Some('=') if out.is_rw => {
- s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
- }
- _ => s.print_string(&constraint, ast::StrStyle::Cooked),
- }
- s.popen();
- s.print_expr(&out.expr);
- s.pclose();
- });
- self.space();
- self.word_space(":");
-
- self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
- s.print_symbol(co, ast::StrStyle::Cooked);
- s.popen();
- s.print_expr(o);
- s.pclose();
- });
- self.space();
- self.word_space(":");
-
- self.commasep(Inconsistent, &a.clobbers, |s, &co| {
- s.print_symbol(co, ast::StrStyle::Cooked);
- });
-
- let mut options = vec![];
- if a.volatile {
- options.push("volatile");
- }
- if a.alignstack {
- options.push("alignstack");
- }
- if a.dialect == ast::LlvmAsmDialect::Intel {
- options.push("intel");
- }
-
- if !options.is_empty() {
- self.space();
- self.word_space(":");
- self.commasep(Inconsistent, &options, |s, &co| {
- s.print_string(co, ast::StrStyle::Cooked);
- });
- }
-
- self.pclose();
- }
- ast::ExprKind::MacCall(ref m) => self.print_mac(m),
- ast::ExprKind::Paren(ref e) => {
- self.popen();
- self.print_expr(e);
- self.pclose();
- }
- ast::ExprKind::Yield(ref e) => {
- self.word("yield");
-
- if let Some(ref expr) = *e {
- self.space();
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- }
- }
- ast::ExprKind::Try(ref e) => {
- self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
- self.word("?")
- }
- ast::ExprKind::TryBlock(ref blk) => {
- self.head("try");
- self.print_block_with_attrs(blk, attrs)
- }
- ast::ExprKind::Err => {
- self.popen();
- self.word("/*ERROR*/");
- self.pclose()
- }
- }
- self.ann.post(self, AnnNode::Expr(expr));
- self.end();
- }
-
fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
enum AsmArg<'a> {
Template(String),
@@ -2551,48 +1490,6 @@
self.ann.post(self, AnnNode::Pat(pat))
}
- fn print_arm(&mut self, arm: &ast::Arm) {
- // Note, I have no idea why this check is necessary, but here it is.
- if arm.attrs.is_empty() {
- self.space();
- }
- self.cbox(INDENT_UNIT);
- self.ibox(0);
- self.maybe_print_comment(arm.pat.span.lo());
- self.print_outer_attributes(&arm.attrs);
- self.print_pat(&arm.pat);
- self.space();
- if let Some(ref e) = arm.guard {
- self.word_space("if");
- self.print_expr(e);
- self.space();
- }
- self.word_space("=>");
-
- match arm.body.kind {
- ast::ExprKind::Block(ref blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
-
- // The block will close the pattern's ibox.
- self.print_block_unclosed_indent(blk);
-
- // If it is a user-provided unsafe block, print a comma after it.
- if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
- self.word(",");
- }
- }
- _ => {
- self.end(); // Close the ibox for the pattern.
- self.print_expr(&arm.body);
- self.word(",");
- }
- }
- self.end(); // Close enclosing cbox.
- }
-
fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
match explicit_self.node {
SelfKind::Value(m) => {
@@ -2614,75 +1511,12 @@
}
}
- fn print_fn_full(
- &mut self,
- sig: &ast::FnSig,
- name: Ident,
- generics: &ast::Generics,
- vis: &ast::Visibility,
- defaultness: ast::Defaultness,
- body: Option<&ast::Block>,
- attrs: &[ast::Attribute],
- ) {
- if body.is_some() {
- self.head("");
- }
- self.print_visibility(vis);
- self.print_defaultness(defaultness);
- self.print_fn(&sig.decl, sig.header, Some(name), generics);
- if let Some(body) = body {
- self.nbsp();
- self.print_block_with_attrs(body, attrs);
- } else {
- self.word(";");
- }
- }
-
- crate fn print_fn(
- &mut self,
- decl: &ast::FnDecl,
- header: ast::FnHeader,
- name: Option<Ident>,
- generics: &ast::Generics,
- ) {
- self.print_fn_header_info(header);
- if let Some(name) = name {
- self.nbsp();
- self.print_ident(name);
- }
- self.print_generic_params(&generics.params);
- self.print_fn_params_and_ret(decl, false);
- self.print_where_clause(&generics.where_clause)
- }
-
- crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
- let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
- self.word(open);
- self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
- self.word(close);
- self.print_fn_ret_ty(&decl.output)
- }
-
- crate fn print_movability(&mut self, movability: ast::Movability) {
- match movability {
- ast::Movability::Static => self.word_space("static"),
- ast::Movability::Movable => {}
- }
- }
-
crate fn print_asyncness(&mut self, asyncness: ast::Async) {
if asyncness.is_async() {
self.word_nbsp("async");
}
}
- crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
- match capture_clause {
- ast::CaptureBy::Value => self.word_space("move"),
- ast::CaptureBy::Ref => {}
- }
- }
-
pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
if !bounds.is_empty() {
self.word(prefix);
@@ -2777,83 +1611,6 @@
self.word(">");
}
- crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
- if where_clause.predicates.is_empty() && !where_clause.has_where_token {
- return;
- }
-
- self.space();
- self.word_space("where");
-
- for (i, predicate) in where_clause.predicates.iter().enumerate() {
- if i != 0 {
- self.word_space(",");
- }
-
- self.print_where_predicate(predicate);
- }
- }
-
- pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
- match predicate {
- ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- bound_generic_params,
- bounded_ty,
- bounds,
- ..
- }) => {
- self.print_formal_generic_params(bound_generic_params);
- self.print_type(bounded_ty);
- self.print_type_bounds(":", bounds);
- }
- ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
- lifetime,
- bounds,
- ..
- }) => {
- self.print_lifetime_bounds(*lifetime, bounds);
- }
- ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
- self.print_type(lhs_ty);
- self.space();
- self.word_space("=");
- self.print_type(rhs_ty);
- }
- }
- }
-
- crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
- match tree.kind {
- ast::UseTreeKind::Simple(rename, ..) => {
- self.print_path(&tree.prefix, false, 0);
- if let Some(rename) = rename {
- self.space();
- self.word_space("as");
- self.print_ident(rename);
- }
- }
- ast::UseTreeKind::Glob => {
- if !tree.prefix.segments.is_empty() {
- self.print_path(&tree.prefix, false, 0);
- self.word("::");
- }
- self.word("*");
- }
- ast::UseTreeKind::Nested(ref items) => {
- if tree.prefix.segments.is_empty() {
- self.word("{");
- } else {
- self.print_path(&tree.prefix, false, 0);
- self.word("::{");
- }
- self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
- this.print_use_tree(tree)
- });
- self.word("}");
- }
- }
- }
-
pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
match mutbl {
ast::Mutability::Mut => self.word_nbsp("mut"),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
new file mode 100644
index 0000000..fe0640b
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
@@ -0,0 +1,41 @@
+use std::iter::Peekable;
+use std::mem;
+use std::ops::Deref;
+
+pub struct Delimited<I: Iterator> {
+ is_first: bool,
+ iter: Peekable<I>,
+}
+
+pub trait IterDelimited: Iterator + Sized {
+ fn delimited(self) -> Delimited<Self> {
+ Delimited { is_first: true, iter: self.peekable() }
+ }
+}
+
+impl<I: Iterator> IterDelimited for I {}
+
+pub struct IteratorItem<T> {
+ value: T,
+ pub is_first: bool,
+ pub is_last: bool,
+}
+
+impl<I: Iterator> Iterator for Delimited<I> {
+ type Item = IteratorItem<I::Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let value = self.iter.next()?;
+ let is_first = mem::replace(&mut self.is_first, false);
+ let is_last = self.iter.peek().is_none();
+ Some(IteratorItem { value, is_first, is_last })
+ }
+}
+
+impl<T> Deref for IteratorItem<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
new file mode 100644
index 0000000..6435f1b
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -0,0 +1,587 @@
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT};
+
+use rustc_ast::ptr::P;
+use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::{self as ast, BlockCheckMode};
+
+impl<'a> State<'a> {
+ fn print_else(&mut self, els: Option<&ast::Expr>) {
+ if let Some(_else) = els {
+ match _else.kind {
+ // Another `else if` block.
+ ast::ExprKind::If(ref i, ref then, ref e) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.word(" else if ");
+ self.print_expr_as_cond(i);
+ self.space();
+ self.print_block(then);
+ self.print_else(e.as_deref())
+ }
+ // Final `else` block.
+ ast::ExprKind::Block(ref b, _) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.word(" else ");
+ self.print_block(b)
+ }
+ // Constraints would be great here!
+ _ => {
+ panic!("print_if saw if with weird alternative");
+ }
+ }
+ }
+ }
+
+ 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.space();
+ self.print_block(blk);
+ self.print_else(elseopt)
+ }
+
+ fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
+ self.popen();
+ self.commasep_exprs(Inconsistent, args);
+ self.pclose()
+ }
+
+ fn print_expr_maybe_paren(&mut self, expr: &ast::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 { ... }`.
+ fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+ }
+
+ // Does `expr` need parentheses 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) {}`.
+ pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
+ match expr.kind {
+ ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
+ _ => parser::contains_exterior_struct_lit(expr),
+ }
+ }
+
+ /// Prints `expr` or `(expr)` when `needs_par` holds.
+ pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
+ if needs_par {
+ self.popen();
+ }
+ self.print_expr(expr);
+ if needs_par {
+ self.pclose();
+ }
+ }
+
+ fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
+ self.ibox(INDENT_UNIT);
+ self.word("[");
+ self.commasep_exprs(Inconsistent, exprs);
+ self.word("]");
+ self.end();
+ }
+
+ pub(super) fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
+ self.ibox(INDENT_UNIT);
+ self.word("const");
+ self.print_expr(&expr.value);
+ self.end();
+ }
+
+ fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
+ self.ibox(INDENT_UNIT);
+ self.word("[");
+ self.print_expr(element);
+ self.word_space(";");
+ self.print_expr(&count.value);
+ self.word("]");
+ self.end();
+ }
+
+ fn print_expr_struct(
+ &mut self,
+ qself: &Option<ast::QSelf>,
+ path: &ast::Path,
+ fields: &[ast::ExprField],
+ rest: &ast::StructRest,
+ ) {
+ if let Some(qself) = qself {
+ self.print_qpath(path, qself, true);
+ } else {
+ self.print_path(path, true, 0);
+ }
+ self.nbsp();
+ self.word("{");
+ let has_rest = match rest {
+ ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true,
+ ast::StructRest::None => false,
+ };
+ if fields.is_empty() && !has_rest {
+ self.word("}");
+ return;
+ }
+ self.cbox(0);
+ for field in fields.iter().delimited() {
+ self.maybe_print_comment(field.span.hi());
+ self.print_outer_attributes(&field.attrs);
+ if field.is_first {
+ self.space_if_not_bol();
+ }
+ if !field.is_shorthand {
+ self.print_ident(field.ident);
+ self.word_nbsp(":");
+ }
+ self.print_expr(&field.expr);
+ if !field.is_last || has_rest {
+ self.word_space(",");
+ } else {
+ self.trailing_comma_or_space();
+ }
+ }
+ if has_rest {
+ if fields.is_empty() {
+ self.space();
+ }
+ self.word("..");
+ if let ast::StructRest::Base(expr) = rest {
+ self.print_expr(expr);
+ }
+ self.space();
+ }
+ self.offset(-INDENT_UNIT);
+ self.end();
+ self.word("}");
+ }
+
+ fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
+ self.popen();
+ self.commasep_exprs(Inconsistent, exprs);
+ if exprs.len() == 1 {
+ self.word(",");
+ }
+ self.pclose()
+ }
+
+ fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
+ let prec = match func.kind {
+ ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
+ _ => parser::PREC_POSTFIX,
+ };
+
+ self.print_expr_maybe_paren(func, prec);
+ self.print_call_post(args)
+ }
+
+ fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
+ let base_args = &args[1..];
+ self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+ self.word(".");
+ self.print_ident(segment.ident);
+ if let Some(ref args) = segment.args {
+ self.print_generic_args(args, true);
+ }
+ self.print_call_post(base_args)
+ }
+
+ fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
+ let assoc_op = AssocOp::from_ast_binop(op.node);
+ let prec = assoc_op.precedence() as i8;
+ let fixity = assoc_op.fixity();
+
+ let (left_prec, right_prec) = match fixity {
+ Fixity::Left => (prec, prec + 1),
+ Fixity::Right => (prec + 1, prec),
+ Fixity::None => (prec + 1, prec + 1),
+ };
+
+ let left_prec = match (&lhs.kind, op.node) {
+ // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+ // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+ // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+ (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
+ parser::PREC_FORCE_PAREN
+ }
+ // We are given `(let _ = a) OP b`.
+ //
+ // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
+ // as the parser will interpret this as `(let _ = a) OP b`.
+ //
+ // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
+ // parens are required since the parser would interpret `let a = b < c` as
+ // `let a = (b < c)`. To achieve this, we force parens.
+ (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+ parser::PREC_FORCE_PAREN
+ }
+ _ => left_prec,
+ };
+
+ self.print_expr_maybe_paren(lhs, left_prec);
+ self.space();
+ self.word_space(op.node.to_string());
+ self.print_expr_maybe_paren(rhs, right_prec)
+ }
+
+ fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
+ self.word(ast::UnOp::to_string(op));
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+ }
+
+ fn print_expr_addr_of(
+ &mut self,
+ kind: ast::BorrowKind,
+ mutability: ast::Mutability,
+ expr: &ast::Expr,
+ ) {
+ self.word("&");
+ match kind {
+ ast::BorrowKind::Ref => self.print_mutability(mutability, false),
+ ast::BorrowKind::Raw => {
+ self.word_nbsp("raw");
+ self.print_mutability(mutability, true);
+ }
+ }
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+ }
+
+ pub fn print_expr(&mut self, expr: &ast::Expr) {
+ self.print_expr_outer_attr_style(expr, true)
+ }
+
+ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
+ self.maybe_print_comment(expr.span.lo());
+
+ let attrs = &expr.attrs;
+ if is_inline {
+ self.print_outer_attributes_inline(attrs);
+ } else {
+ self.print_outer_attributes(attrs);
+ }
+
+ self.ibox(INDENT_UNIT);
+ self.ann.pre(self, AnnNode::Expr(expr));
+ match expr.kind {
+ ast::ExprKind::Box(ref expr) => {
+ self.word_space("box");
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
+ }
+ ast::ExprKind::Array(ref exprs) => {
+ self.print_expr_vec(exprs);
+ }
+ ast::ExprKind::ConstBlock(ref anon_const) => {
+ self.print_expr_anon_const(anon_const);
+ }
+ ast::ExprKind::Repeat(ref element, ref count) => {
+ self.print_expr_repeat(element, count);
+ }
+ ast::ExprKind::Struct(ref se) => {
+ self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
+ }
+ ast::ExprKind::Tup(ref exprs) => {
+ self.print_expr_tup(exprs);
+ }
+ ast::ExprKind::Call(ref func, ref args) => {
+ self.print_expr_call(func, &args);
+ }
+ ast::ExprKind::MethodCall(ref segment, ref args, _) => {
+ self.print_expr_method_call(segment, &args);
+ }
+ ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
+ self.print_expr_binary(op, lhs, rhs);
+ }
+ ast::ExprKind::Unary(op, ref expr) => {
+ self.print_expr_unary(op, expr);
+ }
+ ast::ExprKind::AddrOf(k, m, ref expr) => {
+ self.print_expr_addr_of(k, m, expr);
+ }
+ ast::ExprKind::Lit(ref lit) => {
+ self.print_literal(lit);
+ }
+ ast::ExprKind::Cast(ref expr, ref ty) => {
+ let prec = AssocOp::As.precedence() as i8;
+ self.print_expr_maybe_paren(expr, prec);
+ self.space();
+ self.word_space("as");
+ self.print_type(ty);
+ }
+ ast::ExprKind::Type(ref expr, ref ty) => {
+ let prec = AssocOp::Colon.precedence() as i8;
+ self.print_expr_maybe_paren(expr, prec);
+ self.word_space(":");
+ self.print_type(ty);
+ }
+ ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
+ self.print_let(pat, scrutinee);
+ }
+ ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
+ self.print_if(test, blk, elseopt.as_deref())
+ }
+ ast::ExprKind::While(ref test, ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ self.cbox(0);
+ self.ibox(0);
+ self.word_nbsp("while");
+ self.print_expr_as_cond(test);
+ self.space();
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ self.cbox(0);
+ self.ibox(0);
+ self.word_nbsp("for");
+ self.print_pat(pat);
+ self.space();
+ self.word_space("in");
+ self.print_expr_as_cond(iter);
+ self.space();
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Loop(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ self.cbox(0);
+ self.ibox(0);
+ self.word_nbsp("loop");
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Match(ref expr, ref arms) => {
+ self.cbox(0);
+ self.ibox(0);
+ self.word_nbsp("match");
+ self.print_expr_as_cond(expr);
+ self.space();
+ self.bopen();
+ self.print_inner_attributes_no_trailing_hardbreak(attrs);
+ for arm in arms {
+ self.print_arm(arm);
+ }
+ let empty = attrs.is_empty() && arms.is_empty();
+ self.bclose(expr.span, empty);
+ }
+ ast::ExprKind::Closure(
+ capture_clause,
+ asyncness,
+ movability,
+ ref decl,
+ ref body,
+ _,
+ ) => {
+ self.print_movability(movability);
+ self.print_asyncness(asyncness);
+ self.print_capture_clause(capture_clause);
+
+ self.print_fn_params_and_ret(decl, true);
+ self.space();
+ self.print_expr(body);
+ self.end(); // need to close a box
+
+ // a box will be closed by print_expr, but we didn't want an overall
+ // wrapper so we closed the corresponding opening. so create an
+ // empty box to satisfy the close.
+ self.ibox(0);
+ }
+ ast::ExprKind::Block(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+ // containing cbox, will be closed by print-block at }
+ self.cbox(0);
+ // head-box, will be closed by print-block after {
+ self.ibox(0);
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Async(capture_clause, _, ref blk) => {
+ self.word_nbsp("async");
+ self.print_capture_clause(capture_clause);
+ // cbox/ibox in analogy to the `ExprKind::Block` arm above
+ self.cbox(0);
+ self.ibox(0);
+ self.print_block_with_attrs(blk, attrs);
+ }
+ ast::ExprKind::Await(ref expr) => {
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.word(".await");
+ }
+ ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
+ let prec = AssocOp::Assign.precedence() as i8;
+ self.print_expr_maybe_paren(lhs, prec + 1);
+ self.space();
+ self.word_space("=");
+ self.print_expr_maybe_paren(rhs, prec);
+ }
+ ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+ let prec = AssocOp::Assign.precedence() as i8;
+ self.print_expr_maybe_paren(lhs, prec + 1);
+ self.space();
+ self.word(op.node.to_string());
+ self.word_space("=");
+ self.print_expr_maybe_paren(rhs, prec);
+ }
+ ast::ExprKind::Field(ref expr, ident) => {
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.word(".");
+ self.print_ident(ident);
+ }
+ ast::ExprKind::Index(ref expr, ref index) => {
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.word("[");
+ self.print_expr(index);
+ self.word("]");
+ }
+ ast::ExprKind::Range(ref start, ref end, limits) => {
+ // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
+ // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
+ // Here we use a fake precedence value so that any child with lower precedence than
+ // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
+ let fake_prec = AssocOp::LOr.precedence() as i8;
+ if let Some(ref e) = *start {
+ self.print_expr_maybe_paren(e, fake_prec);
+ }
+ if limits == ast::RangeLimits::HalfOpen {
+ self.word("..");
+ } else {
+ self.word("..=");
+ }
+ if let Some(ref e) = *end {
+ self.print_expr_maybe_paren(e, fake_prec);
+ }
+ }
+ ast::ExprKind::Underscore => self.word("_"),
+ ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
+ ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
+ ast::ExprKind::Break(opt_label, ref opt_expr) => {
+ self.word("break");
+ if let Some(label) = opt_label {
+ self.space();
+ self.print_ident(label.ident);
+ }
+ if let Some(ref expr) = *opt_expr {
+ self.space();
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ }
+ }
+ ast::ExprKind::Continue(opt_label) => {
+ self.word("continue");
+ if let Some(label) = opt_label {
+ self.space();
+ self.print_ident(label.ident);
+ }
+ }
+ ast::ExprKind::Ret(ref result) => {
+ self.word("return");
+ if let Some(ref expr) = *result {
+ self.word(" ");
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ }
+ }
+ ast::ExprKind::InlineAsm(ref a) => {
+ self.word("asm!");
+ self.print_inline_asm(a);
+ }
+ ast::ExprKind::MacCall(ref m) => self.print_mac(m),
+ ast::ExprKind::Paren(ref e) => {
+ self.popen();
+ self.print_expr(e);
+ self.pclose();
+ }
+ ast::ExprKind::Yield(ref e) => {
+ self.word("yield");
+
+ if let Some(ref expr) = *e {
+ self.space();
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ }
+ }
+ ast::ExprKind::Try(ref e) => {
+ self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
+ self.word("?")
+ }
+ ast::ExprKind::TryBlock(ref blk) => {
+ self.cbox(0);
+ self.ibox(0);
+ self.word_nbsp("try");
+ self.print_block_with_attrs(blk, attrs)
+ }
+ ast::ExprKind::Err => {
+ self.popen();
+ self.word("/*ERROR*/");
+ self.pclose()
+ }
+ }
+ self.ann.post(self, AnnNode::Expr(expr));
+ self.end();
+ }
+
+ fn print_arm(&mut self, arm: &ast::Arm) {
+ // Note, I have no idea why this check is necessary, but here it is.
+ if arm.attrs.is_empty() {
+ self.space();
+ }
+ self.cbox(INDENT_UNIT);
+ self.ibox(0);
+ self.maybe_print_comment(arm.pat.span.lo());
+ self.print_outer_attributes(&arm.attrs);
+ self.print_pat(&arm.pat);
+ self.space();
+ if let Some(ref e) = arm.guard {
+ self.word_space("if");
+ self.print_expr(e);
+ self.space();
+ }
+ self.word_space("=>");
+
+ match arm.body.kind {
+ ast::ExprKind::Block(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
+
+ // The block will close the pattern's ibox.
+ self.print_block_unclosed_indent(blk);
+
+ // If it is a user-provided unsafe block, print a comma after it.
+ if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+ self.word(",");
+ }
+ }
+ _ => {
+ self.end(); // Close the ibox for the pattern.
+ self.print_expr(&arm.body);
+ self.word(",");
+ }
+ }
+ self.end(); // Close enclosing cbox.
+ }
+
+ fn print_movability(&mut self, movability: ast::Movability) {
+ match movability {
+ ast::Movability::Static => self.word_space("static"),
+ ast::Movability::Movable => {}
+ }
+ }
+
+ fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
+ match capture_clause {
+ ast::CaptureBy::Value => self.word_space("move"),
+ ast::CaptureBy::Ref => {}
+ }
+ }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
new file mode 100644
index 0000000..d7e9ef0
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -0,0 +1,664 @@
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::delimited::IterDelimited;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+
+use rustc_ast as ast;
+use rustc_ast::GenericBound;
+use rustc_ast::ModKind;
+use rustc_span::symbol::Ident;
+
+fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+ format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
+}
+
+impl<'a> State<'a> {
+ fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
+ self.print_inner_attributes(attrs);
+ for item in &nmod.items {
+ self.print_foreign_item(item);
+ }
+ }
+
+ fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+ let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+ self.ann.pre(self, AnnNode::SubItem(id));
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(span.lo());
+ self.print_outer_attributes(attrs);
+ match kind {
+ ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+ self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+ }
+ ast::ForeignItemKind::Static(ty, mutbl, body) => {
+ let def = ast::Defaultness::Final;
+ self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
+ }
+ ast::ForeignItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ generics,
+ bounds,
+ ty,
+ }) => {
+ self.print_associated_type(
+ ident,
+ generics,
+ bounds,
+ ty.as_deref(),
+ vis,
+ *defaultness,
+ );
+ }
+ ast::ForeignItemKind::MacCall(m) => {
+ self.print_mac(m);
+ if m.args.need_semicolon() {
+ self.word(";");
+ }
+ }
+ }
+ self.ann.post(self, AnnNode::SubItem(id))
+ }
+
+ fn print_item_const(
+ &mut self,
+ ident: Ident,
+ mutbl: Option<ast::Mutability>,
+ ty: &ast::Ty,
+ body: Option<&ast::Expr>,
+ vis: &ast::Visibility,
+ defaultness: ast::Defaultness,
+ ) {
+ self.head("");
+ self.print_visibility(vis);
+ self.print_defaultness(defaultness);
+ let leading = match mutbl {
+ None => "const",
+ Some(ast::Mutability::Not) => "static",
+ Some(ast::Mutability::Mut) => "static mut",
+ };
+ self.word_space(leading);
+ self.print_ident(ident);
+ self.word_space(":");
+ self.print_type(ty);
+ if body.is_some() {
+ self.space();
+ }
+ self.end(); // end the head-ibox
+ if let Some(body) = body {
+ self.word_space("=");
+ self.print_expr(body);
+ }
+ self.word(";");
+ self.end(); // end the outer cbox
+ }
+
+ fn print_associated_type(
+ &mut self,
+ ident: Ident,
+ generics: &ast::Generics,
+ bounds: &ast::GenericBounds,
+ ty: Option<&ast::Ty>,
+ vis: &ast::Visibility,
+ defaultness: ast::Defaultness,
+ ) {
+ self.head("");
+ self.print_visibility(vis);
+ self.print_defaultness(defaultness);
+ self.word_space("type");
+ self.print_ident(ident);
+ self.print_generic_params(&generics.params);
+ self.print_type_bounds(":", bounds);
+ self.print_where_clause(&generics.where_clause);
+ if let Some(ty) = ty {
+ self.space();
+ self.word_space("=");
+ self.print_type(ty);
+ }
+ self.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+
+ /// Pretty-prints an item.
+ crate fn print_item(&mut self, item: &ast::Item) {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(item.span.lo());
+ self.print_outer_attributes(&item.attrs);
+ self.ann.pre(self, AnnNode::Item(item));
+ match item.kind {
+ ast::ItemKind::ExternCrate(orig_name) => {
+ self.head(visibility_qualified(&item.vis, "extern crate"));
+ if let Some(orig_name) = orig_name {
+ self.print_name(orig_name);
+ self.space();
+ self.word("as");
+ self.space();
+ }
+ self.print_ident(item.ident);
+ self.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+ ast::ItemKind::Use(ref tree) => {
+ self.print_visibility(&item.vis);
+ self.word_nbsp("use");
+ self.print_use_tree(tree);
+ self.word(";");
+ }
+ ast::ItemKind::Static(ref ty, mutbl, ref body) => {
+ let def = ast::Defaultness::Final;
+ self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
+ }
+ ast::ItemKind::Const(def, ref ty, ref body) => {
+ self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
+ }
+ ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
+ let body = body.as_deref();
+ self.print_fn_full(
+ sig,
+ item.ident,
+ generics,
+ &item.vis,
+ defaultness,
+ body,
+ &item.attrs,
+ );
+ }
+ ast::ItemKind::Mod(unsafety, ref mod_kind) => {
+ self.head(Self::to_string(|s| {
+ s.print_visibility(&item.vis);
+ s.print_unsafety(unsafety);
+ s.word("mod");
+ }));
+ self.print_ident(item.ident);
+
+ match mod_kind {
+ ModKind::Loaded(items, ..) => {
+ self.nbsp();
+ self.bopen();
+ self.print_inner_attributes(&item.attrs);
+ for item in items {
+ self.print_item(item);
+ }
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
+ }
+ ModKind::Unloaded => {
+ self.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+ }
+ }
+ ast::ItemKind::ForeignMod(ref nmod) => {
+ self.head(Self::to_string(|s| {
+ s.print_unsafety(nmod.unsafety);
+ s.word("extern");
+ }));
+ if let Some(abi) = nmod.abi {
+ self.print_literal(&abi.as_lit());
+ self.nbsp();
+ }
+ self.bopen();
+ self.print_foreign_mod(nmod, &item.attrs);
+ let empty = item.attrs.is_empty() && nmod.items.is_empty();
+ self.bclose(item.span, empty);
+ }
+ ast::ItemKind::GlobalAsm(ref asm) => {
+ self.head(visibility_qualified(&item.vis, "global_asm!"));
+ self.print_inline_asm(asm);
+ self.end();
+ }
+ ast::ItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ ref generics,
+ ref bounds,
+ ref ty,
+ }) => {
+ let ty = ty.as_deref();
+ self.print_associated_type(
+ item.ident,
+ generics,
+ bounds,
+ ty,
+ &item.vis,
+ defaultness,
+ );
+ }
+ ast::ItemKind::Enum(ref enum_definition, ref params) => {
+ self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
+ }
+ ast::ItemKind::Struct(ref struct_def, ref generics) => {
+ self.head(visibility_qualified(&item.vis, "struct"));
+ self.print_struct(struct_def, generics, item.ident, item.span, true);
+ }
+ ast::ItemKind::Union(ref struct_def, ref generics) => {
+ self.head(visibility_qualified(&item.vis, "union"));
+ self.print_struct(struct_def, generics, item.ident, item.span, true);
+ }
+ ast::ItemKind::Impl(box ast::Impl {
+ unsafety,
+ polarity,
+ defaultness,
+ constness,
+ ref generics,
+ ref of_trait,
+ ref self_ty,
+ ref items,
+ }) => {
+ self.head("");
+ self.print_visibility(&item.vis);
+ self.print_defaultness(defaultness);
+ self.print_unsafety(unsafety);
+ self.word("impl");
+
+ if generics.params.is_empty() {
+ self.nbsp();
+ } else {
+ self.print_generic_params(&generics.params);
+ self.space();
+ }
+
+ self.print_constness(constness);
+
+ if let ast::ImplPolarity::Negative(_) = polarity {
+ self.word("!");
+ }
+
+ if let Some(ref t) = *of_trait {
+ self.print_trait_ref(t);
+ self.space();
+ self.word_space("for");
+ }
+
+ self.print_type(self_ty);
+ self.print_where_clause(&generics.where_clause);
+
+ self.space();
+ self.bopen();
+ self.print_inner_attributes(&item.attrs);
+ for impl_item in items {
+ self.print_assoc_item(impl_item);
+ }
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
+ }
+ ast::ItemKind::Trait(box ast::Trait {
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref items,
+ ..
+ }) => {
+ self.head("");
+ self.print_visibility(&item.vis);
+ self.print_unsafety(unsafety);
+ self.print_is_auto(is_auto);
+ self.word_nbsp("trait");
+ self.print_ident(item.ident);
+ self.print_generic_params(&generics.params);
+ let mut real_bounds = Vec::with_capacity(bounds.len());
+ for b in bounds.iter() {
+ if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+ self.space();
+ self.word_space("for ?");
+ self.print_trait_ref(&ptr.trait_ref);
+ } else {
+ real_bounds.push(b.clone());
+ }
+ }
+ self.print_type_bounds(":", &real_bounds);
+ self.print_where_clause(&generics.where_clause);
+ self.word(" ");
+ self.bopen();
+ self.print_inner_attributes(&item.attrs);
+ for trait_item in items {
+ self.print_assoc_item(trait_item);
+ }
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
+ }
+ ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+ self.head(visibility_qualified(&item.vis, "trait"));
+ self.print_ident(item.ident);
+ self.print_generic_params(&generics.params);
+ let mut real_bounds = Vec::with_capacity(bounds.len());
+ // FIXME(durka) this seems to be some quite outdated syntax
+ for b in bounds.iter() {
+ if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+ self.space();
+ self.word_space("for ?");
+ self.print_trait_ref(&ptr.trait_ref);
+ } else {
+ real_bounds.push(b.clone());
+ }
+ }
+ self.nbsp();
+ self.print_type_bounds("=", &real_bounds);
+ self.print_where_clause(&generics.where_clause);
+ self.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
+ }
+ ast::ItemKind::MacCall(ref mac) => {
+ self.print_mac(mac);
+ if mac.args.need_semicolon() {
+ self.word(";");
+ }
+ }
+ ast::ItemKind::MacroDef(ref macro_def) => {
+ self.print_mac_def(macro_def, &item.ident, item.span, |state| {
+ state.print_visibility(&item.vis)
+ });
+ }
+ }
+ self.ann.post(self, AnnNode::Item(item))
+ }
+
+ fn print_enum_def(
+ &mut self,
+ enum_definition: &ast::EnumDef,
+ generics: &ast::Generics,
+ ident: Ident,
+ span: rustc_span::Span,
+ visibility: &ast::Visibility,
+ ) {
+ self.head(visibility_qualified(visibility, "enum"));
+ self.print_ident(ident);
+ self.print_generic_params(&generics.params);
+ self.print_where_clause(&generics.where_clause);
+ self.space();
+ self.print_variants(&enum_definition.variants, span)
+ }
+
+ fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
+ self.bopen();
+ for v in variants {
+ self.space_if_not_bol();
+ self.maybe_print_comment(v.span.lo());
+ self.print_outer_attributes(&v.attrs);
+ self.ibox(0);
+ self.print_variant(v);
+ self.word(",");
+ self.end();
+ self.maybe_print_trailing_comment(v.span, None);
+ }
+ let empty = variants.is_empty();
+ self.bclose(span, empty)
+ }
+
+ crate fn print_visibility(&mut self, vis: &ast::Visibility) {
+ match vis.kind {
+ ast::VisibilityKind::Public => self.word_nbsp("pub"),
+ ast::VisibilityKind::Crate(sugar) => match sugar {
+ ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
+ ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
+ },
+ ast::VisibilityKind::Restricted { ref path, .. } => {
+ let path = Self::to_string(|s| s.print_path(path, false, 0));
+ if path == "self" || path == "super" {
+ self.word_nbsp(format!("pub({})", path))
+ } else {
+ self.word_nbsp(format!("pub(in {})", path))
+ }
+ }
+ ast::VisibilityKind::Inherited => {}
+ }
+ }
+
+ fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
+ if let ast::Defaultness::Default(_) = defaultness {
+ self.word_nbsp("default");
+ }
+ }
+
+ fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
+ self.nbsp();
+ self.bopen();
+
+ let empty = fields.is_empty();
+ if !empty {
+ self.hardbreak_if_not_bol();
+
+ for field in fields {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(field.span.lo());
+ self.print_outer_attributes(&field.attrs);
+ self.print_visibility(&field.vis);
+ self.print_ident(field.ident.unwrap());
+ self.word_nbsp(":");
+ self.print_type(&field.ty);
+ self.word(",");
+ }
+ }
+
+ self.bclose(span, empty);
+ }
+
+ fn print_struct(
+ &mut self,
+ struct_def: &ast::VariantData,
+ generics: &ast::Generics,
+ ident: Ident,
+ span: rustc_span::Span,
+ print_finalizer: bool,
+ ) {
+ self.print_ident(ident);
+ self.print_generic_params(&generics.params);
+ match struct_def {
+ ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+ if let ast::VariantData::Tuple(..) = struct_def {
+ self.popen();
+ self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+ s.maybe_print_comment(field.span.lo());
+ s.print_outer_attributes(&field.attrs);
+ s.print_visibility(&field.vis);
+ s.print_type(&field.ty)
+ });
+ self.pclose();
+ }
+ self.print_where_clause(&generics.where_clause);
+ if print_finalizer {
+ self.word(";");
+ }
+ self.end();
+ self.end(); // Close the outer-box.
+ }
+ ast::VariantData::Struct(ref fields, ..) => {
+ self.print_where_clause(&generics.where_clause);
+ self.print_record_struct_body(fields, span);
+ }
+ }
+ }
+
+ crate fn print_variant(&mut self, v: &ast::Variant) {
+ self.head("");
+ self.print_visibility(&v.vis);
+ let generics = ast::Generics::default();
+ self.print_struct(&v.data, &generics, v.ident, v.span, false);
+ if let Some(ref d) = v.disr_expr {
+ self.space();
+ self.word_space("=");
+ self.print_expr(&d.value)
+ }
+ }
+
+ fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+ let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+ self.ann.pre(self, AnnNode::SubItem(id));
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(span.lo());
+ self.print_outer_attributes(attrs);
+ match kind {
+ ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+ self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+ }
+ ast::AssocItemKind::Const(def, ty, body) => {
+ self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
+ }
+ ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+ self.print_associated_type(
+ ident,
+ generics,
+ bounds,
+ ty.as_deref(),
+ vis,
+ *defaultness,
+ );
+ }
+ ast::AssocItemKind::MacCall(m) => {
+ self.print_mac(m);
+ if m.args.need_semicolon() {
+ self.word(";");
+ }
+ }
+ }
+ self.ann.post(self, AnnNode::SubItem(id))
+ }
+
+ fn print_fn_full(
+ &mut self,
+ sig: &ast::FnSig,
+ name: Ident,
+ generics: &ast::Generics,
+ vis: &ast::Visibility,
+ defaultness: ast::Defaultness,
+ body: Option<&ast::Block>,
+ attrs: &[ast::Attribute],
+ ) {
+ if body.is_some() {
+ self.head("");
+ }
+ self.print_visibility(vis);
+ self.print_defaultness(defaultness);
+ self.print_fn(&sig.decl, sig.header, Some(name), generics);
+ if let Some(body) = body {
+ self.nbsp();
+ self.print_block_with_attrs(body, attrs);
+ } else {
+ self.word(";");
+ }
+ }
+
+ crate fn print_fn(
+ &mut self,
+ decl: &ast::FnDecl,
+ header: ast::FnHeader,
+ name: Option<Ident>,
+ generics: &ast::Generics,
+ ) {
+ self.print_fn_header_info(header);
+ if let Some(name) = name {
+ self.nbsp();
+ self.print_ident(name);
+ }
+ self.print_generic_params(&generics.params);
+ self.print_fn_params_and_ret(decl, false);
+ self.print_where_clause(&generics.where_clause)
+ }
+
+ crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+ let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+ self.word(open);
+ self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+ self.word(close);
+ self.print_fn_ret_ty(&decl.output)
+ }
+
+ fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
+ if where_clause.predicates.is_empty() && !where_clause.has_where_token {
+ return;
+ }
+
+ self.space();
+ self.word_space("where");
+
+ for (i, predicate) in where_clause.predicates.iter().enumerate() {
+ if i != 0 {
+ self.word_space(",");
+ }
+
+ self.print_where_predicate(predicate);
+ }
+ }
+
+ pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
+ match predicate {
+ ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+ bound_generic_params,
+ bounded_ty,
+ bounds,
+ ..
+ }) => {
+ self.print_formal_generic_params(bound_generic_params);
+ self.print_type(bounded_ty);
+ self.print_type_bounds(":", bounds);
+ }
+ ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+ lifetime,
+ bounds,
+ ..
+ }) => {
+ self.print_lifetime_bounds(*lifetime, bounds);
+ }
+ ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+ self.print_type(lhs_ty);
+ self.space();
+ self.word_space("=");
+ self.print_type(rhs_ty);
+ }
+ }
+ }
+
+ fn print_use_tree(&mut self, tree: &ast::UseTree) {
+ match tree.kind {
+ ast::UseTreeKind::Simple(rename, ..) => {
+ self.print_path(&tree.prefix, false, 0);
+ if let Some(rename) = rename {
+ self.nbsp();
+ self.word_nbsp("as");
+ self.print_ident(rename);
+ }
+ }
+ ast::UseTreeKind::Glob => {
+ if !tree.prefix.segments.is_empty() {
+ self.print_path(&tree.prefix, false, 0);
+ self.word("::");
+ }
+ self.word("*");
+ }
+ ast::UseTreeKind::Nested(ref items) => {
+ if !tree.prefix.segments.is_empty() {
+ self.print_path(&tree.prefix, false, 0);
+ self.word("::");
+ }
+ if items.is_empty() {
+ self.word("{}");
+ } else if items.len() == 1 {
+ self.print_use_tree(&items[0].0);
+ } else {
+ self.cbox(INDENT_UNIT);
+ self.word("{");
+ self.zerobreak();
+ self.ibox(0);
+ for use_tree in items.iter().delimited() {
+ self.print_use_tree(&use_tree.0);
+ if !use_tree.is_last {
+ self.word(",");
+ if let ast::UseTreeKind::Nested(_) = use_tree.0.kind {
+ self.hardbreak();
+ } else {
+ self.space();
+ }
+ }
+ }
+ self.end();
+ self.trailing_comma();
+ self.offset(-INDENT_UNIT);
+ self.word("}");
+ self.end();
+ }
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index bab50df..49043e9 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -1,10 +1,13 @@
//! Parsing and validation of builtin attributes
-use rustc_ast::{self as ast, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
+use rustc_ast as ast;
+use rustc_ast::node_id::CRATE_NODE_ID;
+use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability};
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic;
+use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Session;
use rustc_span::hygiene::Transparency;
@@ -217,85 +220,81 @@
let mut issue_num = None;
let mut is_soft = false;
for meta in metas {
- if let Some(mi) = meta.meta_item() {
- match mi.name_or_empty() {
- sym::feature => {
- if !get(mi, &mut feature) {
- continue 'outer;
- }
- }
- sym::reason => {
- if !get(mi, &mut reason) {
- continue 'outer;
- }
- }
- sym::issue => {
- if !get(mi, &mut issue) {
- continue 'outer;
- }
-
- // These unwraps are safe because `get` ensures the meta item
- // is a name/value pair string literal.
- issue_num = match issue.unwrap().as_str() {
- "none" => None,
- issue => {
- let emit_diag = |msg: &str| {
- struct_span_err!(
- diagnostic,
- mi.span,
- E0545,
- "`issue` must be a non-zero numeric string \
- or \"none\"",
- )
- .span_label(
- mi.name_value_literal_span().unwrap(),
- msg,
- )
- .emit();
- };
- match issue.parse() {
- Ok(0) => {
- emit_diag(
- "`issue` must not be \"0\", \
- use \"none\" instead",
- );
- continue 'outer;
- }
- Ok(num) => NonZeroU32::new(num),
- Err(err) => {
- emit_diag(&err.to_string());
- continue 'outer;
- }
- }
- }
- };
- }
- sym::soft => {
- if !mi.is_word() {
- let msg = "`soft` should not have any arguments";
- sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
- }
- is_soft = true;
- }
- _ => {
- handle_errors(
- &sess.parse_sess,
- meta.span(),
- AttrError::UnknownMetaItem(
- pprust::path_to_string(&mi.path),
- &["feature", "reason", "issue", "soft"],
- ),
- );
- continue 'outer;
- }
- }
- } else {
+ let Some(mi) = meta.meta_item() else {
handle_errors(
&sess.parse_sess,
meta.span(),
AttrError::UnsupportedLiteral("unsupported literal", false),
);
continue 'outer;
+ };
+ match mi.name_or_empty() {
+ sym::feature => {
+ if !get(mi, &mut feature) {
+ continue 'outer;
+ }
+ }
+ sym::reason => {
+ if !get(mi, &mut reason) {
+ continue 'outer;
+ }
+ }
+ sym::issue => {
+ if !get(mi, &mut issue) {
+ continue 'outer;
+ }
+
+ // These unwraps are safe because `get` ensures the meta item
+ // is a name/value pair string literal.
+ issue_num = match issue.unwrap().as_str() {
+ "none" => None,
+ issue => {
+ let emit_diag = |msg: &str| {
+ struct_span_err!(
+ diagnostic,
+ mi.span,
+ E0545,
+ "`issue` must be a non-zero numeric string \
+ or \"none\"",
+ )
+ .span_label(mi.name_value_literal_span().unwrap(), msg)
+ .emit();
+ };
+ match issue.parse() {
+ Ok(0) => {
+ emit_diag(
+ "`issue` must not be \"0\", \
+ use \"none\" instead",
+ );
+ continue 'outer;
+ }
+ Ok(num) => NonZeroU32::new(num),
+ Err(err) => {
+ emit_diag(&err.to_string());
+ continue 'outer;
+ }
+ }
+ }
+ };
+ }
+ sym::soft => {
+ if !mi.is_word() {
+ let msg = "`soft` should not have any arguments";
+ sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
+ }
+ is_soft = true;
+ }
+ _ => {
+ handle_errors(
+ &sess.parse_sess,
+ meta.span(),
+ AttrError::UnknownMetaItem(
+ pprust::path_to_string(&mi.path),
+ &["feature", "reason", "issue", "soft"],
+ ),
+ );
+ continue 'outer;
+ }
}
}
@@ -462,8 +461,30 @@
true
}
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
- let ident = cfg.ident().expect("multi-segment cfg predicate");
- sess.config.contains(&(ident.name, cfg.value_str()))
+ let name = cfg.ident().expect("multi-segment cfg predicate").name;
+ let value = cfg.value_str();
+ if sess.check_config.names_checked && !sess.check_config.names_valid.contains(&name)
+ {
+ sess.buffer_lint(
+ UNEXPECTED_CFGS,
+ cfg.span,
+ CRATE_NODE_ID,
+ "unexpected `cfg` condition name",
+ );
+ }
+ if let Some(val) = value {
+ if sess.check_config.values_checked.contains(&name)
+ && !sess.check_config.values_valid.contains(&(name, val))
+ {
+ sess.buffer_lint(
+ UNEXPECTED_CFGS,
+ cfg.span,
+ CRATE_NODE_ID,
+ "unexpected `cfg` condition value",
+ );
+ }
+ }
+ sess.config.contains(&(name, value))
}
}
})
@@ -608,7 +629,7 @@
}
}
-#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic)]
+#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
pub struct Deprecation {
pub since: Option<Symbol>,
/// The note to issue a reason.
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index 3fb11f7..c95c1c4 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -4,6 +4,8 @@
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
//! to this crate.
+#![feature(let_else)]
+
#[macro_use]
extern crate rustc_macros;
diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml
index 75e9c69..eb2fdbd 100644
--- a/compiler/rustc_borrowck/Cargo.toml
+++ b/compiler/rustc_borrowck/Cargo.toml
@@ -8,7 +8,7 @@
[dependencies]
either = "1.5.0"
-itertools = "0.9"
+itertools = "0.10"
tracing = "0.1"
polonius-engine = "0.13.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 5702203..7140cda 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -327,7 +327,7 @@
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
- ) -> DiagnosticBuilder<'cx> {
+ ) -> DiagnosticBuilder<'tcx> {
let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default();
struct_span_err!(
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index a40f148..22edee3 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -60,8 +60,8 @@
/// We sometimes have `region` within an rvalue, or within a
/// call. Make them live at the location where they appear.
- fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) {
- self.add_regular_live_constraint(*region, location);
+ fn visit_region(&mut self, region: ty::Region<'tcx>, location: Location) {
+ self.add_regular_live_constraint(region, location);
self.super_region(region);
}
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 98378a9..d41143e 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -72,7 +72,7 @@
}
}
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, PartialEq, Eq)]
pub struct OutlivesConstraint<'tcx> {
// NB. The ordering here is not significant for correctness, but
// it is for convenience. Before we dump the constraints in the
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 15372ec..f0036f0 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -8,7 +8,6 @@
use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
use rustc_mir_dataflow::{Analysis, Direction, Results};
use std::fmt;
-use std::iter;
use crate::{
places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
@@ -385,14 +384,6 @@
self.kill_borrows_on_place(trans, Place::from(local));
}
- mir::StatementKind::LlvmInlineAsm(ref asm) => {
- for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
- if !kind.is_indirect && !kind.is_rw {
- self.kill_borrows_on_place(trans, *output);
- }
- }
- }
-
mir::StatementKind::FakeRead(..)
| mir::StatementKind::SetDiscriminant { .. }
| mir::StatementKind::StorageLive(..)
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 70acbc9..eec994f 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -16,9 +16,6 @@
PlaceContext::MutatingUse(MutatingUseContext::Store) |
- // This is potentially both a def and a use...
- PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
-
// We let Call define the result in both the success and
// unwind cases. This is not really correct, however it
// does not seem to be observable due to the way that we
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 96326ef..2a906e4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -55,7 +55,7 @@
found,
TypeError::RegionsPlaceholderMismatch,
);
- err.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(err);
}
UniverseInfoInner::TypeOp(ref type_op_info) => {
type_op_info.report_error(mbcx, placeholder, error_element, cause);
@@ -64,11 +64,9 @@
// 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(cause.span, "higher-ranked subtype error")
- .buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(
+ mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
+ );
}
}
}
@@ -144,12 +142,10 @@
let tcx = mbcx.infcx.tcx;
let base_universe = self.base_universe();
- let adjusted_universe = if let Some(adjusted) =
+ let Some(adjusted_universe) =
placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
- {
- adjusted
- } else {
- self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
+ else {
+ mbcx.buffer_error(self.fallback_error(tcx, cause.span));
return;
};
@@ -178,9 +174,9 @@
let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
if let Some(nice_error) = nice_error {
- nice_error.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(nice_error);
} else {
- self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(self.fallback_error(tcx, span));
}
}
}
@@ -358,8 +354,8 @@
})?;
debug!(?sub_region, "cause = {:#?}", cause);
- let nice_error = match (error_region, sub_region) {
- (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
+ let nice_error = match (error_region, *sub_region) {
+ (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
infcx,
RegionResolutionError::SubSupConflict(
vid,
@@ -376,7 +372,7 @@
RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
),
// Note universe here is wrong...
- (None, &ty::ReVar(vid)) => NiceRegionError::new(
+ (None, ty::ReVar(vid)) => NiceRegionError::new(
infcx,
RegionResolutionError::UpperBoundUniverseConflict(
vid,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index a24b7cf..fce5ed0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,4 +1,5 @@
use either::Either;
+use rustc_const_eval::util::{CallDesugaringKind, CallKind};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
@@ -26,7 +27,7 @@
use super::{
explain_borrow::{BorrowExplanation, LaterUseKind},
- FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+ IncludingDowncast, RegionName, RegionNameSource, UseSpans,
};
#[derive(Debug)]
@@ -104,9 +105,9 @@
format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
} else {
- if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
+ if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
debug!(
"report_use_of_moved_or_uninitialized place: error suppressed \
@@ -195,7 +196,9 @@
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "value".to_owned());
match kind {
- FnSelfUseKind::FnOnceCall => {
+ CallKind::FnCall { fn_trait_id, .. }
+ if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
+ {
err.span_label(
fn_call_span,
&format!(
@@ -208,7 +211,8 @@
"this value implements `FnOnce`, which causes it to be moved when called",
);
}
- FnSelfUseKind::Operator { self_arg } => {
+ CallKind::Operator { self_arg, .. } => {
+ let self_arg = self_arg.unwrap();
err.span_label(
fn_call_span,
&format!(
@@ -235,12 +239,9 @@
);
}
}
- FnSelfUseKind::Normal {
- self_arg,
- implicit_into_iter,
- is_option_or_result,
- } => {
- if implicit_into_iter {
+ CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+ let self_arg = self_arg.unwrap();
+ if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
err.span_label(
fn_call_span,
&format!(
@@ -305,8 +306,8 @@
);
}
}
- // Deref::deref takes &self, which cannot cause a move
- FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
+ // Other desugarings takes &self, which cannot cause a move
+ _ => unreachable!(),
}
} else {
err.span_label(
@@ -409,8 +410,9 @@
let generics = tcx.generics_of(self.mir_def_id());
let param = generics.type_param(¶m_ty, tcx);
if let Some(generics) = tcx
- .hir()
- .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
+ .typeck_root_def_id(self.mir_def_id().to_def_id())
+ .as_local()
+ .and_then(|def_id| tcx.hir().get_generics(def_id))
{
suggest_constraining_type_param(
tcx,
@@ -432,7 +434,7 @@
}
if let UseSpans::FnSelfUse {
- kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
+ kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
..
} = use_spans
{
@@ -448,12 +450,7 @@
}
}
- if let Some((_, mut old_err)) =
- self.move_error_reported.insert(move_out_indices, (used_place, err))
- {
- // Cancel the old error so it doesn't ICE.
- old_err.cancel();
- }
+ self.buffer_move_error(move_out_indices, (used_place, err));
}
}
@@ -502,7 +499,7 @@
Some(borrow_span),
None,
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
pub(crate) fn report_use_while_mutably_borrowed(
@@ -1020,7 +1017,7 @@
if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
let err =
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
return;
}
@@ -1112,7 +1109,7 @@
),
};
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn report_local_value_does_not_live_long_enough(
@@ -1294,7 +1291,7 @@
None,
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn report_thread_local_value_does_not_live_long_enough(
@@ -1809,7 +1806,7 @@
loan.kind.describe_mutability(),
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
return;
}
@@ -1835,7 +1832,7 @@
self.explain_deref_coercion(loan, &mut err);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
@@ -1937,7 +1934,7 @@
}
}
err.span_label(span, msg);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
@@ -2327,7 +2324,7 @@
// This is also case 2 from above but for functions, return type is still an
// anonymous reference so we select the first argument.
let argument_span = fn_decl.inputs.first()?.span;
- let argument_ty = sig.inputs().skip_binder().first()?;
+ let argument_ty = *sig.inputs().skip_binder().first()?;
let return_span = fn_decl.output.span();
let return_ty = sig.output().skip_binder();
@@ -2382,27 +2379,27 @@
diag: &mut DiagnosticBuilder<'_>,
) -> String {
match self {
- AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
+ &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
diag.span_label(
- *argument_span,
+ argument_span,
format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
);
cx.get_region_name_for_ty(argument_ty, 0)
}
- AnnotatedBorrowFnSignature::AnonymousFunction {
+ &AnnotatedBorrowFnSignature::AnonymousFunction {
argument_ty,
argument_span,
return_ty,
return_span,
} => {
let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
- diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
+ diag.span_label(argument_span, format!("has type `{}`", argument_ty_name));
let return_ty_name = cx.get_name_for_ty(return_ty, 0);
let types_equal = return_ty_name == argument_ty_name;
diag.span_label(
- *return_span,
+ return_span,
format!(
"{}has type `{}`",
if types_equal { "also " } else { "" },
@@ -2422,7 +2419,7 @@
}
AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
// Region of return type and arguments checked to be the same earlier.
- let region_name = cx.get_region_name_for_ty(return_ty, 0);
+ let region_name = cx.get_region_name_for_ty(*return_ty, 0);
for (_, argument_span) in arguments {
diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index e2eb125..73b0d39 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1,10 +1,10 @@
//! Borrow checker diagnostics.
+use rustc_const_eval::util::call_kind;
use rustc_errors::DiagnosticBuilder;
use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItemGroup;
use rustc_hir::GeneratorKind;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
@@ -13,7 +13,7 @@
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
+use rustc_span::{symbol::sym, Span};
use rustc_target::abi::VariantIdx;
use super::borrow_set::BorrowData;
@@ -37,7 +37,7 @@
crate use outlives_suggestion::OutlivesSuggestionBuilder;
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
crate use region_name::{RegionName, RegionNameSource};
-use rustc_span::symbol::Ident;
+crate use rustc_const_eval::util::CallKind;
pub(super) struct IncludingDowncast(pub(super) bool);
@@ -331,7 +331,7 @@
match place {
PlaceRef { local, projection: [] } => {
let local = &self.body.local_decls[local];
- self.describe_field_from_ty(&local.ty, field, None)
+ self.describe_field_from_ty(local.ty, field, None)
}
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
ProjectionElem::Deref => {
@@ -339,10 +339,10 @@
}
ProjectionElem::Downcast(_, variant_index) => {
let base_ty = place.ty(self.body, self.infcx.tcx).ty;
- self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
+ self.describe_field_from_ty(base_ty, field, Some(*variant_index))
}
ProjectionElem::Field(_, field_type) => {
- self.describe_field_from_ty(&field_type, field, None)
+ self.describe_field_from_ty(*field_type, field, None)
}
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
@@ -362,7 +362,7 @@
) -> String {
if ty.is_box() {
// If the type is a box, the field is described from the boxed type
- self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
+ self.describe_field_from_ty(ty.boxed_ty(), field, variant_index)
} else {
match *ty.kind() {
ty::Adt(def, _) => {
@@ -372,14 +372,14 @@
} else {
def.non_enum_variant()
};
- variant.fields[field.index()].ident.to_string()
+ variant.fields[field.index()].name.to_string()
}
ty::Tuple(_) => field.index().to_string(),
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
- self.describe_field_from_ty(&ty, field, variant_index)
+ self.describe_field_from_ty(ty, field, variant_index)
}
ty::Array(ty, _) | ty::Slice(ty) => {
- self.describe_field_from_ty(&ty, field, variant_index)
+ self.describe_field_from_ty(ty, field, variant_index)
}
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
// We won't be borrowck'ing here if the closure came from another crate,
@@ -497,14 +497,14 @@
// We need to add synthesized lifetimes where appropriate. We do
// this by hooking into the pretty printer and telling it to label the
// lifetimes without names with the value `'0`.
- match ty.kind() {
- ty::Ref(
- ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
- | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
- _,
- _,
- ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
- _ => {}
+ if let ty::Ref(region, ..) = ty.kind() {
+ match **region {
+ ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+ | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
+ printer.region_highlight_mode.highlighting_bound_region(br, counter)
+ }
+ _ => {}
+ }
}
let _ = ty.print(printer);
@@ -517,19 +517,17 @@
let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
- let region = match ty.kind() {
- ty::Ref(region, _, _) => {
- match region {
- ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
- | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
- printer.region_highlight_mode.highlighting_bound_region(*br, counter)
- }
- _ => {}
+ let region = if let ty::Ref(region, ..) = ty.kind() {
+ match **region {
+ ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+ | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
+ printer.region_highlight_mode.highlighting_bound_region(br, counter)
}
-
- region
+ _ => {}
}
- _ => bug!("ty for annotation of borrow region is not a reference"),
+ region
+ } else {
+ bug!("ty for annotation of borrow region is not a reference");
};
let _ = region.print(printer);
@@ -563,7 +561,7 @@
fn_call_span: Span,
/// The definition span of the method being called
fn_span: Span,
- kind: FnSelfUseKind<'tcx>,
+ kind: CallKind<'tcx>,
},
/// This access is caused by a `match` or `if let` pattern.
PatUse(Span),
@@ -571,38 +569,15 @@
OtherUse(Span),
}
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum FnSelfUseKind<'tcx> {
- /// A normal method call of the form `receiver.foo(a, b, c)`
- Normal {
- self_arg: Ident,
- implicit_into_iter: bool,
- /// Whether the self type of the method call has an `.as_ref()` method.
- /// Used for better diagnostics.
- is_option_or_result: bool,
- },
- /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
- FnOnceCall,
- /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
- Operator { self_arg: Ident },
- DerefCoercion {
- /// The `Span` of the `Target` associated type
- /// in the `Deref` impl we are using.
- deref_target: Span,
- /// The type `T::Deref` we are dereferencing to
- deref_target_ty: Ty<'tcx>,
- },
-}
-
impl UseSpans<'_> {
pub(super) fn args_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { args_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
- UseSpans::FnSelfUse {
- fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
- } => fn_call_span,
+ UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+ fn_call_span
+ }
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@@ -613,9 +588,9 @@
UseSpans::ClosureUse { path_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
- UseSpans::FnSelfUse {
- fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
- } => fn_call_span,
+ UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+ fn_call_span
+ }
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@@ -626,9 +601,9 @@
UseSpans::ClosureUse { capture_kind_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
- UseSpans::FnSelfUse {
- fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
- } => fn_call_span,
+ UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+ fn_call_span
+ }
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@@ -892,79 +867,30 @@
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
}) = &self.body[location.block].terminator
{
- let (method_did, method_substs) = if let Some(info) =
+ let Some((method_did, method_substs)) =
rustc_const_eval::util::find_self_call(
self.infcx.tcx,
&self.body,
target_temp,
location.block,
- ) {
- info
- } else {
+ )
+ else {
return normal_ret;
};
- let tcx = self.infcx.tcx;
- let parent = tcx.parent(method_did);
- let is_fn_once = parent == tcx.lang_items().fn_once_trait();
- let is_operator = !from_hir_call
- && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
- let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
- let fn_call_span = *fn_span;
-
- let self_arg = tcx.fn_arg_names(method_did)[0];
-
- debug!(
- "terminator = {:?} from_hir_call={:?}",
- self.body[location.block].terminator, from_hir_call
+ let kind = call_kind(
+ self.infcx.tcx,
+ self.param_env,
+ method_did,
+ method_substs,
+ *fn_span,
+ *from_hir_call,
+ Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
);
- // Check for a 'special' use of 'self' -
- // an FnOnce call, an operator (e.g. `<<`), or a
- // deref coercion.
- let kind = if is_fn_once {
- Some(FnSelfUseKind::FnOnceCall)
- } else if is_operator {
- Some(FnSelfUseKind::Operator { self_arg })
- } else if is_deref {
- let deref_target =
- tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
- Instance::resolve(tcx, self.param_env, deref_target, method_substs)
- .transpose()
- });
- if let Some(Ok(instance)) = deref_target {
- let deref_target_ty = instance.ty(tcx, self.param_env);
- Some(FnSelfUseKind::DerefCoercion {
- deref_target: tcx.def_span(instance.def_id()),
- deref_target_ty,
- })
- } else {
- None
- }
- } else {
- None
- };
-
- let kind = kind.unwrap_or_else(|| {
- // This isn't a 'special' use of `self`
- debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
- let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
- && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
- let parent_self_ty = parent
- .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
- .and_then(|did| match tcx.type_of(did).kind() {
- ty::Adt(def, ..) => Some(def.did),
- _ => None,
- });
- let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
- matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
- });
- FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
- });
-
return FnSelfUse {
var_span: stmt.source_info.span,
- fn_call_span,
+ fn_call_span: *fn_span,
fn_span: self
.infcx
.tcx
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 692c20d..cc65668 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -1,3 +1,4 @@
+use rustc_const_eval::util::CallDesugaringKind;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
@@ -8,7 +9,7 @@
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
-use crate::diagnostics::{FnSelfUseKind, UseSpans};
+use crate::diagnostics::{CallKind, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
@@ -245,18 +246,18 @@
);
(
match kind {
- IllegalMoveOriginKind::BorrowedContent { target_place } => self
+ &IllegalMoveOriginKind::BorrowedContent { target_place } => self
.report_cannot_move_from_borrowed_content(
original_path,
- *target_place,
+ target_place,
span,
use_spans,
),
- IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
+ &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
self.cannot_move_out_of_interior_of_drop(span, ty)
}
- IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
- self.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index))
+ &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
+ self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
}
},
span,
@@ -264,7 +265,7 @@
};
self.add_move_hints(error, &mut err, err_span);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn report_cannot_move_from_static(
@@ -410,7 +411,8 @@
Applicability::MaybeIncorrect,
);
} else if let Some(UseSpans::FnSelfUse {
- kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+ kind:
+ CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
..
}) = use_spans
{
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index b5dad5c..7d0dde5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -488,12 +488,32 @@
// don't create labels for compiler-generated spans
Some(_) => None,
None => {
- let (span, suggestion) = suggest_ampmut(
- self.infcx.tcx,
- local_decl,
- opt_assignment_rhs_span,
- *opt_ty_info,
- );
+ let (span, suggestion) = if name != kw::SelfLower {
+ suggest_ampmut(
+ self.infcx.tcx,
+ local_decl,
+ opt_assignment_rhs_span,
+ *opt_ty_info,
+ )
+ } else {
+ match local_decl.local_info.as_deref() {
+ Some(LocalInfo::User(ClearCrossCrate::Set(
+ mir::BindingForm::Var(mir::VarBindingForm {
+ opt_ty_info: None,
+ ..
+ }),
+ ))) => {
+ suggest_ampmut_self(self.infcx.tcx, local_decl)
+ }
+ // explicit self (eg `self: &'a Self`)
+ _ => suggest_ampmut(
+ self.infcx.tcx,
+ local_decl,
+ opt_assignment_rhs_span,
+ *opt_ty_info,
+ ),
+ }
+ };
Some((true, span, suggestion))
}
}
@@ -606,7 +626,7 @@
}
}
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
/// User cannot make signature of a trait mutable without changing the
@@ -619,51 +639,46 @@
let hir_map = self.infcx.tcx.hir();
let my_def = self.body.source.def_id();
let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap());
- let td = if let Some(a) =
+ let Some(td) =
self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
- {
- a
- } else {
+ else {
return (false, None);
};
(
true,
- td.as_local().and_then(|tld| {
- let h = hir_map.local_def_id_to_hir_id(tld);
- match hir_map.find(h) {
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(_, _, _, _, items),
- ..
- })) => {
- let mut f_in_trait_opt = None;
- for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
- let hi = fi.hir_id();
- if !matches!(k, hir::AssocItemKind::Fn { .. }) {
- continue;
- }
- if hir_map.name(hi) != hir_map.name(my_hir) {
- continue;
- }
- f_in_trait_opt = Some(hi);
- break;
+ td.as_local().and_then(|tld| match hir_map.find_by_def_id(tld) {
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(_, _, _, _, items),
+ ..
+ })) => {
+ let mut f_in_trait_opt = None;
+ for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
+ let hi = fi.hir_id();
+ if !matches!(k, hir::AssocItemKind::Fn { .. }) {
+ continue;
}
- f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
- Some(Node::TraitItem(hir::TraitItem {
- kind:
- hir::TraitItemKind::Fn(
- hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
- _,
- ),
- ..
- })) => {
- let hir::Ty { span, .. } = inputs[local.index() - 1];
- Some(span)
- }
- _ => None,
- })
+ if hir_map.name(hi) != hir_map.name(my_hir) {
+ continue;
+ }
+ f_in_trait_opt = Some(hi);
+ break;
}
- _ => None,
+ f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
+ Some(Node::TraitItem(hir::TraitItem {
+ kind:
+ hir::TraitItemKind::Fn(
+ hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
+ _,
+ ),
+ ..
+ })) => {
+ let hir::Ty { span, .. } = inputs[local.index() - 1];
+ Some(span)
+ }
+ _ => None,
+ })
}
+ _ => None,
}),
)
}
@@ -706,13 +721,12 @@
&origin_projection,
) {
match captured_place.info.capture_kind {
- ty::UpvarCapture::ByRef(ty::UpvarBorrow {
- kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
- ..
- }) => {
+ ty::UpvarCapture::ByRef(
+ ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+ ) => {
capture_reason = format!("mutable borrow of `{}`", upvar);
}
- ty::UpvarCapture::ByValue(_) => {
+ ty::UpvarCapture::ByValue => {
capture_reason = format!("possible mutation of `{}`", upvar);
}
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
@@ -747,7 +761,7 @@
HirId, ImplItem, ImplItemKind, Item, ItemKind,
};
- fn maybe_body_id_of_fn(hir_map: &Map<'_>, id: HirId) -> Option<BodyId> {
+ fn maybe_body_id_of_fn(hir_map: Map<'_>, id: HirId) -> Option<BodyId> {
match hir_map.find(id) {
Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. }))
| Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => {
@@ -758,7 +772,7 @@
}
let hir_map = self.infcx.tcx.hir();
let mir_body_hir_id = self.mir_hir_id();
- if let Some(fn_body_id) = maybe_body_id_of_fn(&hir_map, mir_body_hir_id) {
+ if let Some(fn_body_id) = maybe_body_id_of_fn(hir_map, mir_body_hir_id) {
if let Block(
hir::Block {
expr:
@@ -802,7 +816,7 @@
.map(|assoc_items| {
assoc_items
.in_definition_order()
- .map(|assoc_item_def| assoc_item_def.ident)
+ .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
.filter(|&ident| {
let original_method_ident = path_segment.ident;
original_method_ident != ident
@@ -897,7 +911,7 @@
if look_at_return && hir.get_return_block(closure_id).is_some() {
// ...otherwise we are probably in the tail expression of the function, point at the
// return type.
- match hir.get(hir.get_parent_item(fn_call_id)) {
+ match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) {
hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
| hir::Node::TraitItem(hir::TraitItem {
ident,
@@ -1076,8 +1090,7 @@
if let ty::Adt(def, _) = ty.kind() {
let field = def.all_fields().nth(field.index())?;
// Use the HIR types to construct the diagnostic message.
- let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?);
- let node = tcx.hir().find(hir_id)?;
+ let node = tcx.hir().find_by_def_id(field.did.as_local()?)?;
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
if let hir::Node::Field(field) = node {
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 723b57e..74e872e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -256,6 +256,6 @@
diag.sort_span = mir_span.shrink_to_hi();
// Buffer the diagnostic
- diag.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_non_error_diag(diag);
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index df23eaf..e6a323d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -5,6 +5,7 @@
error_reporting::nice_region_error::NiceRegionError,
error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
};
+use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::{self, RegionVid, Ty};
@@ -139,7 +140,7 @@
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
- if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
+ if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() {
if let ty::BoundRegionKind::BrEnv = free_region.bound_region {
if let DefiningTy::Closure(_, substs) =
self.regioncx.universal_regions().defining_ty
@@ -168,14 +169,12 @@
let type_test_span = type_test.locations.span(&self.body);
if let Some(lower_bound_region) = lower_bound_region {
- self.infcx
- .construct_generic_bound_failure(
- type_test_span,
- None,
- type_test.generic_kind,
- lower_bound_region,
- )
- .buffer(&mut self.errors_buffer);
+ self.buffer_error(self.infcx.construct_generic_bound_failure(
+ type_test_span,
+ None,
+ type_test.generic_kind,
+ lower_bound_region,
+ ));
} else {
// FIXME. We should handle this case better. It
// indicates that we have e.g., some region variable
@@ -186,27 +185,22 @@
// to report it; we could probably handle it by
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
- self.infcx
- .tcx
- .sess
- .struct_span_err(
- type_test_span,
- &format!("`{}` does not live long enough", type_test.generic_kind),
- )
- .buffer(&mut self.errors_buffer);
+ self.buffer_error(self.infcx.tcx.sess.struct_span_err(
+ type_test_span,
+ &format!("`{}` does not live long enough", type_test.generic_kind),
+ ));
}
}
RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
- unexpected_hidden_region_diagnostic(
+ self.buffer_error(unexpected_hidden_region_diagnostic(
self.infcx.tcx,
span,
named_ty,
named_region,
- )
- .buffer(&mut self.errors_buffer);
+ ));
}
RegionErrorKind::BoundUniversalRegionError {
@@ -285,7 +279,7 @@
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
if let Some(diag) = nice.try_report_from_nll() {
- diag.buffer(&mut self.errors_buffer);
+ self.buffer_error(diag);
return;
}
}
@@ -375,7 +369,7 @@
}
}
- diag.buffer(&mut self.errors_buffer);
+ self.buffer_error(diag);
}
/// Report a specialized error when `FnMut` closures return a reference to a captured variable.
@@ -428,17 +422,26 @@
diag.span_label(*span, message);
- // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id
- if let ReturnConstraint::ClosureUpvar(upvar) = kind {
+ if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
DefiningTy::Closure(def_id, _) => def_id,
ty => bug!("unexpected DefiningTy {:?}", ty),
};
- let upvar_def_span = self.infcx.tcx.hir().span(upvar);
- let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span;
- diag.span_label(upvar_def_span, "variable defined here");
- diag.span_label(upvar_span, "variable captured here");
+ let captured_place = &self.upvars[upvar_field.index()].place;
+ let defined_hir = match captured_place.place.base {
+ PlaceBase::Local(hirid) => Some(hirid),
+ PlaceBase::Upvar(upvar) => Some(upvar.var_path.hir_id),
+ _ => None,
+ };
+
+ if defined_hir.is_some() {
+ let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
+ let upvar_def_span = self.infcx.tcx.hir().span(defined_hir.unwrap());
+ let upvar_span = upvars_map.get(&defined_hir.unwrap()).unwrap().span;
+ diag.span_label(upvar_def_span, "variable defined here");
+ diag.span_label(upvar_span, "variable captured here");
+ }
}
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
@@ -635,8 +638,8 @@
fr_name: RegionName,
outlived_fr: RegionVid,
) {
- if let (Some(f), Some(ty::RegionKind::ReStatic)) =
- (self.to_error_region(fr), self.to_error_region(outlived_fr))
+ if let (Some(f), Some(ty::ReStatic)) =
+ (self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref())
{
if let Some(&ty::Opaque(did, substs)) = self
.infcx
@@ -659,7 +662,7 @@
bound.kind().skip_binder()
{
let r = r.subst(self.infcx.tcx, substs);
- if let ty::RegionKind::ReStatic = r {
+ if r.is_static() {
found = true;
break;
} else {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 80f5f77..3bcc9f7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -264,7 +264,7 @@
let tcx = self.infcx.tcx;
debug!("give_region_a_name: error_region = {:?}", error_region);
- match error_region {
+ match *error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
@@ -311,43 +311,39 @@
ty::BoundRegionKind::BrEnv => {
let def_ty = self.regioncx.universal_regions().defining_ty;
- if let DefiningTy::Closure(_, substs) = def_ty {
- let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
- tcx.hir().expect_expr(self.mir_hir_id()).kind
- {
- span
- } else {
- bug!("Closure is not defined by a closure expr");
- };
- let region_name = self.synthesize_region_name();
-
- let closure_kind_ty = substs.as_closure().kind_ty();
- let note = match closure_kind_ty.to_opt_closure_kind() {
- Some(ty::ClosureKind::Fn) => {
- "closure implements `Fn`, so references to captured variables \
- can't escape the closure"
- }
- Some(ty::ClosureKind::FnMut) => {
- "closure implements `FnMut`, so references to captured variables \
- can't escape the closure"
- }
- Some(ty::ClosureKind::FnOnce) => {
- bug!("BrEnv in a `FnOnce` closure");
- }
- None => bug!("Closure kind not inferred in borrow check"),
- };
-
- Some(RegionName {
- name: region_name,
- source: RegionNameSource::SynthesizedFreeEnvRegion(
- args_span,
- note.to_string(),
- ),
- })
- } else {
+ let DefiningTy::Closure(_, substs) = def_ty else {
// Can't have BrEnv in functions, constants or generators.
bug!("BrEnv outside of closure.");
- }
+ };
+ let hir::ExprKind::Closure(_, _, _, args_span, _) =
+ tcx.hir().expect_expr(self.mir_hir_id()).kind else {
+ bug!("Closure is not defined by a closure expr");
+ };
+ let region_name = self.synthesize_region_name();
+
+ let closure_kind_ty = substs.as_closure().kind_ty();
+ let note = match closure_kind_ty.to_opt_closure_kind() {
+ Some(ty::ClosureKind::Fn) => {
+ "closure implements `Fn`, so references to captured variables \
+ can't escape the closure"
+ }
+ Some(ty::ClosureKind::FnMut) => {
+ "closure implements `FnMut`, so references to captured variables \
+ can't escape the closure"
+ }
+ Some(ty::ClosureKind::FnOnce) => {
+ bug!("BrEnv in a `FnOnce` closure");
+ }
+ None => bug!("Closure kind not inferred in borrow check"),
+ };
+
+ Some(RegionName {
+ name: region_name,
+ source: RegionNameSource::SynthesizedFreeEnvRegion(
+ args_span,
+ note.to_string(),
+ ),
+ })
}
ty::BoundRegionKind::BrAnon(_) => None,
@@ -437,7 +433,7 @@
span: Span,
counter: usize,
) -> RegionNameHighlight {
- let mut highlight = RegionHighlightMode::default();
+ let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
highlight.highlighting_region_vid(needle_fr, counter);
let type_name =
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
@@ -504,7 +500,7 @@
}
// Otherwise, let's descend into the referent types.
- search_stack.push((referent_ty, &referent_hir_ty.ty));
+ search_stack.push((*referent_ty, &referent_hir_ty.ty));
}
// Match up something like `Foo<'1>`
@@ -543,7 +539,7 @@
(ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
| (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => {
- search_stack.push((elem_ty, elem_hir_ty));
+ search_stack.push((*elem_ty, elem_hir_ty));
}
(ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
@@ -704,7 +700,7 @@
hir::AsyncGeneratorKind::Block => " of async block",
hir::AsyncGeneratorKind::Closure => " of async closure",
hir::AsyncGeneratorKind::Fn => {
- let parent_item = hir.get(hir.get_parent_item(mir_hir_id));
+ let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id));
let output = &parent_item
.fn_decl()
.expect("generator lowered from async fn should be in fn")
@@ -765,45 +761,45 @@
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
let hir = self.infcx.tcx.hir();
- if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind {
- let opaque_ty = hir.item(id);
- if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- bounds:
- [
- hir::GenericBound::LangItemTrait(
- hir::LangItem::Future,
- _,
- _,
- hir::GenericArgs {
- bindings:
- [
- hir::TypeBinding {
- ident: Ident { name: sym::Output, .. },
- kind: hir::TypeBindingKind::Equality { ty },
- ..
- },
- ],
- ..
- },
- ),
- ],
- ..
- }) = opaque_ty.kind
- {
- ty
- } else {
- span_bug!(
- hir_ty.span,
- "bounds from lowered return type of async fn did not match expected format: {:?}",
- opaque_ty
- );
- }
- } else {
+ let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
span_bug!(
hir_ty.span,
"lowered return type of async fn is not OpaqueDef: {:?}",
hir_ty
);
+ };
+ let opaque_ty = hir.item(id);
+ if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ bounds:
+ [
+ hir::GenericBound::LangItemTrait(
+ hir::LangItem::Future,
+ _,
+ _,
+ hir::GenericArgs {
+ bindings:
+ [
+ hir::TypeBinding {
+ ident: Ident { name: sym::Output, .. },
+ kind:
+ hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ ],
+ ..
+ }) = opaque_ty.kind
+ {
+ ty
+ } else {
+ span_bug!(
+ hir_ty.span,
+ "bounds from lowered return type of async fn did not match expected format: {:?}",
+ opaque_ty
+ );
}
}
@@ -822,7 +818,7 @@
return None;
}
- let mut highlight = RegionHighlightMode::default();
+ let mut highlight = RegionHighlightMode::new(tcx);
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
let type_name =
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index c03e4d8..73ced63 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -5,12 +5,11 @@
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
use rustc_middle::ty::TyCtxt;
-use std::iter;
use crate::{
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
- Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
- Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
+ Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind,
+ ReadOrWrite, Reservation, Shallow, Write, WriteKind,
};
pub(super) fn generate_invalidates<'tcx>(
@@ -59,37 +58,13 @@
StatementKind::Assign(box (lhs, rhs)) => {
self.consume_rvalue(location, rhs);
- self.mutate_place(location, *lhs, Shallow(None), JustWrite);
+ self.mutate_place(location, *lhs, Shallow(None));
}
StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
StatementKind::SetDiscriminant { place, variant_index: _ } => {
- self.mutate_place(location, **place, Shallow(None), JustWrite);
- }
- StatementKind::LlvmInlineAsm(asm) => {
- for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
- if o.is_indirect {
- // FIXME(eddyb) indirect inline asm outputs should
- // be encoded through MIR place derefs instead.
- self.access_place(
- location,
- *output,
- (Deep, Read(ReadKind::Copy)),
- LocalMutationIsAllowed::No,
- );
- } else {
- self.mutate_place(
- location,
- *output,
- if o.is_rw { Deep } else { Shallow(None) },
- if o.is_rw { WriteAndRead } else { JustWrite },
- );
- }
- }
- for (_, input) in asm.inputs.iter() {
- self.consume_operand(location, input);
- }
+ self.mutate_place(location, **place, Shallow(None));
}
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
ref src,
@@ -142,7 +117,7 @@
target: _,
unwind: _,
} => {
- self.mutate_place(location, *drop_place, Deep, JustWrite);
+ self.mutate_place(location, *drop_place, Deep);
self.consume_operand(location, new_value);
}
TerminatorKind::Call {
@@ -158,7 +133,7 @@
self.consume_operand(location, arg);
}
if let Some((dest, _ /*bb*/)) = destination {
- self.mutate_place(location, *dest, Deep, JustWrite);
+ self.mutate_place(location, *dest, Deep);
}
}
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@@ -181,7 +156,7 @@
}
}
- self.mutate_place(location, *resume_arg, Deep, JustWrite);
+ self.mutate_place(location, *resume_arg, Deep);
}
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
// Invalidate all borrows of local places
@@ -208,13 +183,13 @@
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
if let Some(place) = place {
- self.mutate_place(location, place, Shallow(None), JustWrite);
+ self.mutate_place(location, place, Shallow(None));
}
}
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
self.consume_operand(location, in_value);
if let Some(out_place) = out_place {
- self.mutate_place(location, out_place, Shallow(None), JustWrite);
+ self.mutate_place(location, out_place, Shallow(None));
}
}
InlineAsmOperand::Const { value: _ }
@@ -238,13 +213,7 @@
impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
/// Simulates mutation of a place.
- fn mutate_place(
- &mut self,
- location: Location,
- place: Place<'tcx>,
- kind: AccessDepth,
- _mode: MutateMode,
- ) {
+ fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
self.access_place(
location,
place,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index fe34d6e..04d914c 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -9,6 +9,7 @@
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
@@ -40,7 +41,6 @@
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeMap;
-use std::iter;
use std::mem;
use std::rc::Rc;
@@ -55,7 +55,6 @@
use self::diagnostics::{AccessKind, RegionName};
use self::location::LocationTable;
use self::prefixes::PrefixSet;
-use self::MutateMode::{JustWrite, WriteAndRead};
use facts::AllFacts;
use self::path_utils::*;
@@ -176,17 +175,20 @@
}
}
+ let mut errors = error::BorrowckErrors::new();
+
// Gather the upvars of a closure, if any.
let tables = tcx.typeck_opt_const_arg(def);
if let Some(ErrorReported) = tables.tainted_by_errors {
infcx.set_tainted_by_errors();
+ errors.set_tainted_by_errors();
}
let upvars: Vec<_> = tables
.closure_min_captures_flattened(def.did.to_def_id())
.map(|captured_place| {
let capture = captured_place.info.capture_kind;
let by_ref = match capture {
- ty::UpvarCapture::ByValue(_) => false,
+ ty::UpvarCapture::ByValue => false,
ty::UpvarCapture::ByRef(..) => true,
};
Upvar { place: captured_place.clone(), by_ref }
@@ -206,7 +208,6 @@
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>)>) =
match MoveData::gather_moves(&body, tcx, param_env) {
Ok(move_data) => (move_data, Vec::new()),
@@ -264,7 +265,7 @@
®ioncx,
&opt_closure_req,
&opaque_type_values,
- &mut errors_buffer,
+ &mut errors,
);
// The various `flow_*` structures can be large. We drop `flow_inits` here
@@ -311,9 +312,7 @@
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
reservation_warnings: Default::default(),
- move_error_reported: BTreeMap::new(),
uninitialized_error_reported: Default::default(),
- errors_buffer,
regioncx: regioncx.clone(),
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
@@ -324,9 +323,10 @@
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output: None,
+ errors,
};
promoted_mbcx.report_move_errors(move_errors);
- errors_buffer = promoted_mbcx.errors_buffer;
+ errors = promoted_mbcx.errors;
};
}
@@ -344,9 +344,7 @@
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
reservation_warnings: Default::default(),
- move_error_reported: BTreeMap::new(),
uninitialized_error_reported: Default::default(),
- errors_buffer,
regioncx: Rc::clone(®ioncx),
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
@@ -357,6 +355,7 @@
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output,
+ errors,
};
// Compute and report region errors, if any.
@@ -399,7 +398,7 @@
diag.message = initial_diag.styled_message().clone();
diag.span = initial_diag.span.clone();
- diag.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_non_error_diag(diag);
},
);
initial_diag.cancel();
@@ -424,7 +423,7 @@
mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
- let used_mut = mbcx.used_mut;
+ let used_mut = std::mem::take(&mut mbcx.used_mut);
for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
let local_decl = &mbcx.body.local_decls[local];
let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data {
@@ -461,23 +460,13 @@
})
}
- // Buffer any move errors that we collected and de-duplicated.
- for (_, (_, diag)) in mbcx.move_error_reported {
- diag.buffer(&mut mbcx.errors_buffer);
- }
-
- if !mbcx.errors_buffer.is_empty() {
- mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span);
-
- for diag in mbcx.errors_buffer.drain(..) {
- mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
- }
- }
+ let tainted_by_errors = mbcx.emit_errors();
let result = BorrowCheckResult {
concrete_opaque_types: opaque_type_values,
closure_requirements: opt_closure_req,
used_mut_upvars: mbcx.used_mut_upvars,
+ tainted_by_errors,
};
let body_with_facts = if return_body_with_facts {
@@ -554,26 +543,9 @@
/// for the activation of the borrow.
reservation_warnings:
FxHashMap<BorrowIndex, (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>)>,
- /// This field keeps track of move errors that are to be reported for given move indices.
- ///
- /// There are situations where many errors can be reported for a single move out (see #53807)
- /// and we want only the best of those errors.
- ///
- /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
- /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
- /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
- /// all move errors have been reported, any diagnostics in this map are added to the buffer
- /// to be emitted.
- ///
- /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
- /// when errors in the map are being re-added to the error buffer so that errors with the
- /// same primary span come out in a consistent order.
- move_error_reported: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>,
/// This field keeps track of errors reported in the checking of uninitialized variables,
/// so that we don't report seemingly duplicate errors.
uninitialized_error_reported: FxHashSet<PlaceRef<'tcx>>,
- /// Errors to be reported buffer
- errors_buffer: Vec<Diagnostic>,
/// This field keeps track of all the local variables that are declared mut and are mutated.
/// Used for the warning issued by an unused mutable local variable.
used_mut: FxHashSet<Local>,
@@ -605,6 +577,8 @@
/// Results of Polonius analysis.
polonius_output: Option<Rc<PoloniusOutput>>,
+
+ errors: error::BorrowckErrors<'tcx>,
}
// Check that:
@@ -630,7 +604,7 @@
StatementKind::Assign(box (lhs, ref rhs)) => {
self.consume_rvalue(location, (rhs, span), flow_state);
- self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
+ self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
}
StatementKind::FakeRead(box (_, ref place)) => {
// Read for match doesn't access any memory and is used to
@@ -651,41 +625,8 @@
);
}
StatementKind::SetDiscriminant { place, variant_index: _ } => {
- self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
+ self.mutate_place(location, (**place, span), Shallow(None), flow_state);
}
- StatementKind::LlvmInlineAsm(ref asm) => {
- for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
- if o.is_indirect {
- // FIXME(eddyb) indirect inline asm outputs should
- // be encoded through MIR place derefs instead.
- self.access_place(
- location,
- (*output, o.span),
- (Deep, Read(ReadKind::Copy)),
- LocalMutationIsAllowed::No,
- flow_state,
- );
- self.check_if_path_or_subpath_is_moved(
- location,
- InitializationRequiringAction::Use,
- (output.as_ref(), o.span),
- flow_state,
- );
- } else {
- self.mutate_place(
- location,
- (*output, o.span),
- if o.is_rw { Deep } else { Shallow(None) },
- if o.is_rw { WriteAndRead } else { JustWrite },
- flow_state,
- );
- }
- }
- for (_, input) in asm.inputs.iter() {
- self.consume_operand(location, (input, span), flow_state);
- }
- }
-
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
..
}) => {
@@ -750,7 +691,7 @@
target: _,
unwind: _,
} => {
- self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state);
+ self.mutate_place(loc, (drop_place, span), Deep, flow_state);
self.consume_operand(loc, (new_value, span), flow_state);
}
TerminatorKind::Call {
@@ -766,7 +707,7 @@
self.consume_operand(loc, (arg, span), flow_state);
}
if let Some((dest, _ /*bb*/)) = *destination {
- self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state);
+ self.mutate_place(loc, (dest, span), Deep, flow_state);
}
}
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@@ -780,7 +721,7 @@
TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
self.consume_operand(loc, (value, span), flow_state);
- self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
+ self.mutate_place(loc, (resume_arg, span), Deep, flow_state);
}
TerminatorKind::InlineAsm {
@@ -798,13 +739,7 @@
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
if let Some(place) = place {
- self.mutate_place(
- loc,
- (place, span),
- Shallow(None),
- JustWrite,
- flow_state,
- );
+ self.mutate_place(loc, (place, span), Shallow(None), flow_state);
}
}
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
@@ -814,7 +749,6 @@
loc,
(out_place, span),
Shallow(None),
- JustWrite,
flow_state,
);
}
@@ -886,12 +820,6 @@
}
}
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum MutateMode {
- JustWrite,
- WriteAndRead,
-}
-
use self::AccessDepth::{Deep, Shallow};
use self::ReadOrWrite::{Activation, Read, Reservation, Write};
@@ -977,7 +905,6 @@
#[derive(Copy, Clone, Debug)]
enum InitializationRequiringAction {
- Update,
Borrow,
MatchOn,
Use,
@@ -994,7 +921,6 @@
impl InitializationRequiringAction {
fn as_noun(self) -> &'static str {
match self {
- InitializationRequiringAction::Update => "update",
InitializationRequiringAction::Borrow => "borrow",
InitializationRequiringAction::MatchOn => "use", // no good noun
InitializationRequiringAction::Use => "use",
@@ -1005,7 +931,6 @@
fn as_verb_in_past_tense(self) -> &'static str {
match self {
- InitializationRequiringAction::Update => "updated",
InitializationRequiringAction::Borrow => "borrowed",
InitializationRequiringAction::MatchOn => "matched on",
InitializationRequiringAction::Use => "used",
@@ -1077,7 +1002,6 @@
if conflict_error || mutability_error {
debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
-
self.access_place_error_reported.insert((place_span.0, place_span.1));
}
}
@@ -1157,12 +1081,14 @@
error_reported = true;
match kind {
ReadKind::Copy => {
- this.report_use_while_mutably_borrowed(location, place_span, borrow)
- .buffer(&mut this.errors_buffer);
+ let err = this
+ .report_use_while_mutably_borrowed(location, place_span, borrow);
+ this.buffer_error(err);
}
ReadKind::Borrow(bk) => {
- this.report_conflicting_borrow(location, place_span, bk, borrow)
- .buffer(&mut this.errors_buffer);
+ let err =
+ this.report_conflicting_borrow(location, place_span, bk, borrow);
+ this.buffer_error(err);
}
}
Control::Break
@@ -1212,8 +1138,9 @@
error_reported = true;
match kind {
WriteKind::MutableBorrow(bk) => {
- this.report_conflicting_borrow(location, place_span, bk, borrow)
- .buffer(&mut this.errors_buffer);
+ let err =
+ this.report_conflicting_borrow(location, place_span, bk, borrow);
+ this.buffer_error(err);
}
WriteKind::StorageDeadOrDrop => this
.report_borrowed_value_does_not_live_long_enough(
@@ -1242,23 +1169,10 @@
location: Location,
place_span: (Place<'tcx>, Span),
kind: AccessDepth,
- mode: MutateMode,
flow_state: &Flows<'cx, 'tcx>,
) {
- // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
- match mode {
- MutateMode::WriteAndRead => {
- self.check_if_path_or_subpath_is_moved(
- location,
- InitializationRequiringAction::Update,
- (place_span.0.as_ref(), place_span.1),
- flow_state,
- );
- }
- MutateMode::JustWrite => {
- self.check_if_assigned_path_is_moved(location, place_span, flow_state);
- }
- }
+ // Write of P[i] or *P requires P init'd.
+ self.check_if_assigned_path_is_moved(location, place_span, flow_state);
// Special case: you can assign an immutable local variable
// (e.g., `x = ...`) so long as it has never been initialized
@@ -1490,9 +1404,8 @@
bug!("temporary should be initialized exactly once")
};
- let loc = match init.location {
- InitLocation::Statement(stmt) => stmt,
- _ => bug!("temporary initialized in arguments"),
+ let InitLocation::Statement(loc) = init.location else {
+ bug!("temporary initialized in arguments")
};
let body = self.body;
@@ -1634,7 +1547,7 @@
yield_span,
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
}
@@ -2110,10 +2023,9 @@
| WriteKind::MutableBorrow(BorrowKind::Shared)
| WriteKind::MutableBorrow(BorrowKind::Shallow),
) => {
- if let (Err(_), true) = (
- self.is_mutable(place.as_ref(), is_local_mutation_allowed),
- self.errors_buffer.is_empty(),
- ) {
+ if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
+ && !self.has_buffered_errors()
+ {
// rust-lang/rust#46908: In pure NLL mode this code path should be
// unreachable, but we use `delay_span_bug` because we can hit this when
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
@@ -2365,6 +2277,112 @@
}
}
+mod error {
+ use super::*;
+
+ pub struct BorrowckErrors<'tcx> {
+ /// This field keeps track of move errors that are to be reported for given move indices.
+ ///
+ /// There are situations where many errors can be reported for a single move out (see #53807)
+ /// and we want only the best of those errors.
+ ///
+ /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
+ /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
+ /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
+ /// all move errors have been reported, any diagnostics in this map are added to the buffer
+ /// to be emitted.
+ ///
+ /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
+ /// when errors in the map are being re-added to the error buffer so that errors with the
+ /// same primary span come out in a consistent order.
+ buffered_move_errors:
+ BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
+ /// Errors to be reported buffer
+ buffered: Vec<Diagnostic>,
+ /// Set to Some if we emit an error during borrowck
+ tainted_by_errors: Option<ErrorReported>,
+ }
+
+ impl BorrowckErrors<'_> {
+ pub fn new() -> Self {
+ BorrowckErrors {
+ buffered_move_errors: BTreeMap::new(),
+ buffered: Default::default(),
+ tainted_by_errors: None,
+ }
+ }
+
+ pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
+ self.tainted_by_errors = Some(ErrorReported {});
+ t.buffer(&mut self.buffered);
+ }
+
+ // For diagnostics we must not set `tainted_by_errors`.
+ pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_>) {
+ t.buffer(&mut self.buffered);
+ }
+
+ pub fn set_tainted_by_errors(&mut self) {
+ self.tainted_by_errors = Some(ErrorReported {});
+ }
+ }
+
+ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+ pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
+ self.errors.buffer_error(t);
+ }
+
+ pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_>) {
+ self.errors.buffer_non_error_diag(t);
+ }
+
+ pub fn buffer_move_error(
+ &mut self,
+ move_out_indices: Vec<MoveOutIndex>,
+ place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
+ ) -> bool {
+ if let Some((_, mut diag)) =
+ self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
+ {
+ // Cancel the old diagnostic so we don't ICE
+ diag.cancel();
+ false
+ } else {
+ true
+ }
+ }
+
+ pub fn emit_errors(&mut self) -> Option<ErrorReported> {
+ // Buffer any move errors that we collected and de-duplicated.
+ for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
+ // We have already set tainted for this error, so just buffer it.
+ diag.buffer(&mut self.errors.buffered);
+ }
+
+ if !self.errors.buffered.is_empty() {
+ self.errors.buffered.sort_by_key(|diag| diag.sort_span);
+
+ for diag in self.errors.buffered.drain(..) {
+ self.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
+ }
+ }
+
+ self.errors.tainted_by_errors
+ }
+
+ pub fn has_buffered_errors(&self) -> bool {
+ self.errors.buffered.is_empty()
+ }
+
+ pub fn has_move_error(
+ &self,
+ move_out_indices: &[MoveOutIndex],
+ ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
+ self.errors.buffered_move_errors.get(move_out_indices)
+ }
+ }
+}
+
/// The degree of overlap between 2 places for borrow-checking.
enum Overlap {
/// The places might partially overlap - in this case, we give
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 6ffab16..a2736fd 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -1,7 +1,6 @@
//! The entry point of the NLL borrow checker.
use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::Diagnostic;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
@@ -9,7 +8,7 @@
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
Promoted,
};
-use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty};
+use rustc_middle::ty::{self, OpaqueTypeKey, Region, RegionVid, Ty};
use rustc_span::symbol::sym;
use std::env;
use std::fmt::Debug;
@@ -373,7 +372,7 @@
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
- errors_buffer: &mut Vec<Diagnostic>,
+ errors: &mut crate::error::BorrowckErrors<'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@@ -418,7 +417,7 @@
err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
}
- err.buffer(errors_buffer);
+ errors.buffer_non_error_diag(err);
}
fn for_each_region_constraint(
@@ -444,9 +443,9 @@
fn to_region_vid(self) -> RegionVid;
}
-impl<'tcx> ToRegionVid for &'tcx RegionKind {
+impl<'tcx> ToRegionVid for Region<'tcx> {
fn to_region_vid(self) -> RegionVid {
- if let ty::ReVar(vid) = self { *vid } else { bug!("region is not an ReVar: {:?}", self) }
+ if let ty::ReVar(vid) = *self { vid } else { bug!("region is not an ReVar: {:?}", self) }
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index cfd3acb..97233b9 100644
--- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -72,7 +72,7 @@
}
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
- constraints.sort();
+ constraints.sort_by_key(|c| (c.sup, c.sub));
for constraint in &constraints {
let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
let (name, arg) = match locations {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index b39a28f..abd6a15 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -612,7 +612,7 @@
fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
debug!("constraints={:#?}", {
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
- constraints.sort();
+ constraints.sort_by_key(|c| (c.sup, c.sub));
constraints
.into_iter()
.map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub)))
@@ -1169,7 +1169,7 @@
match verify_bound {
VerifyBound::IfEq(test_ty, verify_bound1) => {
- self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1)
+ self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1)
}
VerifyBound::IsEmpty => {
@@ -1178,7 +1178,7 @@
}
VerifyBound::OutlivedBy(r) => {
- let r_vid = self.to_region_vid(r);
+ let r_vid = self.to_region_vid(*r);
self.eval_outlives(r_vid, lower_bound)
}
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 76b3be7..60c48d8 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -133,7 +133,7 @@
for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
match self.definitions[vid].external_name {
None => {}
- Some(&ty::ReStatic) => {}
+ Some(region) if region.is_static() => {}
Some(region) => return region,
}
}
@@ -183,7 +183,7 @@
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
- GenericArgKind::Lifetime(ty::ReStatic) => {
+ GenericArgKind::Lifetime(lt) if lt.is_static() => {
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_label(
@@ -196,9 +196,9 @@
return false;
}
GenericArgKind::Lifetime(lt) => {
- matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+ matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
}
- GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
+ GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
};
if arg_is_param {
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 4b6cab2..2876d60 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -57,7 +57,7 @@
#[instrument(skip(self), level = "debug")]
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
- *ty = self.renumber_regions(ty);
+ *ty = self.renumber_regions(*ty);
debug!(?ty);
}
@@ -72,12 +72,12 @@
#[instrument(skip(self), level = "debug")]
fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
let old_region = *region;
- *region = self.renumber_regions(&old_region);
+ *region = self.renumber_regions(old_region);
debug!(?region);
}
- fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
- *constant = self.renumber_regions(&*constant);
+ fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) {
+ *constant = self.renumber_regions(*constant);
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index a3b3959..5022cb9 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -105,8 +105,8 @@
// create new region variables, which can't be done later when
// verifying these bounds.
if t1.has_placeholders() {
- t1 = tcx.fold_regions(&t1, &mut false, |r, _| match *r {
- ty::RegionKind::RePlaceholder(placeholder) => {
+ t1 = tcx.fold_regions(t1, &mut false, |r, _| match *r {
+ ty::RePlaceholder(placeholder) => {
self.constraints.placeholder_region(self.infcx, placeholder)
}
_ => r,
@@ -142,8 +142,8 @@
}
fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
- if let ty::RePlaceholder(placeholder) = r {
- self.constraints.placeholder_region(self.infcx, *placeholder).to_region_vid()
+ if let ty::RePlaceholder(placeholder) = *r {
+ self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
} else {
self.universal_regions.to_region_vid(r)
}
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index fec6bdf..9a02814 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -358,7 +358,7 @@
// `where Type:` is lowered to `where Type: 'empty` so that
// we check `Type` is well formed, but there's no use for
// this bound here.
- if let ty::ReEmpty(_) = r1 {
+ if r1.is_empty() {
return;
}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 094af20..169de23 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -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(self.cx.typeck.tcx()) {
+ if local_ty.has_free_regions() {
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 1f745f9..a582409 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -312,6 +312,7 @@
}
}
+#[track_caller]
fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) {
// We sometimes see MIR failures (notably predicate failures) due to
// the fact that we check rvalue sized predicates here. So use `delay_span_bug`
@@ -382,7 +383,7 @@
} else {
let tcx = self.tcx();
let maybe_uneval = match constant.literal {
- ConstantKind::Ty(ct) => match ct.val {
+ ConstantKind::Ty(ct) => match ct.val() {
ty::ConstKind::Unevaluated(uv) => Some(uv),
_ => None,
},
@@ -425,7 +426,7 @@
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
constant.literal.ty(),
uv.def.did,
- UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None },
+ UserSubsts { substs: uv.substs, user_self_ty: None },
)),
) {
span_mirbug!(
@@ -481,7 +482,7 @@
// then remove the outermost reference so we can check the
// type annotation for the remaining type.
if let ty::Ref(_, rty, _) = local_decl.ty.kind() {
- rty
+ *rty
} else {
bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
}
@@ -715,7 +716,7 @@
PlaceTy::from_ty(match base_ty.kind() {
ty::Array(inner, _) => {
assert!(!from_end, "array subslices should not use from_end");
- tcx.mk_array(inner, to - from)
+ tcx.mk_array(*inner, to - from)
}
ty::Slice(..) => {
assert!(from_end, "slice subslices should use from_end");
@@ -757,6 +758,7 @@
},
ProjectionElem::Field(field, fty) => {
let fty = self.sanitize_type(place, fty);
+ let fty = self.cx.normalize(fty, location);
match self.field_ty(place, base, field, location) {
Ok(ty) => {
let ty = self.cx.normalize(ty, location);
@@ -1477,7 +1479,6 @@
StatementKind::FakeRead(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
- | StatementKind::LlvmInlineAsm { .. }
| StatementKind::Retag { .. }
| StatementKind::Coverage(..)
| StatementKind::Nop => {}
@@ -1736,7 +1737,7 @@
ConstraintCategory::Boring
};
if let Err(terr) =
- self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category)
+ self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category)
{
span_mirbug!(
self,
@@ -1955,7 +1956,7 @@
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
if let Operand::Constant(constant) = op {
let maybe_uneval = match constant.literal {
- ConstantKind::Ty(ct) => match ct.val {
+ ConstantKind::Ty(ct) => match ct.val() {
ty::ConstKind::Unevaluated(uv) => Some(uv),
_ => None,
},
@@ -1969,7 +1970,7 @@
let predicates = self.prove_closure_bounds(
tcx,
def_id.expect_local(),
- uv.substs(tcx),
+ uv.substs,
location,
);
self.normalize_and_prove_instantiated_predicates(
@@ -2047,7 +2048,7 @@
}
}
- Rvalue::NullaryOp(_, ty) => {
+ &Rvalue::NullaryOp(_, ty) => {
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
@@ -2065,7 +2066,7 @@
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
- substs: tcx.mk_substs_trait(ty, &[]),
+ substs: tcx.mk_substs_trait(*ty, &[]),
};
self.prove_trait_ref(
@@ -2092,7 +2093,7 @@
let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
if let Err(terr) = self.eq_types(
- ty,
+ *ty,
ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast,
@@ -2116,7 +2117,7 @@
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
if let Err(terr) = self.eq_types(
- ty,
+ *ty,
ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast,
@@ -2145,7 +2146,7 @@
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
if let Err(terr) = self.eq_types(
- ty,
+ *ty,
ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast,
@@ -2208,8 +2209,8 @@
}
};
if let Err(terr) = self.sub_types(
- ty_from,
- ty_to,
+ *ty_from,
+ *ty_to,
location.to_locations(),
ConstraintCategory::Cast,
) {
@@ -2277,8 +2278,8 @@
}
if let Err(terr) = self.sub_types(
- ty_elem,
- ty_to,
+ *ty_elem,
+ *ty_to,
location.to_locations(),
ConstraintCategory::Cast,
) {
@@ -2296,7 +2297,7 @@
CastKind::Misc => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
- let cast_ty_to = CastTy::from_ty(ty);
+ let cast_ty_to = CastTy::from_ty(*ty);
match (cast_ty_from, cast_ty_to) {
(None, _)
| (_, None | Some(CastTy::FnPtr))
@@ -2317,7 +2318,7 @@
}
Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
- self.add_reborrow_constraint(&body, location, region, borrowed_place);
+ self.add_reborrow_constraint(&body, location, *region, borrowed_place);
}
Rvalue::BinaryOp(
@@ -2529,9 +2530,7 @@
body,
);
let category = if let Some(field) = field {
- let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable();
- // FIXME(project-rfc-2229#8): Use Place for better diagnostics
- ConstraintCategory::ClosureUpvar(var_hir_id)
+ ConstraintCategory::ClosureUpvar(field)
} else {
ConstraintCategory::Boring
};
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index cc3fe0a..590a7a9 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -117,7 +117,7 @@
// We don't have to worry about the equality of consts during borrow checking
// as consts always have a static lifetime.
- fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
+ fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
fn normalization() -> NormalizationStrategy {
NormalizationStrategy::Eager
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index b986df4..72de380 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -180,8 +180,9 @@
/// anywhere. There is only one, `'static`.
Global,
- /// An **external** region is only relevant for closures. In that
- /// case, it refers to regions that are free in the closure type
+ /// An **external** region is only relevant for
+ /// closures, generators, and inline consts. In that
+ /// case, it refers to regions that are free in the type
/// -- basically, something bound in the surrounding context.
///
/// Consider this example:
@@ -198,8 +199,8 @@
/// Here, the lifetimes `'a` and `'b` would be **external** to the
/// closure.
///
- /// If we are not analyzing a closure, there are no external
- /// lifetimes.
+ /// If we are not analyzing a closure/generator/inline-const,
+ /// there are no external lifetimes.
External,
/// A **local** lifetime is one about which we know the full set
@@ -322,7 +323,7 @@
/// See `UniversalRegionIndices::to_region_vid`.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
- if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r {
+ if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r {
self.root_empty
} else {
self.indices.to_region_vid(r)
@@ -424,22 +425,30 @@
let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
- // If this is a closure or generator, then the late-bound regions from the enclosing
- // function are actually external regions to us. For example, here, 'a is not local
- // to the closure c (although it is local to the fn foo):
- // fn foo<'a>() {
- // let c = || { let x: &'a u32 = ...; }
- // }
- if self.mir_def.did.to_def_id() != typeck_root_def_id {
+ // If this is is a 'root' body (not a closure/generator/inline const), then
+ // there are no extern regions, so the local regions start at the same
+ // position as the (empty) sub-list of extern regions
+ let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ first_extern_index
+ } else {
+ // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
+ // function are actually external regions to us. For example, here, 'a is not local
+ // to the closure c (although it is local to the fn foo):
+ // fn foo<'a>() {
+ // let c = || { let x: &'a u32 = ...; }
+ // }
self.infcx
- .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
- }
-
- let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
+ .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
+ // Any regions created during the execution of `defining_ty` or during the above
+ // late-bound region replacement are all considered 'extern' regions
+ self.infcx.num_region_vars()
+ };
// "Liberate" the late-bound regions. These correspond to
// "local" free regions.
- let first_local_index = self.infcx.num_region_vars();
+
+ let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
+
let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
FR,
self.mir_def.did,
@@ -503,7 +512,7 @@
first_local_index,
num_universals,
defining_ty,
- unnormalized_output_ty,
+ unnormalized_output_ty: *unnormalized_output_ty,
unnormalized_input_tys,
yield_ty,
}
@@ -796,7 +805,7 @@
/// during initialization. Relies on the `indices` map having been
/// fully initialized.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
- if let ty::ReVar(..) = r {
+ if let ty::ReVar(..) = *r {
r.to_region_vid()
} else {
*self
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 1a93b9b..ac37c49 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -16,13 +16,13 @@
use smallvec::smallvec;
pub struct AsmArgs {
- templates: Vec<P<ast::Expr>>,
- operands: Vec<(ast::InlineAsmOperand, Span)>,
+ pub templates: Vec<P<ast::Expr>>,
+ pub operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
- clobber_abis: Vec<(Symbol, Span)>,
+ pub clobber_abis: Vec<(Symbol, Span)>,
options: ast::InlineAsmOptions,
- options_spans: Vec<Span>,
+ pub options_spans: Vec<Span>,
}
fn parse_args<'a>(
@@ -50,15 +50,6 @@
return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
}
- // Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
- if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
- let mut err =
- diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
- err.note("consider migrating to the new asm! syntax specified in RFC 2873");
- err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
- return Err(err);
- }
-
let first_template = p.parse_expr()?;
let mut args = AsmArgs {
templates: vec![first_template],
@@ -709,11 +700,11 @@
Some(idx)
}
}
- parse::ArgumentNamed(name) => match args.named_args.get(&name) {
+ parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
- ecx.struct_span_err(span, &msg).emit();
+ ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
None
}
},
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index eb08170..c06af52 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -6,9 +6,7 @@
/// Emits errors for literal expressions that are invalid inside and outside of an array.
fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_nested: bool) {
- let lit = if let ast::ExprKind::Lit(lit) = &expr.kind {
- lit
- } else {
+ let ast::ExprKind::Lit(lit) = &expr.kind else {
unreachable!();
};
match lit.kind {
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 8c53094..1d1eee8 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -222,9 +222,6 @@
"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" };
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 367a5aa..0ca7988 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -134,7 +134,7 @@
// Create the type of `self`.
//
- // in addition, remove defaults from type params (impls cannot have them).
+ // in addition, remove defaults from generic params (impls cannot have them).
let self_params: Vec<_> = generics
.params
.iter_mut()
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 154c51b2..6141d00 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -4,13 +4,15 @@
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::visit::{self, Visitor};
use rustc_ast::{token, BlockCheckMode, UnsafeSource};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
use rustc_expand::base::{self, *};
use rustc_parse_format as parse;
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{MultiSpan, Span};
+use rustc_span::{InnerSpan, MultiSpan, Span};
+use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
@@ -24,7 +26,7 @@
enum Position {
Exact(usize),
Capture(usize),
- Named(Symbol),
+ Named(Symbol, InnerSpan),
}
struct Context<'a, 'b> {
@@ -245,13 +247,13 @@
match *p {
parse::String(_) => {}
parse::NextArgument(ref mut arg) => {
- if let parse::ArgumentNamed(s) = arg.position {
+ if let parse::ArgumentNamed(s, _) = arg.position {
arg.position = parse::ArgumentIs(lookup(s));
}
- if let parse::CountIsName(s) = arg.format.width {
+ if let parse::CountIsName(s, _) = arg.format.width {
arg.format.width = parse::CountIsParam(lookup(s));
}
- if let parse::CountIsName(s) = arg.format.precision {
+ if let parse::CountIsName(s, _) = arg.format.precision {
arg.format.precision = parse::CountIsParam(lookup(s));
}
}
@@ -274,7 +276,7 @@
// it's written second, so it should come after width/precision.
let pos = match arg.position {
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
- parse::ArgumentNamed(s) => Named(s),
+ parse::ArgumentNamed(s, span) => Named(s, span),
};
let ty = Placeholder(match arg.format.ty {
@@ -344,8 +346,8 @@
parse::CountIsParam(i) => {
self.verify_arg_type(Exact(i), Count);
}
- parse::CountIsName(s) => {
- self.verify_arg_type(Named(s), Count);
+ parse::CountIsName(s, span) => {
+ self.verify_arg_type(Named(s, span), Count);
}
}
}
@@ -531,7 +533,7 @@
}
}
- Named(name) => {
+ Named(name, span) => {
match self.names.get(&name) {
Some(&idx) => {
// Treat as positional arg.
@@ -546,7 +548,7 @@
self.arg_types.push(Vec::new());
self.arg_unique_types.push(Vec::new());
let span = if self.is_literal {
- *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
+ self.fmtsp.from_inner(span)
} else {
self.fmtsp
};
@@ -557,7 +559,7 @@
} else {
let msg = format!("there is no argument named `{}`", name);
let sp = if self.is_literal {
- *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
+ self.fmtsp.from_inner(span)
} else {
self.fmtsp
};
@@ -627,7 +629,7 @@
}
parse::CountImplied => count(sym::Implied, None),
// should never be the case, names are already resolved
- parse::CountIsName(_) => panic!("should never happen"),
+ parse::CountIsName(..) => panic!("should never happen"),
}
}
@@ -674,7 +676,7 @@
// should never be the case, because names are already
// resolved.
- parse::ArgumentNamed(_) => panic!("should never happen"),
+ parse::ArgumentNamed(..) => panic!("should never happen"),
}
};
@@ -756,78 +758,109 @@
/// Actually builds the expression which the format_args! block will be
/// expanded to.
fn into_expr(self) -> P<ast::Expr> {
- let mut args = Vec::with_capacity(
+ let mut original_args = self.args;
+ let mut fmt_args = Vec::with_capacity(
self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
);
- let mut heads = Vec::with_capacity(self.args.len());
// First, build up the static array which will become our precompiled
// format "string"
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
- // Before consuming the expressions, we have to remember spans for
- // count arguments as they are now generated separate from other
- // arguments, hence have no access to the `P<ast::Expr>`'s.
- let spans_pos: Vec<_> = self.args.iter().map(|e| e.span).collect();
-
- // Right now there is a bug such that for the expression:
- // foo(bar(&1))
- // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
- // valid for the call to `foo`. To work around this all arguments to the
- // format! string are shoved into locals. Furthermore, we shove the address
- // of each variable because we don't want to move out of the arguments
- // passed to this function.
- for (i, e) in self.args.into_iter().enumerate() {
- for arg_ty in self.arg_unique_types[i].iter() {
- args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
- }
- // use the arg span for `&arg` so that borrowck errors
- // point to the specific expression passed to the macro
- // (the span is otherwise unavailable in MIR)
- heads.push(self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e));
+ // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
+ // constructor. In general the expressions in this slice might be
+ // permuted from their order in original_args (such as in the case of
+ // "{1} {0}"), or may have multiple entries referring to the same
+ // element of original_args ("{0} {0}").
+ //
+ // The following vector has one item per element of our output slice,
+ // identifying the index of which element of original_args it's passing,
+ // and that argument's type.
+ let mut fmt_arg_index_and_ty = SmallVec::<[(usize, &ArgumentType); 8]>::new();
+ for (i, unique_types) in self.arg_unique_types.iter().enumerate() {
+ fmt_arg_index_and_ty.extend(unique_types.iter().map(|ty| (i, ty)));
}
- for index in self.count_args {
- let span = spans_pos[index];
- args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
+ fmt_arg_index_and_ty.extend(self.count_args.iter().map(|&i| (i, &Count)));
+
+ // Figure out whether there are permuted or repeated elements. If not,
+ // we can generate simpler code.
+ //
+ // The sequence has no indices out of order or repeated if: for every
+ // adjacent pair of elements, the first one's index is less than the
+ // second one's index.
+ let nicely_ordered =
+ fmt_arg_index_and_ty.array_windows().all(|[(i, _i_ty), (j, _j_ty)]| i < j);
+
+ // We want to emit:
+ //
+ // [ArgumentV1::new(&$arg0, …), ArgumentV1::new(&$arg1, …), …]
+ //
+ // However, it's only legal to do so if $arg0, $arg1, … were written in
+ // exactly that order by the programmer. When arguments are permuted, we
+ // want them evaluated in the order written by the programmer, not in
+ // the order provided to fmt::Arguments. When arguments are repeated, we
+ // want the expression evaluated only once.
+ //
+ // Further, if any arg _after the first one_ contains a yield point such
+ // as `await` or `yield`, the above short form is inconvenient for the
+ // caller because it would keep a temporary of type ArgumentV1 alive
+ // across the yield point. ArgumentV1 can't implement Send since it
+ // holds a type-erased arbitrary type.
+ //
+ // Thus in the not nicely ordered case, and in the yielding case, we
+ // emit the following instead:
+ //
+ // match (&$arg0, &$arg1, …) {
+ // args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …]
+ // }
+ //
+ // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty.
+ // This more verbose representation ensures that all arguments are
+ // evaluated a single time each, in the order written by the programmer,
+ // and that the surrounding future/generator (if any) is Send whenever
+ // possible.
+ let no_need_for_match =
+ nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e));
+
+ for (arg_index, arg_ty) in fmt_arg_index_and_ty {
+ let e = &mut original_args[arg_index];
+ let span = e.span;
+ let arg = if no_need_for_match {
+ let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
+ // The indices are strictly ordered so e has not been taken yet.
+ self.ecx.expr_addr_of(expansion_span, P(e.take()))
+ } else {
+ let def_site = self.ecx.with_def_site_ctxt(span);
+ let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site));
+ let member = Ident::new(sym::integer(arg_index), def_site);
+ self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member))
+ };
+ fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
}
- let args_array = self.ecx.expr_vec(self.macsp, args);
+ let args_array = self.ecx.expr_vec(self.macsp, fmt_args);
+ let args_slice = self.ecx.expr_addr_of(
+ self.macsp,
+ if no_need_for_match {
+ args_array
+ } else {
+ // In the !no_need_for_match case, none of the exprs were moved
+ // away in the previous loop.
+ //
+ // This uses the arg span for `&arg` so that borrowck errors
+ // point to the specific expression passed to the macro (the
+ // span is otherwise unavailable in the MIR used by borrowck).
+ let heads = original_args
+ .into_iter()
+ .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
+ .collect();
- // Constructs an AST equivalent to:
- //
- // match (&arg0, &arg1) {
- // (tmp0, tmp1) => args_array
- // }
- //
- // It was:
- //
- // let tmp0 = &arg0;
- // let tmp1 = &arg1;
- // args_array
- //
- // Because of #11585 the new temporary lifetime rule, the enclosing
- // statements for these temporaries become the let's themselves.
- // If one or more of them are RefCell's, RefCell borrow() will also
- // end there; they don't last long enough for args_array to use them.
- // The match expression solves the scope problem.
- //
- // Note, it may also very well be transformed to:
- //
- // match arg0 {
- // ref tmp0 => {
- // match arg1 => {
- // ref tmp1 => args_array } } }
- //
- // But the nested match expression is proved to perform not as well
- // as series of let's; the first approach does.
- let args_match = {
- let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp));
- 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, args_match);
+ let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
+ 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])
+ },
+ );
// Now create the fmt::Arguments struct with all our locals we created.
let (fn_name, fn_args) = if self.all_pieces_simple {
@@ -860,11 +893,9 @@
macsp: Span,
mut sp: Span,
ty: &ArgumentType,
- arg_index: usize,
+ arg: P<ast::Expr>,
) -> P<ast::Expr> {
sp = ecx.with_def_site_ctxt(sp);
- let arg = ecx.expr_ident(sp, Ident::new(sym::_args, sp));
- let arg = ecx.expr(sp, ast::ExprKind::Field(arg, Ident::new(sym::integer(arg_index), sp)));
let trait_ = match *ty {
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
Placeholder(trait_) => trait_,
@@ -873,11 +904,21 @@
return ecx.expr_call_global(macsp, path, vec![arg]);
}
};
+ let new_fn_name = match trait_ {
+ "Display" => "new_display",
+ "Debug" => "new_debug",
+ "LowerExp" => "new_lower_exp",
+ "UpperExp" => "new_upper_exp",
+ "Octal" => "new_octal",
+ "Pointer" => "new_pointer",
+ "Binary" => "new_binary",
+ "LowerHex" => "new_lower_hex",
+ "UpperHex" => "new_upper_hex",
+ _ => unreachable!(),
+ };
- let path = ecx.std_path(&[sym::fmt, Symbol::intern(trait_), sym::fmt]);
- let format_fn = ecx.path_global(sp, path);
- let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::new]);
- ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
+ let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
+ ecx.expr_call_global(sp, path, vec![arg])
}
}
@@ -1213,3 +1254,35 @@
cx.into_expr()
}
+
+fn may_contain_yield_point(e: &ast::Expr) -> bool {
+ struct MayContainYieldPoint(bool);
+
+ impl Visitor<'_> for MayContainYieldPoint {
+ fn visit_expr(&mut self, e: &ast::Expr) {
+ if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
+ self.0 = true;
+ } else {
+ visit::walk_expr(self, e);
+ }
+ }
+
+ fn visit_mac_call(&mut self, _: &ast::MacCall) {
+ self.0 = true;
+ }
+
+ fn visit_attribute(&mut self, _: &ast::Attribute) {
+ // Conservatively assume this may be a proc macro attribute in
+ // expression position.
+ self.0 = true;
+ }
+
+ fn visit_item(&mut self, _: &ast::Item) {
+ // Do not recurse into nested items.
+ }
+ }
+
+ let mut visitor = MayContainYieldPoint(false);
+ visitor.visit_expr(e);
+ visitor.0
+}
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index a433876..36cfbba 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -26,14 +26,14 @@
// Allow using `#[global_allocator]` on an item statement
// FIXME - if we get deref patterns, use them to reduce duplication here
- let (item, is_stmt) = match &item {
+ let (item, is_stmt, ty_span) = match &item {
Annotatable::Item(item) => match item.kind {
- ItemKind::Static(..) => (item, false),
+ ItemKind::Static(ref ty, ..) => (item, false, ecx.with_def_site_ctxt(ty.span)),
_ => return not_static(),
},
Annotatable::Stmt(stmt) => match &stmt.kind {
StmtKind::Item(item_) => match item_.kind {
- ItemKind::Static(..) => (item_, true),
+ ItemKind::Static(ref ty, ..) => (item_, true, ecx.with_def_site_ctxt(ty.span)),
_ => return not_static(),
},
_ => return not_static(),
@@ -43,13 +43,14 @@
// Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span);
- let f = AllocFnFactory { span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
+ let f =
+ AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
// Generate item statements for the allocator methods.
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
// Generate anonymous constant serving as container for the allocator methods.
- let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
+ let const_ty = ecx.ty(ty_span, TyKind::Tup(Vec::new()));
let const_body = ecx.expr_block(ecx.block(span, stmts));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
let const_item = if is_stmt {
@@ -64,6 +65,7 @@
struct AllocFnFactory<'a, 'b> {
span: Span,
+ ty_span: Span,
kind: AllocatorKind,
global: Ident,
cx: &'b ExtCtxt<'a>,
@@ -97,18 +99,18 @@
self.attrs(),
kind,
);
- self.cx.stmt_item(self.span, item)
+ self.cx.stmt_item(self.ty_span, item)
}
fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> {
let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]);
- let method = self.cx.expr_path(self.cx.path(self.span, method));
- let allocator = self.cx.path_ident(self.span, self.global);
+ let method = self.cx.expr_path(self.cx.path(self.ty_span, method));
+ let allocator = self.cx.path_ident(self.ty_span, self.global);
let allocator = self.cx.expr_path(allocator);
- let allocator = self.cx.expr_addr_of(self.span, allocator);
+ let allocator = self.cx.expr_addr_of(self.ty_span, allocator);
args.insert(0, allocator);
- self.cx.expr_call(self.span, method, args)
+ self.cx.expr_call(self.ty_span, method, args)
}
fn attrs(&self) -> Vec<Attribute> {
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index e43cece..3887739 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -2,14 +2,18 @@
//! injecting code into the crate before it is lowered to HIR.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
+#![feature(is_sorted)]
#![feature(nll)]
+#![feature(let_else)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
extern crate proc_macro;
@@ -34,7 +38,6 @@
mod format;
mod format_foreign;
mod global_allocator;
-mod llvm_asm;
mod log_syntax;
mod source_util;
mod test;
@@ -78,7 +81,6 @@
include_str: source_util::expand_include_str,
include: source_util::expand_include,
line: source_util::expand_line,
- llvm_asm: llvm_asm::expand_llvm_asm,
log_syntax: log_syntax::expand_log_syntax,
module_path: source_util::expand_mod,
option_env: env::expand_option_env,
diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs
deleted file mode 100644
index d72bfa6..0000000
--- a/compiler/rustc_builtin_macros/src/llvm_asm.rs
+++ /dev/null
@@ -1,303 +0,0 @@
-// Llvm-style inline assembly support.
-//
-use State::*;
-
-use rustc_ast as ast;
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
-use rustc_ast::tokenstream::{self, TokenStream};
-use rustc_ast::LlvmAsmDialect;
-use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult};
-use rustc_expand::base::*;
-use rustc_parse::parser::Parser;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
-
-enum State {
- Asm,
- Outputs,
- Inputs,
- Clobbers,
- Options,
- StateNone,
-}
-
-impl State {
- fn next(&self) -> State {
- match *self {
- Asm => Outputs,
- Outputs => Inputs,
- Inputs => Clobbers,
- Clobbers => Options,
- Options => StateNone,
- StateNone => StateNone,
- }
- }
-}
-
-const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel];
-
-pub fn expand_llvm_asm<'cx>(
- cx: &'cx mut ExtCtxt<'_>,
- sp: Span,
- tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
- let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
- Ok(Some(inline_asm)) => inline_asm,
- Ok(None) => return DummyResult::any(sp),
- Err(mut err) => {
- err.emit();
- return DummyResult::any(sp);
- }
- };
-
- // If there are no outputs, the inline assembly is executed just for its side effects,
- // so ensure that it is volatile
- if inline_asm.outputs.is_empty() {
- inline_asm.volatile = true;
- }
-
- MacEager::expr(P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- kind: ast::ExprKind::LlvmInlineAsm(P(inline_asm)),
- span: cx.with_def_site_ctxt(sp),
- attrs: ast::AttrVec::new(),
- tokens: None,
- }))
-}
-
-fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> {
- match p.parse_str_lit() {
- Ok(str_lit) => Ok(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");
- Err(err)
- }
- }
-}
-
-fn parse_inline_asm<'a>(
- cx: &mut ExtCtxt<'a>,
- sp: Span,
- tts: TokenStream,
-) -> Result<Option<ast::LlvmInlineAsm>, DiagnosticBuilder<'a>> {
- // Split the tts before the first colon, to avoid `llvm_asm!("x": y)` being
- // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
- let first_colon = tts
- .trees()
- .position(|tt| {
- matches!(
- tt,
- tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
- )
- })
- .unwrap_or(tts.len());
- let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
- let mut asm = kw::Empty;
- let mut asm_str_style = None;
- let mut outputs = Vec::new();
- let mut inputs = Vec::new();
- let mut clobs = Vec::new();
- let mut volatile = false;
- let mut alignstack = false;
- let mut dialect = LlvmAsmDialect::Att;
-
- let mut state = Asm;
-
- 'statement: loop {
- match state {
- Asm => {
- if asm_str_style.is_some() {
- // If we already have a string with instructions,
- // ending up in Asm state again is an error.
- return Err(struct_span_err!(
- cx.sess.parse_sess.span_diagnostic,
- sp,
- E0660,
- "malformed inline assembly"
- ));
- }
- // Nested parser, stop before the first colon (see above).
- let mut p2 = cx.new_parser_from_tts(tts.trees().take(first_colon).collect());
-
- if p2.token == token::Eof {
- let mut err =
- cx.struct_span_err(sp, "macro requires a string literal as an argument");
- err.span_label(sp, "string literal required");
- return Err(err);
- }
-
- let expr = p2.parse_expr()?;
- let (s, style) =
- match expr_to_string(cx, expr, "inline assembly must be a string literal") {
- Some((s, st)) => (s, st),
- None => return Ok(None),
- };
-
- // This is most likely malformed.
- if p2.token != token::Eof {
- let mut extra_tts = p2.parse_all_token_trees()?;
- extra_tts.extend(tts.trees().skip(first_colon));
- p = cx.new_parser_from_tts(extra_tts.into_iter().collect());
- }
-
- asm = s;
- asm_str_style = Some(style);
- }
- Outputs => {
- while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
- if !outputs.is_empty() {
- p.eat(&token::Comma);
- }
-
- let constraint = parse_asm_str(&mut p)?;
-
- let span = p.prev_token.span;
-
- p.expect(&token::OpenDelim(token::Paren))?;
- let expr = p.parse_expr()?;
- p.expect(&token::CloseDelim(token::Paren))?;
-
- // Expands a read+write operand into two operands.
- //
- // Use '+' modifier when you want the same expression
- // to be both an input and an output at the same time.
- // It's the opposite of '=&' which means that the memory
- // cannot be shared with any other operand (usually when
- // a register is clobbered early.)
- let constraint_str = constraint.as_str();
- let mut ch = constraint_str.chars();
- let output = match ch.next() {
- Some('=') => None,
- Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
- _ => {
- struct_span_err!(
- cx.sess.parse_sess.span_diagnostic,
- span,
- E0661,
- "output operand constraint lacks '=' or '+'"
- )
- .emit();
- None
- }
- };
-
- let is_rw = output.is_some();
- let is_indirect = constraint_str.contains('*');
- outputs.push(ast::LlvmInlineAsmOutput {
- constraint: output.unwrap_or(constraint),
- expr,
- is_rw,
- is_indirect,
- });
- }
- }
- Inputs => {
- while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
- if !inputs.is_empty() {
- p.eat(&token::Comma);
- }
-
- let constraint = parse_asm_str(&mut p)?;
-
- if constraint.as_str().starts_with('=') {
- struct_span_err!(
- cx.sess.parse_sess.span_diagnostic,
- p.prev_token.span,
- E0662,
- "input operand constraint contains '='"
- )
- .emit();
- } else if constraint.as_str().starts_with('+') {
- struct_span_err!(
- cx.sess.parse_sess.span_diagnostic,
- p.prev_token.span,
- E0663,
- "input operand constraint contains '+'"
- )
- .emit();
- }
-
- p.expect(&token::OpenDelim(token::Paren))?;
- let input = p.parse_expr()?;
- p.expect(&token::CloseDelim(token::Paren))?;
-
- inputs.push((constraint, input));
- }
- }
- Clobbers => {
- while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
- if !clobs.is_empty() {
- p.eat(&token::Comma);
- }
-
- let s = parse_asm_str(&mut p)?;
-
- if OPTIONS.iter().any(|&opt| s == opt) {
- cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
- } else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
- struct_span_err!(
- cx.sess.parse_sess.span_diagnostic,
- p.prev_token.span,
- E0664,
- "clobber should not be surrounded by braces"
- )
- .emit();
- }
-
- clobs.push(s);
- }
- }
- Options => {
- let option = parse_asm_str(&mut p)?;
-
- if option == sym::volatile {
- // Indicates that the inline assembly has side effects
- // and must not be optimized out along with its outputs.
- volatile = true;
- } else if option == sym::alignstack {
- alignstack = true;
- } else if option == sym::intel {
- dialect = LlvmAsmDialect::Intel;
- } else {
- cx.span_warn(p.prev_token.span, "unrecognized option");
- }
-
- if p.token == token::Comma {
- p.eat(&token::Comma);
- }
- }
- StateNone => (),
- }
-
- loop {
- // MOD_SEP is a double colon '::' without space in between.
- // When encountered, the state must be advanced twice.
- match (&p.token.kind, state.next(), state.next().next()) {
- (&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => {
- p.bump();
- break 'statement;
- }
- (&token::Colon, st, _) | (&token::ModSep, _, st) => {
- p.bump();
- state = st;
- }
- (&token::Eof, ..) => break 'statement,
- _ => break,
- }
- }
- }
-
- Ok(Some(ast::LlvmInlineAsm {
- asm,
- asm_str_style: asm_str_style.unwrap(),
- outputs,
- inputs,
- clobbers: clobs,
- volatile,
- alignstack,
- dialect,
- }))
-}
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 6f61e4c..c9dd114 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -56,7 +56,6 @@
is_proc_macro_crate: bool,
has_proc_macro_decls: bool,
is_test_crate: bool,
- num_crate_types: usize,
handler: &rustc_errors::Handler,
) -> ast::Crate {
let ecfg = ExpansionConfig::default("proc_macro".to_string());
@@ -81,10 +80,6 @@
return krate;
}
- if num_crate_types > 1 {
- handler.err("cannot mix `proc-macro` crate type with others");
- }
-
if is_test_crate {
return krate;
}
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index e106f60..3571517 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -11,7 +11,6 @@
mut krate: ast::Crate,
resolver: &mut dyn ResolverExpand,
sess: &Session,
- alt_std_name: Option<Symbol>,
) -> ast::Crate {
let edition = sess.parse_sess.edition;
@@ -53,7 +52,7 @@
span,
ident,
vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
- ast::ItemKind::ExternCrate(alt_std_name),
+ ast::ItemKind::ExternCrate(None),
),
);
}
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index c08b141..d5991be 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -6,6 +6,7 @@
use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast_pretty::pprust;
+use rustc_errors::Applicability;
use rustc_expand::base::*;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident, Symbol};
@@ -102,11 +103,21 @@
}
};
- if let ast::ItemKind::MacCall(_) = item.kind {
- cx.sess.parse_sess.span_diagnostic.span_warn(
- item.span,
- "`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.",
- );
+ // Note: non-associated fn items are already handled by `expand_test_or_bench`
+ if !matches!(item.kind, ast::ItemKind::Fn(_)) {
+ let diag = &cx.sess.parse_sess.span_diagnostic;
+ let msg = "the `#[test]` attribute may only be used on a non-associated function";
+ let mut err = match item.kind {
+ // These were a warning before #92959 and need to continue being that to avoid breaking
+ // stable user code (#94508).
+ ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
+ _ => diag.struct_span_err(attr_sp, msg),
+ };
+ err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
+ .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
+ .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect)
+ .emit();
+
return vec![Annotatable::Item(item)];
}
@@ -252,11 +263,6 @@
"ignore",
cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
),
- // allow_fail: true | false
- field(
- "allow_fail",
- cx.expr_bool(sp, should_fail(&cx.sess, &item)),
- ),
// compile_fail: true | false
field("compile_fail", cx.expr_bool(sp, false)),
// no_run: true | false
@@ -359,10 +365,6 @@
sess.contains_name(&i.attrs, sym::ignore)
}
-fn should_fail(sess: &Session, i: &ast::Item) -> bool {
- sess.contains_name(&i.attrs, sym::allow_fail)
-}
-
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
Some(attr) => {
@@ -475,7 +477,7 @@
(false, _) => true,
}
} else {
- sd.span_err(i.span, "only functions may be used as tests");
+ // should be unreachable because `is_test_fn_item` should catch all non-fn items
false
}
}
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 65e142a..faed527 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -172,9 +172,9 @@
[[package]]
name = "indexmap"
-version = "1.7.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 3be4250..2d19040 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -19,7 +19,7 @@
object = { version = "0.27.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"
+indexmap = "1.8.0"
libloading = { version = "0.6.0", optional = true }
smallvec = "1.6.1"
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 72ebc84..a055086 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -544,7 +544,7 @@
let arg_value = drop_place.place_ref(
fx,
fx.layout_of(fx.tcx.mk_ref(
- &ty::RegionKind::ReErased,
+ fx.tcx.lifetimes.re_erased,
TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
)),
);
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index b0eb386..a099e8b 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -105,8 +105,6 @@
Ok(())
}
- fn update_symbols(&mut self) {}
-
fn build(mut self) {
enum BuilderKind {
Bsd(ar::Builder<File>),
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index b16f5af..917afa4e 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -79,7 +79,7 @@
let arg_uninhabited = fx
.mir
.args_iter()
- .any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
+ .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
if !crate::constant::check_constants(&mut fx) {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
@@ -668,7 +668,7 @@
let times = fx
.monomorphize(times)
.eval(fx.tcx, ParamEnv::reveal_all())
- .val
+ .val()
.try_to_bits(fx.tcx.data_layout.pointer_size)
.unwrap();
if operand.layout().size.bytes() == 0 {
@@ -749,18 +749,6 @@
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..) => {}
- StatementKind::LlvmInlineAsm(asm) => {
- match asm.asm.asm.as_str().trim() {
- "" => {
- // Black box
- }
- _ => fx.tcx.sess.span_fatal(
- stmt.source_info.span,
- "Legacy `llvm_asm!` inline assembly is not supported. \
- Try using the new `asm!` instead.",
- ),
- }
- }
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
StatementKind::CopyNonOverlapping(inner) => {
let dst = codegen_operand(fx, &inner.dst);
@@ -830,16 +818,16 @@
match cplace.layout().ty.kind() {
ty::Array(elem_ty, _len) => {
assert!(!from_end, "array subslices are never `from_end`");
- let elem_layout = fx.layout_of(elem_ty);
+ let elem_layout = fx.layout_of(*elem_ty);
let ptr = cplace.to_ptr();
cplace = CPlace::for_ptr(
ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
- fx.layout_of(fx.tcx.mk_array(elem_ty, to - from)),
+ fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)),
);
}
ty::Slice(elem_ty) => {
assert!(from_end, "slice subslices should be `from_end`");
- let elem_layout = fx.layout_of(elem_ty);
+ let elem_layout = fx.layout_of(*elem_ty);
let (ptr, len) = cplace.to_ptr_maybe_unsized();
let len = len.unwrap();
cplace = CPlace::for_ptr_with_extra(
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 3b6025c..50f9896 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -61,7 +61,7 @@
},
ty::FnPtr(_) => pointer_ty(tcx),
ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
- if has_ptr_meta(tcx, pointee_ty) {
+ if has_ptr_meta(tcx, *pointee_ty) {
return None;
} else {
pointer_ty(tcx)
@@ -100,7 +100,7 @@
(a, b)
}
ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
- if has_ptr_meta(tcx, pointee_ty) {
+ if has_ptr_meta(tcx, *pointee_ty) {
(pointer_ty(tcx), pointer_ty(tcx))
} else {
return None;
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 9a6c45a..274fb21 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -46,7 +46,7 @@
ConstantKind::Ty(ct) => ct,
ConstantKind::Val(..) => continue,
};
- match const_.val {
+ match const_.val() {
ConstKind::Value(_) => {}
ConstKind::Unevaluated(unevaluated) => {
if let Err(err) =
@@ -127,13 +127,15 @@
ConstantKind::Ty(ct) => ct,
ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty),
};
- let const_val = match const_.val {
+ let const_val = match const_.val() {
ConstKind::Value(const_val) => const_val,
- ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => {
- assert!(uv.substs(fx.tcx).is_empty());
- assert!(uv.promoted.is_none());
+ ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+ if fx.tcx.is_static(def.did) =>
+ {
+ assert!(substs.is_empty());
+ assert!(promoted.is_none());
- return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
+ return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty())).to_cvalue(fx);
}
ConstKind::Unevaluated(unevaluated) => {
match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
@@ -150,7 +152,7 @@
| ConstKind::Error(_) => unreachable!("{:?}", const_),
};
- codegen_const_value(fx, const_val, const_.ty)
+ codegen_const_value(fx, const_val, const_.ty())
}
pub(crate) fn codegen_const_value<'tcx>(
@@ -463,7 +465,7 @@
match operand {
Operand::Constant(const_) => match const_.literal {
ConstantKind::Ty(const_) => {
- fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
+ fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val().try_to_value()
}
ConstantKind::Val(val, _) => Some(val),
},
@@ -488,7 +490,7 @@
return None;
}
let const_val = mir_operand_get_const_val(fx, operand)?;
- if fx.layout_of(ty).size
+ if fx.layout_of(*ty).size
!= const_val.try_to_scalar_int()?.size()
{
return None;
@@ -506,7 +508,7 @@
{
return None;
}
- StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
+ StatementKind::CopyNonOverlapping(_) => {
return None;
} // conservative handling
StatementKind::Assign(_)
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 638b025..693092b 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -114,7 +114,7 @@
}
fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
- if let Some(type_id) = self.types.get(ty) {
+ if let Some(type_id) = self.types.get(&ty) {
return *type_id;
}
@@ -143,7 +143,7 @@
// Ensure that type is inserted before recursing to avoid duplicates
self.types.insert(ty, type_id);
- let pointee = self.dwarf_ty(pointee_ty);
+ let pointee = self.dwarf_ty(*pointee_ty);
let type_entry = self.dwarf.unit.get_mut(type_id);
@@ -174,7 +174,7 @@
field_entry.set(
gimli::DW_AT_name,
- AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()),
+ AttributeValue::String(field_def.name.as_str().to_string().into_bytes()),
);
field_entry.set(
gimli::DW_AT_data_member_location,
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 93384bc..c242c75 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -6,7 +6,7 @@
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir::InlineAsmOperand;
-use rustc_span::Symbol;
+use rustc_span::sym;
use rustc_target::asm::*;
pub(crate) fn codegen_inline_asm<'tcx>(
@@ -182,11 +182,7 @@
impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
fn allocate_registers(&mut self) {
let sess = self.tcx.sess;
- let map = allocatable_registers(
- self.arch,
- |feature| sess.target_features.contains(&Symbol::intern(feature)),
- &sess.target,
- );
+ let map = allocatable_registers(self.arch, &sess.target_features, &sess.target);
let mut allocated = FxHashMap::<_, (bool, bool)>::default();
let mut regs = vec![None; self.operands.len()];
@@ -319,9 +315,9 @@
// Allocate stack slots for saving clobbered registers
let abi_clobber = InlineAsmClobberAbi::parse(
self.arch,
- |feature| self.tcx.sess.target_features.contains(&Symbol::intern(feature)),
+ &self.tcx.sess.target_features,
&self.tcx.sess.target,
- Symbol::intern("C"),
+ sym::C,
)
.unwrap()
.clobbered_regs();
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index f4703b2..55c9b4d 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -90,7 +90,7 @@
match $intrinsic {
$(
sym::$name => {
- assert!($substs.is_noop());
+ assert!($substs.is_empty());
if let [$(ref $arg),*] = *$args {
let ($($arg,)*) = (
$(codegen_operand($fx, $arg),)*
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index fd96858..8cae506 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -66,7 +66,7 @@
(&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, .. })) => {
- (src, unsized_info(fx, a, b, old_info))
+ (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());
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index f29d13c..b016af5 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -514,7 +514,7 @@
// Can only happen for vector types
let len =
u16::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap();
- let vector_ty = fx.clif_type(element).unwrap().by(len).unwrap();
+ let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
let data = match from.0 {
CValueInner::ByRef(ptr, None) => {
@@ -721,8 +721,8 @@
index: Value,
) -> CPlace<'tcx> {
let (elem_layout, ptr) = match self.layout().ty.kind() {
- ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.to_ptr()),
- ty::Slice(elem_ty) => (fx.layout_of(elem_ty), self.to_ptr_maybe_unsized().0),
+ ty::Array(elem_ty, _) => (fx.layout_of(*elem_ty), self.to_ptr()),
+ ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0),
_ => bug!("place_index({:?})", self.layout().ty),
};
@@ -781,11 +781,11 @@
ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
) => {
- assert_assignable(fx, a, b);
+ assert_assignable(fx, *a, *b);
}
(ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
| (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
- assert_assignable(fx, a, b);
+ assert_assignable(fx, *a, *b);
}
(ty::FnPtr(_), ty::FnPtr(_)) => {
let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index 11dd6d4..fac532f 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -113,9 +113,6 @@
Ok(())
}
- fn update_symbols(&mut self) {
- }
-
fn build(mut self) {
use std::process::Command;
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 453bcd6..8a74c4c 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -4,9 +4,8 @@
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
-use rustc_hir::LlvmInlineAsmInner;
use rustc_middle::{bug, ty::Instance};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
use rustc_target::asm::*;
use std::borrow::Cow;
@@ -106,17 +105,6 @@
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
- fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
- self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
- .help("consider using the `asm!` macro instead")
- .emit();
-
- // We return `true` even if we've failed to generate the asm
- // because we want to suppress the "malformed inline assembly" error
- // generated by the frontend.
- true
- }
-
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
if options.contains(InlineAsmOptions::MAY_UNWIND) {
self.sess()
@@ -184,7 +172,7 @@
let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
.any(|&(_, feature)| {
if let Some(feature) = feature {
- self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+ self.tcx.sess.target_features.contains(&feature)
} else {
true // Register class is unconditionally supported
}
@@ -572,6 +560,7 @@
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::Msp430(_) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
@@ -634,6 +623,7 @@
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
+ InlineAsmRegClass::Msp430(_) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
@@ -741,6 +731,7 @@
InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(_) => unimplemented!(),
InlineAsmRegClass::Mips(_) => unimplemented!(),
+ InlineAsmRegClass::Msp430(_) => unimplemented!(),
InlineAsmRegClass::Nvptx(_) => unimplemented!(),
InlineAsmRegClass::PowerPC(_) => unimplemented!(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 379c88b..ffb77e1 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1256,7 +1256,11 @@
aggregate_value
}
- fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> {
+ fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> {
let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1");
let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
@@ -1267,11 +1271,7 @@
// rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
}
- fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) {
- // TODO(antoyo)
- }
-
- fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> {
+ fn resume(&mut self, _exn: RValue<'gcc>) {
unimplemented!();
}
@@ -1279,7 +1279,7 @@
unimplemented!();
}
- fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> {
+ fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) {
unimplemented!();
}
@@ -1287,18 +1287,15 @@
unimplemented!();
}
- fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> {
+ fn catch_switch(
+ &mut self,
+ _parent: Option<RValue<'gcc>>,
+ _unwind: Option<Block<'gcc>>,
+ _handlers: &[Block<'gcc>],
+ ) -> RValue<'gcc> {
unimplemented!();
}
- fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) {
- unimplemented!();
- }
-
- fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
- // TODO(antoyo)
- }
-
// Atomic Operations
fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index ba4589b..ddc2b88 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -144,7 +144,7 @@
// TODO(antoyo): set link section.
}
- if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+ if attrs.flags.contains(CodegenFnAttrFlags::USED) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
self.add_used_global(global.to_rvalue());
}
}
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 9c39c8f..281e49f 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -57,7 +57,7 @@
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() && !def.variants.is_empty() {
- write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+ write!(&mut name, "::{}", def.variants[index].name).unwrap();
}
}
if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index e9b66b5..8a11e3e 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -37,7 +37,7 @@
where
F: FnMut(llvm::Attribute),
{
- for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg)
+ for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg, NoUndef)
}
}
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 30d91b4..7680d4f 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -64,7 +64,7 @@
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
if tcx.sess.must_emit_unwind_tables() {
- attributes::emit_uwtable(llfn, true);
+ attributes::emit_uwtable(llfn);
}
let callee = kind.fn_name(method.name);
@@ -111,7 +111,7 @@
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
if tcx.sess.must_emit_unwind_tables() {
- attributes::emit_uwtable(llfn, true);
+ attributes::emit_uwtable(llfn);
}
let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index caf16c1..e22bec2 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -7,16 +7,13 @@
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
-use rustc_ast::LlvmAsmDialect;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::mir::operand::OperandValue;
-use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, span_bug, ty::Instance};
-use rustc_span::{Pos, Span, Symbol};
+use rustc_span::{Pos, Span};
use rustc_target::abi::*;
use rustc_target::asm::*;
@@ -24,100 +21,6 @@
use tracing::debug;
impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
- fn codegen_llvm_inline_asm(
- &mut self,
- ia: &hir::LlvmInlineAsmInner,
- outputs: Vec<PlaceRef<'tcx, &'ll Value>>,
- mut inputs: Vec<&'ll Value>,
- span: Span,
- ) -> bool {
- let mut ext_constraints = vec![];
- let mut output_types = vec![];
-
- // Prepare the output operands
- let mut indirect_outputs = vec![];
- for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() {
- if out.is_rw {
- let operand = self.load_operand(place);
- if let OperandValue::Immediate(_) = operand.val {
- inputs.push(operand.immediate());
- }
- ext_constraints.push(i.to_string());
- }
- if out.is_indirect {
- let operand = self.load_operand(place);
- if let OperandValue::Immediate(_) = operand.val {
- indirect_outputs.push(operand.immediate());
- }
- } else {
- output_types.push(place.layout.llvm_type(self.cx));
- }
- }
- if !indirect_outputs.is_empty() {
- indirect_outputs.extend_from_slice(&inputs);
- inputs = indirect_outputs;
- }
-
- let clobbers = ia.clobbers.iter().map(|s| format!("~{{{}}}", &s));
-
- // Default per-arch clobbers
- // Basically what clang does
- let arch_clobbers = match &self.sess().target.arch[..] {
- "x86" | "x86_64" => &["~{dirflag}", "~{fpsr}", "~{flags}"][..],
- "mips" | "mips64" => &["~{$1}"],
- _ => &[],
- };
-
- let all_constraints = ia
- .outputs
- .iter()
- .map(|out| out.constraint.to_string())
- .chain(ia.inputs.iter().map(|s| s.to_string()))
- .chain(ext_constraints)
- .chain(clobbers)
- .chain(arch_clobbers.iter().map(|s| (*s).to_string()))
- .collect::<Vec<String>>()
- .join(",");
-
- debug!("Asm Constraints: {}", &all_constraints);
-
- // Depending on how many outputs we have, the return type is different
- let num_outputs = output_types.len();
- let output_type = match num_outputs {
- 0 => self.type_void(),
- 1 => output_types[0],
- _ => self.type_struct(&output_types, false),
- };
-
- let asm = ia.asm.as_str();
- let r = inline_asm_call(
- self,
- &asm,
- &all_constraints,
- &inputs,
- output_type,
- ia.volatile,
- ia.alignstack,
- ia.dialect,
- &[span],
- false,
- None,
- );
- if r.is_none() {
- return false;
- }
- let r = r.unwrap();
-
- // Again, based on how many outputs we have
- let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect);
- for (i, (_, &place)) in outputs.enumerate() {
- let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) };
- OperandValue::Immediate(v).store(self, place);
- }
-
- true
- }
-
fn codegen_inline_asm(
&mut self,
template: &[InlineAsmTemplatePiece],
@@ -142,9 +45,8 @@
for &(_, feature) in reg_class.supported_types(asm_arch) {
if let Some(feature) = feature {
let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
- let feature_name = Symbol::intern(feature);
- if self.tcx.sess.target_features.contains(&feature_name)
- || codegen_fn_attrs.target_features.contains(&feature_name)
+ if self.tcx.sess.target_features.contains(&feature)
+ || codegen_fn_attrs.target_features.contains(&feature)
{
return true;
}
@@ -330,6 +232,9 @@
InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
InlineAsmArch::Bpf => {}
+ InlineAsmArch::Msp430 => {
+ constraints.push("~{sr}".to_string());
+ }
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
@@ -349,9 +254,9 @@
InlineAsmArch::X86 | InlineAsmArch::X86_64
if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
{
- LlvmAsmDialect::Intel
+ llvm::AsmDialect::Intel
}
- _ => LlvmAsmDialect::Att,
+ _ => llvm::AsmDialect::Att,
};
let result = inline_asm_call(
self,
@@ -455,7 +360,7 @@
output: &'ll llvm::Type,
volatile: bool,
alignstack: bool,
- dia: LlvmAsmDialect,
+ dia: llvm::AsmDialect,
line_spans: &[Span],
unwind: bool,
dest_catch_funclet: Option<(
@@ -498,7 +403,7 @@
cons.len(),
volatile,
alignstack,
- llvm::AsmDialect::from_generic(dia),
+ dia,
can_throw,
);
@@ -522,7 +427,7 @@
// we just encode the start position of each line.
// FIXME: Figure out a way to pass the entire line spans.
let mut srcloc = vec![];
- if dia == LlvmAsmDialect::Intel && line_spans.len() > 1 {
+ if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
// LLVM inserts an extra line to add the ".intel_syntax", so add
// a dummy srcloc entry for it.
//
@@ -678,6 +583,7 @@
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
@@ -764,6 +670,7 @@
},
InlineAsmRegClass::Avr(_) => None,
InlineAsmRegClass::S390x(_) => None,
+ InlineAsmRegClass::Msp430(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
@@ -832,6 +739,7 @@
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+ InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 7f82ce3..f6d7221 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -55,12 +55,28 @@
if enabled.contains(SanitizerSet::HWADDRESS) {
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
}
+ if enabled.contains(SanitizerSet::MEMTAG) {
+ // Check to make sure the mte target feature is actually enabled.
+ let sess = cx.tcx.sess;
+ let features = llvm_util::llvm_global_features(sess).join(",");
+ let mte_feature_enabled = features.rfind("+mte");
+ let mte_feature_disabled = features.rfind("-mte");
+
+ if mte_feature_enabled.is_none() || (mte_feature_disabled > mte_feature_enabled) {
+ sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`");
+ }
+
+ llvm::Attribute::SanitizeMemTag.apply_llfn(Function, llfn);
+ }
}
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
#[inline]
-pub fn emit_uwtable(val: &Value, emit: bool) {
- Attribute::UWTable.toggle_llfn(Function, val, emit);
+pub fn emit_uwtable(val: &Value) {
+ // NOTE: We should determine if we even need async unwind tables, as they
+ // take have more overhead and if we can use sync unwind tables we
+ // probably should.
+ llvm::EmitUWTableAttr(val, true);
}
/// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
@@ -275,7 +291,7 @@
// You can also find more info on why Windows always requires uwtables here:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
if cx.sess().must_emit_unwind_tables() {
- attributes::emit_uwtable(llfn, true);
+ attributes::emit_uwtable(llfn);
}
if cx.sess().opts.debugging_opts.profile_sample_use.is_some() {
@@ -322,12 +338,33 @@
// The target doesn't care; the subtarget reads our attribute.
apply_tune_cpu_attr(cx, llfn);
- let mut function_features = codegen_fn_attrs
- .target_features
+ let function_features =
+ codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
+
+ if let Some(f) = llvm_util::check_tied_features(
+ cx.tcx.sess,
+ &function_features.iter().map(|f| (*f, true)).collect(),
+ ) {
+ let span = cx
+ .tcx
+ .get_attrs(instance.def_id())
+ .iter()
+ .find(|a| a.has_name(rustc_span::sym::target_feature))
+ .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
+ let msg = format!(
+ "the target features {} must all be either enabled or disabled together",
+ f.join(", ")
+ );
+ let mut err = cx.tcx.sess.struct_span_err(span, &msg);
+ err.help("add the missing features in a `target_feature` attribute");
+ err.emit();
+ return;
+ }
+
+ let mut function_features = function_features
.iter()
- .flat_map(|f| {
- let feature = f.as_str();
- llvm_util::to_llvm_feature(cx.tcx.sess, feature)
+ .flat_map(|feat| {
+ llvm_util::to_llvm_feature(cx.tcx.sess, feat)
.into_iter()
.map(|f| format!("+{}", f))
.collect::<Vec<String>>()
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 2fb5a0f..21bd1da 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -1,6 +1,7 @@
//! A helper class for dealing with static archives
-use std::ffi::{CStr, CString};
+use std::env;
+use std::ffi::{CStr, CString, OsString};
use std::io;
use std::mem;
use std::path::{Path, PathBuf};
@@ -26,7 +27,6 @@
config: ArchiveConfig<'a>,
removals: Vec<String>,
additions: Vec<Addition>,
- should_update_symbols: bool,
src_archive: Option<Option<ArchiveRO>>,
}
@@ -74,7 +74,6 @@
config,
removals: Vec::new(),
additions: Vec::new(),
- should_update_symbols: false,
src_archive: None,
}
}
@@ -128,12 +127,6 @@
.push(Addition::File { path: file.to_path_buf(), name_in_archive: name.to_owned() });
}
- /// Indicate that the next call to `build` should update all symbols in
- /// the archive (equivalent to running 'ar s' over it).
- fn update_symbols(&mut self) {
- self.should_update_symbols = true;
- }
-
/// Combine the provided files, rlibs, and native libraries into a single
/// `Archive`.
fn build(mut self) {
@@ -158,55 +151,128 @@
output_path.with_extension("lib")
};
- // we've checked for \0 characters in the library name already
- let dll_name_z = CString::new(lib_name).unwrap();
- // All import names are Rust identifiers and therefore cannot contain \0 characters.
- // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
- // have any \0 characters
- let import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> = dll_imports
+ let mingw_gnu_toolchain = self.config.sess.target.llvm_target.ends_with("pc-windows-gnu");
+
+ let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
.iter()
.map(|import: &DllImport| {
if self.config.sess.target.arch == "x86" {
- (LlvmArchiveBuilder::i686_decorated_name(import), import.ordinal)
+ (
+ LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
+ import.ordinal,
+ )
} else {
- (CString::new(import.name.to_string()).unwrap(), import.ordinal)
+ (import.name.to_string(), import.ordinal)
}
})
.collect();
- let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+ if mingw_gnu_toolchain {
+ // The binutils linker used on -windows-gnu targets cannot read the import
+ // libraries generated by LLVM: in our attempts, the linker produced an .EXE
+ // that loaded but crashed with an AV upon calling one of the imported
+ // functions. Therefore, use binutils to create the import library instead,
+ // by writing a .DEF file to the temp dir and calling binutils's dlltool.
+ let def_file_path =
+ tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
- tracing::trace!("invoking LLVMRustWriteImportLibrary");
- tracing::trace!(" dll_name {:#?}", dll_name_z);
- tracing::trace!(" output_path {}", output_path.display());
- tracing::trace!(
- " import names: {}",
- dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
- );
+ let def_file_content = format!(
+ "EXPORTS\n{}",
+ import_name_and_ordinal_vector
+ .into_iter()
+ .map(|(name, ordinal)| {
+ match ordinal {
+ Some(n) => format!("{} @{} NONAME", name, n),
+ None => name,
+ }
+ })
+ .collect::<Vec<String>>()
+ .join("\n")
+ );
- let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_and_ordinal_vector
- .iter()
- .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
- .collect();
- let result = unsafe {
- crate::llvm::LLVMRustWriteImportLibrary(
- dll_name_z.as_ptr(),
- output_path_z.as_ptr(),
- ffi_exports.as_ptr(),
- ffi_exports.len(),
- llvm_machine_type(&self.config.sess.target.arch) as u16,
- !self.config.sess.target.is_like_msvc,
- )
+ match std::fs::write(&def_file_path, def_file_content) {
+ Ok(_) => {}
+ Err(e) => {
+ self.config.sess.fatal(&format!("Error writing .DEF file: {}", e));
+ }
+ };
+
+ let dlltool = find_binutils_dlltool(self.config.sess);
+ let result = std::process::Command::new(dlltool)
+ .args([
+ "-d",
+ def_file_path.to_str().unwrap(),
+ "-D",
+ lib_name,
+ "-l",
+ output_path.to_str().unwrap(),
+ ])
+ .output();
+
+ match result {
+ Err(e) => {
+ self.config.sess.fatal(&format!("Error calling dlltool: {}", e));
+ }
+ Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
+ "Dlltool could not create import library: {}\n{}",
+ String::from_utf8_lossy(&output.stdout),
+ String::from_utf8_lossy(&output.stderr)
+ )),
+ _ => {}
+ }
+ } else {
+ // we've checked for \0 characters in the library name already
+ let dll_name_z = CString::new(lib_name).unwrap();
+
+ let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+
+ tracing::trace!("invoking LLVMRustWriteImportLibrary");
+ tracing::trace!(" dll_name {:#?}", dll_name_z);
+ tracing::trace!(" output_path {}", output_path.display());
+ tracing::trace!(
+ " import names: {}",
+ dll_imports
+ .iter()
+ .map(|import| import.name.to_string())
+ .collect::<Vec<_>>()
+ .join(", "),
+ );
+
+ // All import names are Rust identifiers and therefore cannot contain \0 characters.
+ // FIXME: when support for #[link_name] is implemented, ensure that the import names
+ // still don't contain any \0 characters. Also need to check that the names don't
+ // contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
+ // in definition files.
+ let cstring_import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> =
+ import_name_and_ordinal_vector
+ .into_iter()
+ .map(|(name, ordinal)| (CString::new(name).unwrap(), ordinal))
+ .collect();
+
+ let ffi_exports: Vec<LLVMRustCOFFShortExport> = cstring_import_name_and_ordinal_vector
+ .iter()
+ .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
+ .collect();
+ let result = unsafe {
+ crate::llvm::LLVMRustWriteImportLibrary(
+ dll_name_z.as_ptr(),
+ output_path_z.as_ptr(),
+ ffi_exports.as_ptr(),
+ ffi_exports.len(),
+ llvm_machine_type(&self.config.sess.target.arch) as u16,
+ !self.config.sess.target.is_like_msvc,
+ )
+ };
+
+ if result == crate::llvm::LLVMRustResult::Failure {
+ self.config.sess.fatal(&format!(
+ "Error creating import library for {}: {}",
+ lib_name,
+ llvm::last_error().unwrap_or("unknown LLVM error".to_string())
+ ));
+ }
};
- if result == crate::llvm::LLVMRustResult::Failure {
- self.config.sess.fatal(&format!(
- "Error creating import library for {}: {}",
- lib_name,
- llvm::last_error().unwrap_or("unknown LLVM error".to_string())
- ));
- }
-
self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
self.config.sess.fatal(&format!(
"failed to add native library {}: {}",
@@ -239,7 +305,6 @@
let mut members = Vec::new();
let dst = CString::new(self.config.dst.to_str().unwrap())?;
- let should_update_symbols = self.should_update_symbols;
unsafe {
if let Some(archive) = self.src_archive() {
@@ -311,7 +376,7 @@
dst.as_ptr(),
members.len() as libc::size_t,
members.as_ptr() as *const &_,
- should_update_symbols,
+ true,
kind,
);
let ret = if r.into_result().is_err() {
@@ -332,22 +397,61 @@
}
}
- fn i686_decorated_name(import: &DllImport) -> CString {
+ fn i686_decorated_name(import: &DllImport, mingw: bool) -> String {
let name = import.name;
- // We verified during construction that `name` does not contain any NULL characters, so the
- // conversion to CString is guaranteed to succeed.
- CString::new(match import.calling_convention {
- DllCallingConvention::C => format!("_{}", name),
- DllCallingConvention::Stdcall(arg_list_size) => format!("_{}@{}", name, arg_list_size),
+ let prefix = if mingw { "" } else { "_" };
+
+ match import.calling_convention {
+ DllCallingConvention::C => format!("{}{}", prefix, name),
+ DllCallingConvention::Stdcall(arg_list_size) => {
+ format!("{}{}@{}", prefix, name, arg_list_size)
+ }
DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
DllCallingConvention::Vectorcall(arg_list_size) => {
format!("{}@@{}", name, arg_list_size)
}
- })
- .unwrap()
+ }
}
}
fn string_to_io_error(s: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
}
+
+fn find_binutils_dlltool(sess: &Session) -> OsString {
+ assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
+ if let Some(dlltool_path) = &sess.opts.debugging_opts.dlltool {
+ return dlltool_path.clone().into_os_string();
+ }
+
+ let mut tool_name: OsString = if sess.host.arch != sess.target.arch {
+ // We are cross-compiling, so we need the tool with the prefix matching our target
+ if sess.target.arch == "x86" {
+ "i686-w64-mingw32-dlltool"
+ } else {
+ "x86_64-w64-mingw32-dlltool"
+ }
+ } else {
+ // We are not cross-compiling, so we just want `dlltool`
+ "dlltool"
+ }
+ .into();
+
+ if sess.host.options.is_like_windows {
+ // If we're compiling on Windows, add the .exe suffix
+ tool_name.push(".exe");
+ }
+
+ // NOTE: it's not clear how useful it is to explicitly search PATH.
+ for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
+ let full_path = dir.join(&tool_name);
+ if full_path.is_file() {
+ return full_path.into_os_string();
+ }
+ }
+
+ // The user didn't specify the location of the dlltool binary, and we weren't able
+ // to find the appropriate one on the PATH. Just return the name of the tool
+ // and let the invocation fail with a hopefully useful error message.
+ tool_name
+}
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index ddba43c..6afa649 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -349,13 +349,6 @@
);
save_temp_bitcode(cgcx, &module, "lto.after-restriction");
}
-
- if cgcx.no_landing_pads {
- unsafe {
- llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
- }
- save_temp_bitcode(cgcx, &module, "lto.after-nounwind");
- }
}
Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
@@ -770,16 +763,6 @@
return Err(write::llvm_err(&diag_handler, msg));
}
- // Like with "fat" LTO, get some better optimizations if landing pads
- // are disabled by removing all landing pads.
- if cgcx.no_landing_pads {
- let _timer = cgcx
- .prof
- .generic_activity_with_arg("LLVM_thin_lto_remove_landing_pads", thin_module.name());
- llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
- save_temp_bitcode(cgcx, &module, "thin-lto-after-nounwind");
- }
-
// Up next comes the per-module local analyses that we do for Thin LTO.
// Each of these functions is basically copied from the LLVM
// implementation and then tailored to suit this implementation. Ideally
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5217fa2..c9a04e6 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -731,27 +731,11 @@
}
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if !self.fptoint_sat_broken_in_llvm() {
- let src_ty = self.cx.val_ty(val);
- 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);
- return Some(self.call_intrinsic(&name, &[val]));
- }
-
- None
+ self.fptoint_sat(false, val, dest_ty)
}
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if !self.fptoint_sat_broken_in_llvm() {
- let src_ty = self.cx.val_ty(val);
- 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);
- return Some(self.call_intrinsic(&name, &[val]));
- }
-
- None
+ self.fptoint_sat(true, val, dest_ty)
}
fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -972,29 +956,24 @@
unsafe { llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint, UNNAMED) }
}
- fn landing_pad(
- &mut self,
- ty: &'ll Type,
- pers_fn: &'ll Value,
- num_clauses: usize,
- ) -> &'ll Value {
- // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while,
- // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The
- // personality lives on the parent function anyway.
- self.set_personality_fn(pers_fn);
+ fn set_personality_fn(&mut self, personality: &'ll Value) {
unsafe {
- llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
+ llvm::LLVMSetPersonalityFn(self.llfn(), personality);
}
}
- fn set_cleanup(&mut self, landing_pad: &'ll Value) {
+ fn cleanup_landing_pad(&mut self, ty: &'ll Type, pers_fn: &'ll Value) -> &'ll Value {
+ let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */);
unsafe {
llvm::LLVMSetCleanup(landing_pad, llvm::True);
}
+ landing_pad
}
- fn resume(&mut self, exn: &'ll Value) -> &'ll Value {
- unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) }
+ fn resume(&mut self, exn: &'ll Value) {
+ unsafe {
+ llvm::LLVMBuildResume(self.llbuilder, exn);
+ }
}
fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> {
@@ -1011,14 +990,11 @@
Funclet::new(ret.expect("LLVM does not have support for cleanuppad"))
}
- fn cleanup_ret(
- &mut self,
- funclet: &Funclet<'ll>,
- unwind: Option<&'ll BasicBlock>,
- ) -> &'ll Value {
- let ret =
- unsafe { llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) };
- ret.expect("LLVM does not have support for cleanupret")
+ fn cleanup_ret(&mut self, funclet: &Funclet<'ll>, unwind: Option<&'ll BasicBlock>) {
+ unsafe {
+ llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind)
+ .expect("LLVM does not have support for cleanupret");
+ }
}
fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> {
@@ -1039,7 +1015,7 @@
&mut self,
parent: Option<&'ll Value>,
unwind: Option<&'ll BasicBlock>,
- num_handlers: usize,
+ handlers: &[&'ll BasicBlock],
) -> &'ll Value {
let name = cstr!("catchswitch");
let ret = unsafe {
@@ -1047,23 +1023,17 @@
self.llbuilder,
parent,
unwind,
- num_handlers as c_uint,
+ handlers.len() as c_uint,
name.as_ptr(),
)
};
- ret.expect("LLVM does not have support for catchswitch")
- }
-
- fn add_handler(&mut self, catch_switch: &'ll Value, handler: &'ll BasicBlock) {
- unsafe {
- llvm::LLVMRustAddHandler(catch_switch, handler);
+ let ret = ret.expect("LLVM does not have support for catchswitch");
+ for handler in handlers {
+ unsafe {
+ llvm::LLVMRustAddHandler(ret, handler);
+ }
}
- }
-
- fn set_personality_fn(&mut self, personality: &'ll Value) {
- unsafe {
- llvm::LLVMSetPersonalityFn(self.llfn(), personality);
- }
+ ret
}
// Atomic Operations
@@ -1455,4 +1425,58 @@
_ => false,
}
}
+
+ fn fptoint_sat(
+ &mut self,
+ signed: bool,
+ val: &'ll Value,
+ dest_ty: &'ll Type,
+ ) -> Option<&'ll Value> {
+ if !self.fptoint_sat_broken_in_llvm() {
+ let src_ty = self.cx.val_ty(val);
+ let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector
+ {
+ assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
+ (
+ self.cx.element_type(src_ty),
+ self.cx.element_type(dest_ty),
+ Some(self.cx.vector_length(src_ty)),
+ )
+ } else {
+ (src_ty, dest_ty, None)
+ };
+ let float_width = self.cx.float_width(float_ty);
+ let int_width = self.cx.int_width(int_ty);
+
+ let instr = if signed { "fptosi" } else { "fptoui" };
+ let name = if let Some(vector_length) = vector_length {
+ format!(
+ "llvm.{}.sat.v{}i{}.v{}f{}",
+ instr, vector_length, int_width, vector_length, float_width
+ )
+ } else {
+ format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
+ };
+ let f =
+ self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
+ Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None))
+ } else {
+ None
+ }
+ }
+
+ pub(crate) fn landing_pad(
+ &mut self,
+ ty: &'ll Type,
+ pers_fn: &'ll Value,
+ num_clauses: usize,
+ ) -> &'ll Value {
+ // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while,
+ // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The
+ // personality lives on the parent function anyway.
+ self.set_personality_fn(pers_fn);
+ unsafe {
+ llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
+ }
+ }
}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index d43c7c6..6707de9 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -522,6 +522,9 @@
}
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+ // `USED` and `USED_LINKER` can't be used together.
+ assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
+
// 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.
@@ -530,6 +533,12 @@
// in some versions of the gold linker.
self.add_compiler_used_global(g);
}
+ if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
+ // `USED` and `USED_LINKER` can't be used together.
+ assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED));
+
+ self.add_used_global(g);
+ }
}
}
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 9f24a95..ddc8d72 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -21,7 +21,8 @@
};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
-use rustc_session::config::{CFGuard, CrateType, DebugInfo};
+use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
+use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
use rustc_session::Session;
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
@@ -134,7 +135,8 @@
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
let mut target_data_layout = sess.target.data_layout.clone();
- if llvm_util::get_version() < (13, 0, 0) {
+ let llvm_version = llvm_util::get_version();
+ if llvm_version < (13, 0, 0) {
if sess.target.arch == "powerpc64" {
target_data_layout = target_data_layout.replace("-S128", "");
}
@@ -145,6 +147,18 @@
target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string();
}
}
+ if llvm_version < (14, 0, 0) {
+ if sess.target.llvm_target == "i686-pc-windows-msvc"
+ || sess.target.llvm_target == "i586-pc-windows-msvc"
+ {
+ target_data_layout =
+ "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-a:0:32-S32"
+ .to_string();
+ }
+ if sess.target.arch == "wasm32" {
+ target_data_layout = target_data_layout.replace("-p10:8:8-p20:8:8", "");
+ }
+ }
// Ensure the data-layout values hardcoded remain the defaults.
if sess.target.is_builtin {
@@ -215,16 +229,19 @@
// to ensure intrinsic calls don't use it.
if !sess.needs_plt() {
let avoid_plt = "RtLibUseGOT\0".as_ptr().cast();
- llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
+ llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
}
if sess.is_sanitizer_cfi_enabled() {
// FIXME(rcvalle): Add support for non canonical jump tables.
let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
- // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
- // Warning behavior flag. Add support for specifying the behavior flag to
- // LLVMRustAddModuleFlag.
- llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
+ // FIXME(rcvalle): Add it with Override behavior flag.
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Warning,
+ canonical_jump_tables,
+ 1,
+ );
}
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
@@ -233,15 +250,75 @@
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
- llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 1)
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Warning,
+ "cfguard\0".as_ptr() as *const _,
+ 1,
+ )
}
CFGuard::Checks => {
// Set `cfguard=2` module flag to emit metadata and checks.
- llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 2)
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Warning,
+ "cfguard\0".as_ptr() as *const _,
+ 2,
+ )
}
}
}
+ if let Some(BranchProtection { bti, pac_ret }) = sess.opts.debugging_opts.branch_protection {
+ if sess.target.arch != "aarch64" {
+ sess.err("-Zbranch-protection is only supported on aarch64");
+ } else {
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Error,
+ "branch-target-enforcement\0".as_ptr().cast(),
+ bti.into(),
+ );
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Error,
+ "sign-return-address\0".as_ptr().cast(),
+ pac_ret.is_some().into(),
+ );
+ let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Error,
+ "sign-return-address-all\0".as_ptr().cast(),
+ pac_opts.leaf.into(),
+ );
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Error,
+ "sign-return-address-with-bkey\0".as_ptr().cast(),
+ u32::from(pac_opts.key == PAuthKey::B),
+ );
+ }
+ }
+
+ // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
+ if let CFProtection::Branch | CFProtection::Full = sess.opts.debugging_opts.cf_protection {
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Override,
+ "cf-protection-branch\0".as_ptr().cast(),
+ 1,
+ )
+ }
+ if let CFProtection::Return | CFProtection::Full = sess.opts.debugging_opts.cf_protection {
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Override,
+ "cf-protection-return\0".as_ptr().cast(),
+ 1,
+ )
+ }
+
llmod
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index e0af565..58f3916 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -5,12 +5,14 @@
use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefIdSet;
use rustc_llvm::RustString;
+use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::CodeRegion;
use rustc_middle::ty::TyCtxt;
-use rustc_span::Symbol;
use std::ffi::CString;
@@ -37,7 +39,7 @@
// LLVM 12.
let version = coverageinfo::mapping_version();
if version < 4 {
- tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher.");
+ tcx.sess.fatal("rustc option `-C instrument-coverage` requires LLVM 12 or higher.");
}
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
@@ -46,7 +48,7 @@
// functions exist. Generate synthetic functions with a (required) single counter, and add the
// MIR `Coverage` code regions to the `function_coverage_map`, before calling
// `ctx.take_function_coverage_map()`.
- if !tcx.sess.instrument_coverage_except_unused_functions() {
+ if cx.codegen_unit.is_code_coverage_dead_code_cgu() {
add_unused_functions(cx);
}
@@ -75,10 +77,18 @@
let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
});
- debug_assert!(
- !coverage_mapping_buffer.is_empty(),
- "Every `FunctionCoverage` should have at least one counter"
- );
+
+ if coverage_mapping_buffer.is_empty() {
+ if function_coverage.is_used() {
+ bug!(
+ "A used function should have had coverage mapping data but did not: {}",
+ mangled_function_name
+ );
+ } else {
+ debug!("unused function had no coverage mapping data: {}", mangled_function_name);
+ continue;
+ }
+ }
function_data.push((mangled_function_name, source_hash, is_used, coverage_mapping_buffer));
}
@@ -264,33 +274,42 @@
/// (functions referenced by other "used" or public items). Any other functions considered unused,
/// or "Unreachable", were still parsed and processed through the MIR stage, but were not
/// codegenned. (Note that `-Clink-dead-code` can force some unused code to be codegenned, but
-/// that flag is known to cause other errors, when combined with `-Z instrument-coverage`; and
+/// that flag is known to cause other errors, when combined with `-C instrument-coverage`; and
/// `-Clink-dead-code` will not generate code for unused generic functions.)
///
/// We can find the unused functions (including generic functions) by the set difference of all MIR
/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
/// `codegened_and_inlined_items`).
///
-/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and
-/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`)
-/// allocated to only one of those CGUs. We must NOT inject any unused functions's `CodeRegion`s
-/// more than once, so we have to pick a CGUs `function_coverage_map` into which the unused
-/// function will be inserted.
+/// These unused functions are then codegen'd in one of the CGUs which is marked as the
+/// "code coverage dead code cgu" during the partitioning process. This prevents us from generating
+/// code regions for the same function more than once which can lead to linker errors regarding
+/// duplicate symbols.
fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
- let tcx = cx.tcx;
+ assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
- // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources
- // of compiler state data that might help (or better sources that could be exposed, but
- // aren't yet)?
+ let tcx = cx.tcx;
let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
- let all_def_ids: DefIdSet = tcx
+ let eligible_def_ids: DefIdSet = tcx
.mir_keys(())
.iter()
.filter_map(|local_def_id| {
let def_id = local_def_id.to_def_id();
- if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
+ let kind = tcx.def_kind(def_id);
+ // `mir_keys` will give us `DefId`s for all kinds of things, not
+ // just "functions", like consts, statics, etc. Filter those out.
+ // If `ignore_unused_generics` was specified, filter out any
+ // generic functions from consideration as well.
+ if !matches!(
+ kind,
+ DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator
+ ) {
+ return None;
+ } else if ignore_unused_generics
+ && tcx.generics_of(def_id).requires_monomorphization(tcx)
+ {
return None;
}
Some(local_def_id.to_def_id())
@@ -299,79 +318,17 @@
let codegenned_def_ids = tcx.codegened_and_inlined_items(());
- let mut unused_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default();
- for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) {
- // Make sure the non-codegenned (unused) function has at least one MIR
- // `Coverage` statement with a code region, and return its file name.
- if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
- let def_ids =
- unused_def_ids_by_file.entry(*non_codegenned_file_name).or_insert_with(Vec::new);
- def_ids.push(non_codegenned_def_id);
+ for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) {
+ let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
+
+ // If a function is marked `#[no_coverage]`, then skip generating a
+ // dead code stub for it.
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+ debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id);
+ continue;
}
- }
- if unused_def_ids_by_file.is_empty() {
- // There are no unused functions with file names to add (in any CGU)
- return;
- }
-
- // Each `CodegenUnit` (CGU) has its own function_coverage_map, and generates a specific binary
- // with its own coverage map.
- //
- // Each covered function `Instance` can be included in only one coverage map, produced from a
- // specific function_coverage_map, from a specific CGU.
- //
- // Since unused functions did not generate code, they are not associated with any CGU yet.
- //
- // To avoid injecting the unused functions in multiple coverage maps (for multiple CGUs)
- // determine which function_coverage_map has the responsibility for publishing unreachable
- // coverage, based on file name: For each unused function, find the CGU that generates the
- // first function (based on sorted `DefId`) from the same file.
- //
- // Add a new `FunctionCoverage` to the `function_coverage_map`, with unreachable code regions
- // for each region in it's MIR.
-
- // Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them.
- let mut sorted_codegenned_def_ids: Vec<DefId> = codegenned_def_ids.iter().copied().collect();
- sorted_codegenned_def_ids.sort_unstable();
-
- let mut first_covered_def_id_by_file: FxHashMap<Symbol, DefId> = FxHashMap::default();
- for &def_id in sorted_codegenned_def_ids.iter() {
- if let Some(covered_file_name) = tcx.covered_file_name(def_id) {
- // Only add files known to have unused functions
- if unused_def_ids_by_file.contains_key(covered_file_name) {
- first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id);
- }
- }
- }
-
- // Get the set of def_ids with coverage regions, known by *this* CoverageContext.
- let cgu_covered_def_ids: DefIdSet = match cx.coverage_context() {
- Some(ctx) => ctx
- .function_coverage_map
- .borrow()
- .keys()
- .map(|&instance| instance.def.def_id())
- .collect(),
- None => return,
- };
-
- let cgu_covered_files: FxHashSet<Symbol> = first_covered_def_id_by_file
- .iter()
- .filter_map(
- |(&file_name, def_id)| {
- if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None }
- },
- )
- .collect();
-
- // For each file for which this CGU is responsible for adding unused function coverage,
- // get the `def_id`s for each unused function (if any), define a synthetic function with a
- // single LLVM coverage counter, and add the function's coverage `CodeRegion`s. to the
- // function_coverage_map.
- for covered_file_name in cgu_covered_files {
- for def_id in unused_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() {
- cx.define_unused_fn(def_id);
- }
+ debug!("generating unused fn: {:?}", non_codegenned_def_id);
+ cx.define_unused_fn(non_codegenned_def_id);
}
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 60ff18a..1abc3fb 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -10,6 +10,8 @@
use crate::abi;
use crate::common::CodegenCx;
+use crate::debuginfo::utils::fat_pointer_kind;
+use crate::debuginfo::utils::FatPtrKind;
use crate::llvm;
use crate::llvm::debuginfo::{
DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
@@ -19,6 +21,7 @@
use cstr::cstr;
use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
+use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
@@ -27,18 +30,18 @@
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::bug;
use rustc_middle::mir::{self, GeneratorLayout};
use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{
self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES,
};
-use rustc_middle::{bug, span_bug};
use rustc_query_system::ich::NodeIdHashingMode;
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::Symbol;
use rustc_span::FileNameDisplayPreference;
-use rustc_span::{self, SourceFile, SourceFileHash, Span};
+use rustc_span::{self, SourceFile, SourceFileHash};
use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding};
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
@@ -182,9 +185,9 @@
///
/// This function is used to remove the temporary metadata
/// mapping after we've computed the actual metadata.
- fn remove_type(&mut self, type_: Ty<'tcx>) {
- if self.type_to_metadata.remove(type_).is_none() {
- bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", type_);
+ fn remove_type(&mut self, ty: Ty<'tcx>) {
+ if self.type_to_metadata.remove(&ty).is_none() {
+ bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", ty);
}
}
@@ -274,6 +277,12 @@
) -> String {
format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id))
}
+
+ /// Gets the `UniqueTypeId` for the type of a vtable.
+ fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> UniqueTypeId {
+ let interner_key = self.unique_id_interner.intern(vtable_type_name);
+ interner_key
+ }
}
/// A description of some recursive type. It can either be already finished (as
@@ -349,14 +358,15 @@
// ... then create the member descriptions ...
let member_descriptions = member_description_factory.create_member_descriptions(cx);
+ let type_params = compute_type_parameters(cx, unfinished_type);
// ... and attach them to the stub to complete it.
set_members_of_composite_type(
cx,
- unfinished_type,
member_holding_stub,
member_descriptions,
None,
+ type_params,
);
MetadataCreationResult::new(metadata_stub, true)
}
@@ -376,23 +386,24 @@
};
}
-fn fixed_vec_metadata<'ll, 'tcx>(
+/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`).
+/// For slices (that is, "arrays" of unknown size) use [slice_type_metadata].
+fn fixed_size_array_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId,
- array_or_slice_type: Ty<'tcx>,
- element_type: Ty<'tcx>,
- span: Span,
+ array_type: Ty<'tcx>,
) -> MetadataCreationResult<'ll> {
- let element_type_metadata = type_metadata(cx, element_type, span);
+ let ty::Array(element_type, len) = array_type.kind() else {
+ bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type)
+ };
+
+ let element_type_metadata = type_metadata(cx, *element_type);
return_if_metadata_created_in_meantime!(cx, unique_type_id);
- let (size, align) = cx.size_and_align_of(array_or_slice_type);
+ let (size, align) = cx.size_and_align_of(array_type);
- let upper_bound = match array_or_slice_type.kind() {
- ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
- _ => -1,
- };
+ let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
let subrange =
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
@@ -411,67 +422,117 @@
MetadataCreationResult::new(metadata, false)
}
-fn vec_slice_metadata<'ll, 'tcx>(
+/// Creates debuginfo for built-in pointer-like things:
+///
+/// - ty::Ref
+/// - ty::RawPtr
+/// - ty::Adt in the case it's Box
+///
+/// At some point we might want to remove the special handling of Box
+/// and treat it the same as other smart pointers (like Rc, Arc, ...).
+fn pointer_or_reference_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
- slice_ptr_type: Ty<'tcx>,
- element_type: Ty<'tcx>,
+ ptr_type: Ty<'tcx>,
+ pointee_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
- span: Span,
) -> MetadataCreationResult<'ll> {
- let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
-
- let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
+ let pointee_type_metadata = type_metadata(cx, pointee_type);
return_if_metadata_created_in_meantime!(cx, unique_type_id);
- let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true);
+ let (thin_pointer_size, thin_pointer_align) =
+ cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit));
+ let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
- let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
- let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
+ let pointer_type_metadata = match fat_pointer_kind(cx, pointee_type) {
+ None => {
+ // This is a thin pointer. Create a regular pointer type and give it the correct name.
+ debug_assert_eq!(
+ (thin_pointer_size, thin_pointer_align),
+ cx.size_and_align_of(ptr_type)
+ );
- let member_descriptions = vec![
- MemberDescription {
- name: "data_ptr".to_owned(),
- type_metadata: data_ptr_metadata,
- offset: Size::ZERO,
- size: pointer_size,
- align: pointer_align,
- flags: DIFlags::FlagZero,
- discriminant: None,
- source_info: None,
- },
- MemberDescription {
- name: "length".to_owned(),
- type_metadata: type_metadata(cx, cx.tcx.types.usize, span),
- offset: pointer_size,
- size: usize_size,
- align: usize_align,
- flags: DIFlags::FlagZero,
- discriminant: None,
- source_info: None,
- },
- ];
+ unsafe {
+ llvm::LLVMRustDIBuilderCreatePointerType(
+ DIB(cx),
+ pointee_type_metadata,
+ thin_pointer_size.bits(),
+ thin_pointer_align.bits() as u32,
+ 0, // Ignore DWARF address space.
+ ptr_type_debuginfo_name.as_ptr().cast(),
+ ptr_type_debuginfo_name.len(),
+ )
+ }
+ }
+ Some(fat_pointer_kind) => {
+ let layout = cx.layout_of(ptr_type);
- let file_metadata = unknown_file_metadata(cx);
+ let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
+ let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
- let metadata = composite_type_metadata(
- cx,
- slice_ptr_type,
- &slice_type_name,
- unique_type_id,
- member_descriptions,
- NO_SCOPE_METADATA,
- file_metadata,
- span,
- );
- MetadataCreationResult::new(metadata, false)
+ let (addr_field_name, extra_field_name) = match fat_pointer_kind {
+ FatPtrKind::Dyn => ("pointer", "vtable"),
+ FatPtrKind::Slice => ("data_ptr", "length"),
+ };
+
+ debug_assert_eq!(abi::FAT_PTR_ADDR, 0);
+ debug_assert_eq!(abi::FAT_PTR_EXTRA, 1);
+
+ // The data pointer type is a regular, thin pointer, regardless of whether this is a slice
+ // or a trait object.
+ let data_ptr_type_metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreatePointerType(
+ DIB(cx),
+ pointee_type_metadata,
+ addr_field.size.bits(),
+ addr_field.align.abi.bits() as u32,
+ 0, // Ignore DWARF address space.
+ std::ptr::null(),
+ 0,
+ )
+ };
+
+ let member_descriptions = vec![
+ MemberDescription {
+ name: addr_field_name.into(),
+ type_metadata: data_ptr_type_metadata,
+ offset: layout.fields.offset(abi::FAT_PTR_ADDR),
+ size: addr_field.size,
+ align: addr_field.align.abi,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ },
+ MemberDescription {
+ name: extra_field_name.into(),
+ type_metadata: type_metadata(cx, extra_field.ty),
+ offset: layout.fields.offset(abi::FAT_PTR_EXTRA),
+ size: extra_field.size,
+ align: extra_field.align.abi,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ },
+ ];
+
+ composite_type_metadata(
+ cx,
+ ptr_type,
+ &ptr_type_debuginfo_name,
+ unique_type_id,
+ member_descriptions,
+ NO_SCOPE_METADATA,
+ )
+ }
+ };
+
+ MetadataCreationResult { metadata: pointer_type_metadata, already_stored_in_typemap: false }
}
fn subroutine_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId,
signature: ty::PolyFnSig<'tcx>,
- span: Span,
) -> MetadataCreationResult<'ll> {
let signature =
cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature);
@@ -480,12 +541,12 @@
// return type
match signature.output().kind() {
ty::Tuple(tys) if tys.is_empty() => None,
- _ => Some(type_metadata(cx, signature.output(), span)),
+ _ => Some(type_metadata(cx, signature.output())),
},
)
.chain(
// regular arguments
- signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type, span))),
+ signature.inputs().iter().map(|&argument_type| Some(type_metadata(cx, argument_type))),
)
.collect();
@@ -502,98 +563,60 @@
)
}
-// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
-// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
-// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
-// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
-// of a DST struct, there is no `trait_object_type` and the results of this
-// function will be a little bit weird.
-fn trait_pointer_metadata<'ll, 'tcx>(
+/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
+/// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
+fn dyn_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
- trait_type: Ty<'tcx>,
- trait_object_type: Option<Ty<'tcx>>,
+ dyn_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
) -> &'ll DIType {
- // The implementation provided here is a stub. It makes sure that the trait
- // type is assigned the correct name, size, namespace, and source location.
- // However, it does not describe the trait's methods.
-
- let (containing_scope, trait_type_name) = match trait_object_type {
- Some(trait_object_type) => match trait_object_type.kind() {
- ty::Adt(def, _) => (
- Some(get_namespace_for_item(cx, def.did)),
- compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
- ),
- ty::RawPtr(_) | ty::Ref(..) => {
- (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
- }
- _ => {
- bug!(
- "debuginfo: unexpected trait-object type in \
- trait_pointer_metadata(): {:?}",
- trait_object_type
- );
- }
- },
-
- // No object type, use the trait type directly (no scope here since the type
- // will be wrapped in the dyn$ synthetic type).
- None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
- };
-
- let file_metadata = unknown_file_metadata(cx);
-
- let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
-
- assert_eq!(abi::FAT_PTR_ADDR, 0);
- assert_eq!(abi::FAT_PTR_EXTRA, 1);
-
- let data_ptr_field = layout.field(cx, 0);
- let vtable_field = layout.field(cx, 1);
- let member_descriptions = vec![
- MemberDescription {
- name: "pointer".to_owned(),
- type_metadata: type_metadata(
- cx,
- cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
- rustc_span::DUMMY_SP,
- ),
- offset: layout.fields.offset(0),
- size: data_ptr_field.size,
- align: data_ptr_field.align.abi,
- flags: DIFlags::FlagArtificial,
- discriminant: None,
- source_info: None,
- },
- MemberDescription {
- name: "vtable".to_owned(),
- type_metadata: type_metadata(cx, vtable_field.ty, rustc_span::DUMMY_SP),
- offset: layout.fields.offset(1),
- size: vtable_field.size,
- align: vtable_field.align.abi,
- flags: DIFlags::FlagArtificial,
- discriminant: None,
- source_info: None,
- },
- ];
-
- composite_type_metadata(
- cx,
- trait_object_type.unwrap_or(trait_type),
- &trait_type_name,
- unique_type_id,
- member_descriptions,
- containing_scope,
- file_metadata,
- rustc_span::DUMMY_SP,
- )
+ if let ty::Dynamic(..) = dyn_type.kind() {
+ let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
+ composite_type_metadata(cx, dyn_type, &type_name, unique_type_id, vec![], NO_SCOPE_METADATA)
+ } else {
+ bug!("Only ty::Dynamic is valid for dyn_type_metadata(). Found {:?} instead.", dyn_type)
+ }
}
-pub fn type_metadata<'ll, 'tcx>(
+/// Create debuginfo for `[T]` and `str`. These are unsized.
+///
+/// NOTE: We currently emit just emit the debuginfo for the element type here
+/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
+/// `*const T` for the `data_ptr` field of the corresponding fat-pointer
+/// debuginfo of `&[T]`.
+///
+/// It would be preferable and more accurate if we emitted a DIArray of T
+/// without an upper bound instead. That is, LLVM already supports emitting
+/// debuginfo of arrays of unknown size. But GDB currently seems to end up
+/// in an infinite loop when confronted with such a type.
+///
+/// As a side effect of the current encoding every instance of a type like
+/// `struct Foo { unsized_field: [u8] }` will look like
+/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
+/// slice is zero, then accessing `unsized_field` in the debugger would
+/// result in an out-of-bounds access.
+fn slice_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
- t: Ty<'tcx>,
- usage_site_span: Span,
-) -> &'ll DIType {
+ slice_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+) -> MetadataCreationResult<'ll> {
+ let element_type = match slice_type.kind() {
+ ty::Slice(element_type) => *element_type,
+ ty::Str => cx.tcx.types.u8,
+ _ => {
+ bug!(
+ "Only ty::Slice is valid for slice_type_metadata(). Found {:?} instead.",
+ slice_type
+ )
+ }
+ };
+
+ let element_type_metadata = type_metadata(cx, element_type);
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
+ MetadataCreationResult { metadata: element_type_metadata, already_stored_in_typemap: false }
+}
+
+pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
// Get the unique type ID of this type.
let unique_type_id = {
let mut type_map = debug_context(cx).type_map.borrow_mut();
@@ -629,26 +652,6 @@
debug!("type_metadata: {:?}", t);
- let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
- ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)),
- ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)),
- ty::Dynamic(..) => Ok(MetadataCreationResult::new(
- trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
- false,
- )),
- _ => {
- let pointee_metadata = type_metadata(cx, ty, usage_site_span);
-
- if let Some(metadata) =
- debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
- {
- return Err(metadata);
- }
-
- Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false))
- }
- };
-
let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() {
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
@@ -656,24 +659,20 @@
ty::Tuple(elements) if elements.is_empty() => {
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
}
- ty::Array(typ, _) | ty::Slice(typ) => {
- fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span)
- }
- ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span),
+ ty::Array(..) => fixed_size_array_metadata(cx, unique_type_id, t),
+ ty::Slice(_) | ty::Str => slice_type_metadata(cx, t, unique_type_id),
ty::Dynamic(..) => {
- MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
+ MetadataCreationResult::new(dyn_type_metadata(cx, t, unique_type_id), false)
}
ty::Foreign(..) => {
MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
}
- ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) {
- Ok(res) => res,
- Err(metadata) => return metadata,
- },
- ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) {
- Ok(res) => res,
- Err(metadata) => return metadata,
- },
+ ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
+ pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
+ }
+ ty::Adt(def, _) if def.is_box() => {
+ pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
+ }
ty::FnDef(..) | ty::FnPtr(_) => {
if let Some(metadata) =
debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
@@ -710,26 +709,33 @@
type_map.borrow_mut().register_type_with_metadata(t, temp_type);
let fn_metadata =
- subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx), usage_site_span)
- .metadata;
+ subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx)).metadata;
type_map.borrow_mut().remove_type(t);
// This is actually a function pointer, so wrap it in pointer DI.
- MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
+ let (pointer_size, pointer_align) =
+ cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit()));
+ let name = compute_debuginfo_type_name(cx.tcx, t, false);
+ let md = unsafe {
+ llvm::LLVMRustDIBuilderCreatePointerType(
+ DIB(cx),
+ fn_metadata,
+ pointer_size.bits(),
+ pointer_align.bits() as u32,
+ 0, // Ignore DWARF address space.
+ name.as_ptr().cast(),
+ name.len(),
+ )
+ };
+
+ MetadataCreationResult::new(md, false)
}
ty::Closure(def_id, substs) => {
let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
let containing_scope = get_namespace_for_item(cx, def_id);
- prepare_tuple_metadata(
- cx,
- t,
- &upvar_tys,
- unique_type_id,
- usage_site_span,
- Some(containing_scope),
- )
- .finalize(cx)
+ prepare_tuple_metadata(cx, t, &upvar_tys, unique_type_id, Some(containing_scope))
+ .finalize(cx)
}
ty::Generator(def_id, substs, _) => {
let upvar_tys: Vec<_> = substs
@@ -737,25 +743,18 @@
.prefix_tys()
.map(|t| cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
.collect();
- prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span, upvar_tys)
- .finalize(cx)
+ prepare_enum_metadata(cx, t, def_id, unique_type_id, upvar_tys).finalize(cx)
}
ty::Adt(def, ..) => match def.adt_kind() {
- AdtKind::Struct => {
- prepare_struct_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
- }
- AdtKind::Union => {
- prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
- }
+ AdtKind::Struct => prepare_struct_metadata(cx, t, unique_type_id).finalize(cx),
+ AdtKind::Union => prepare_union_metadata(cx, t, unique_type_id).finalize(cx),
AdtKind::Enum => {
- prepare_enum_metadata(cx, t, def.did, unique_type_id, usage_site_span, vec![])
- .finalize(cx)
+ prepare_enum_metadata(cx, t, def.did, unique_type_id, vec![]).finalize(cx)
}
},
ty::Tuple(elements) => {
let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
- prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
- .finalize(cx)
+ prepare_tuple_metadata(cx, t, &tys, unique_type_id, NO_SCOPE_METADATA).finalize(cx)
}
// Type parameters from polymorphized functions.
ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
@@ -770,8 +769,7 @@
let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => metadata,
None => {
- span_bug!(
- usage_site_span,
+ bug!(
"expected type metadata for unique \
type ID '{}' to already be in \
the `debuginfo::TypeMap` but it \
@@ -785,8 +783,7 @@
match type_map.find_metadata_for_type(t) {
Some(metadata) => {
if metadata != metadata_for_uid {
- span_bug!(
- usage_site_span,
+ bug!(
"mismatch between `Ty` and \
`UniqueTypeId` maps in \
`debuginfo::TypeMap`. \
@@ -994,27 +991,17 @@
debug!("foreign_type_metadata: {:?}", t);
let name = compute_debuginfo_type_name(cx.tcx, t, false);
- create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
-}
-
-fn pointer_type_metadata<'ll, 'tcx>(
- cx: &CodegenCx<'ll, 'tcx>,
- pointer_type: Ty<'tcx>,
- pointee_type_metadata: &'ll DIType,
-) -> &'ll DIType {
- let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
- let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false);
- unsafe {
- llvm::LLVMRustDIBuilderCreatePointerType(
- DIB(cx),
- pointee_type_metadata,
- pointer_size.bits(),
- pointer_align.bits() as u32,
- 0, // Ignore DWARF address space.
- name.as_ptr().cast(),
- name.len(),
- )
- }
+ let (size, align) = cx.size_and_align_of(t);
+ create_struct_stub(
+ cx,
+ size,
+ align,
+ &name,
+ unique_type_id,
+ NO_SCOPE_METADATA,
+ DIFlags::FlagZero,
+ None,
+ )
}
fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
@@ -1283,7 +1270,6 @@
struct StructMemberDescriptionFactory<'tcx> {
ty: Ty<'tcx>,
variant: &'tcx ty::VariantDef,
- span: Span,
}
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
@@ -1300,12 +1286,12 @@
let name = if self.variant.ctor_kind == CtorKind::Fn {
format!("__{}", i)
} else {
- f.ident.to_string()
+ f.name.to_string()
};
let field = layout.field(cx, i);
MemberDescription {
name,
- type_metadata: type_metadata(cx, field.ty, self.span),
+ type_metadata: type_metadata(cx, field.ty),
offset: layout.fields.offset(i),
size: field.size,
align: field.align.abi,
@@ -1322,7 +1308,6 @@
cx: &CodegenCx<'ll, 'tcx>,
struct_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
- span: Span,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
@@ -1332,14 +1317,17 @@
};
let containing_scope = get_namespace_for_item(cx, struct_def_id);
+ let (size, align) = cx.size_and_align_of(struct_type);
let struct_metadata_stub = create_struct_stub(
cx,
- struct_type,
+ size,
+ align,
&struct_name,
unique_type_id,
Some(containing_scope),
DIFlags::FlagZero,
+ None,
);
create_and_register_recursive_type_forward_declaration(
@@ -1348,7 +1336,7 @@
unique_type_id,
struct_metadata_stub,
struct_metadata_stub,
- StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant, span }),
+ StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant }),
)
}
@@ -1385,7 +1373,6 @@
struct TupleMemberDescriptionFactory<'tcx> {
ty: Ty<'tcx>,
component_types: Vec<Ty<'tcx>>,
- span: Span,
}
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
@@ -1412,7 +1399,7 @@
};
MemberDescription {
name,
- type_metadata: type_metadata(cx, component_type, self.span),
+ type_metadata: type_metadata(cx, component_type),
offset: layout.fields.offset(i),
size,
align,
@@ -1430,18 +1417,20 @@
tuple_type: Ty<'tcx>,
component_types: &[Ty<'tcx>],
unique_type_id: UniqueTypeId,
- span: Span,
containing_scope: Option<&'ll DIScope>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
+ let (size, align) = cx.size_and_align_of(tuple_type);
let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
let struct_stub = create_struct_stub(
cx,
- tuple_type,
+ size,
+ align,
&tuple_name[..],
unique_type_id,
containing_scope,
DIFlags::FlagZero,
+ None,
);
create_and_register_recursive_type_forward_declaration(
@@ -1453,7 +1442,6 @@
TupleMDF(TupleMemberDescriptionFactory {
ty: tuple_type,
component_types: component_types.to_vec(),
- span,
}),
)
}
@@ -1465,7 +1453,6 @@
struct UnionMemberDescriptionFactory<'tcx> {
layout: TyAndLayout<'tcx>,
variant: &'tcx ty::VariantDef,
- span: Span,
}
impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
@@ -1480,8 +1467,8 @@
.map(|(i, f)| {
let field = self.layout.field(cx, i);
MemberDescription {
- name: f.ident.to_string(),
- type_metadata: type_metadata(cx, field.ty, self.span),
+ name: f.name.to_string(),
+ type_metadata: type_metadata(cx, field.ty),
offset: Size::ZERO,
size: field.size,
align: field.align.abi,
@@ -1498,7 +1485,6 @@
cx: &CodegenCx<'ll, 'tcx>,
union_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
- span: Span,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
@@ -1518,7 +1504,7 @@
unique_type_id,
union_metadata_stub,
union_metadata_stub,
- UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant, span }),
+ UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant }),
)
}
@@ -1538,7 +1524,7 @@
let state_arg = mir::Local::new(1);
for var in &body.var_debug_info {
- let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue };
+ let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
if place.local != state_arg {
continue;
}
@@ -1573,7 +1559,6 @@
layout: TyAndLayout<'tcx>,
tag_type_metadata: Option<&'ll DIType>,
common_members: Vec<Option<&'ll DIType>>,
- span: Span,
}
impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
@@ -1605,7 +1590,7 @@
// msvc, then we need to use a different, fallback encoding of the debuginfo.
let fallback = cpp_like_debuginfo(cx.tcx);
// This will always find the metadata in the type map.
- let self_metadata = type_metadata(cx, self.enum_type, self.span);
+ let self_metadata = type_metadata(cx, self.enum_type);
match self.layout.variants {
Variants::Single { index } => {
@@ -1617,16 +1602,17 @@
let variant_info = variant_info_for(index);
let (variant_type_metadata, member_description_factory) =
- describe_enum_variant(cx, self.layout, variant_info, self_metadata, self.span);
+ describe_enum_variant(cx, self.layout, variant_info, self_metadata);
let member_descriptions = member_description_factory.create_member_descriptions(cx);
+ let type_params = compute_type_parameters(cx, self.enum_type);
set_members_of_composite_type(
cx,
- self.enum_type,
variant_type_metadata,
member_descriptions,
Some(&self.common_members),
+ type_params,
);
vec![MemberDescription {
name: variant_info.variant_name(),
@@ -1682,23 +1668,19 @@
.map(|(i, _)| {
let variant = self.layout.for_variant(cx, i);
let variant_info = variant_info_for(i);
- let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
- cx,
- variant,
- variant_info,
- self_metadata,
- self.span,
- );
+ let (variant_type_metadata, member_desc_factory) =
+ describe_enum_variant(cx, variant, variant_info, self_metadata);
let member_descriptions =
member_desc_factory.create_member_descriptions(cx);
+ let type_params = compute_type_parameters(cx, self.enum_type);
set_members_of_composite_type(
cx,
- self.enum_type,
variant_type_metadata,
member_descriptions,
Some(&self.common_members),
+ type_params,
);
MemberDescription {
@@ -1807,7 +1789,7 @@
tag.value.size(cx).bits(),
tag.value.align(cx).abi.bits() as u32,
create_DIArray(DIB(cx), &tags),
- type_metadata(cx, discr_enum_ty, self.span),
+ type_metadata(cx, discr_enum_ty),
true,
)
};
@@ -1818,17 +1800,17 @@
dataful_variant_layout,
variant_info,
self_metadata,
- self.span,
);
let member_descriptions = member_desc_factory.create_member_descriptions(cx);
+ let type_params = compute_type_parameters(cx, self.enum_type);
set_members_of_composite_type(
cx,
- self.enum_type,
variant_type_metadata,
member_descriptions,
Some(&self.common_members),
+ type_params,
);
let (size, align) =
@@ -1864,23 +1846,18 @@
let variant = self.layout.for_variant(cx, i);
let variant_info = variant_info_for(i);
let (variant_type_metadata, member_desc_factory) =
- describe_enum_variant(
- cx,
- variant,
- variant_info,
- self_metadata,
- self.span,
- );
+ describe_enum_variant(cx, variant, variant_info, self_metadata);
let member_descriptions =
member_desc_factory.create_member_descriptions(cx);
+ let type_params = compute_type_parameters(cx, self.enum_type);
set_members_of_composite_type(
cx,
- self.enum_type,
variant_type_metadata,
member_descriptions,
Some(&self.common_members),
+ type_params,
);
let niche_value = calculate_niche_value(i);
@@ -1908,7 +1885,6 @@
/// Cloned from the `layout::Struct` describing the variant.
offsets: Vec<Size>,
args: Vec<(String, Ty<'tcx>)>,
- span: Span,
}
impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
@@ -1923,7 +1899,7 @@
let (size, align) = cx.size_and_align_of(ty);
MemberDescription {
name: name.to_string(),
- type_metadata: type_metadata(cx, ty, self.span),
+ type_metadata: type_metadata(cx, ty),
offset: self.offsets[i],
size,
align,
@@ -1950,7 +1926,7 @@
impl<'tcx> VariantInfo<'_, 'tcx> {
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
match self {
- VariantInfo::Adt(variant) => f(variant.ident.as_str()),
+ VariantInfo::Adt(variant) => f(variant.name.as_str()),
VariantInfo::Generator { variant_index, .. } => {
f(&GeneratorSubsts::variant_name(*variant_index))
}
@@ -1959,7 +1935,7 @@
fn variant_name(&self) -> String {
match self {
- VariantInfo::Adt(variant) => variant.ident.to_string(),
+ VariantInfo::Adt(variant) => variant.name.to_string(),
VariantInfo::Generator { variant_index, .. } => {
// Since GDB currently prints out the raw discriminant along
// with every variant, make each variant name be just the value
@@ -1973,7 +1949,7 @@
fn field_name(&self, i: usize) -> String {
let field_name = match *self {
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => {
- Some(variant.fields[i].ident.name)
+ Some(variant.fields[i].name)
}
VariantInfo::Generator {
generator_layout,
@@ -2011,20 +1987,24 @@
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
containing_scope: &'ll DIScope,
- span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
let metadata_stub = variant.map_struct_name(|variant_name| {
let unique_type_id = debug_context(cx)
.type_map
.borrow_mut()
.get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name);
+
+ let (size, align) = cx.size_and_align_of(layout.ty);
+
create_struct_stub(
cx,
- layout.ty,
+ size,
+ align,
variant_name,
unique_type_id,
Some(containing_scope),
DIFlags::FlagZero,
+ None,
)
});
@@ -2033,8 +2013,7 @@
.map(|i| (variant.field_name(i), layout.field(cx, i).ty))
.collect();
- let member_description_factory =
- VariantMDF(VariantMemberDescriptionFactory { offsets, args, span });
+ let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { offsets, args });
(metadata_stub, member_description_factory)
}
@@ -2044,7 +2023,6 @@
enum_type: Ty<'tcx>,
enum_def_id: DefId,
unique_type_id: UniqueTypeId,
- span: Span,
outer_field_tys: Vec<Ty<'tcx>>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
let tcx = cx.tcx;
@@ -2063,7 +2041,7 @@
let enumerators_metadata: Vec<_> = match enum_type.kind() {
ty::Adt(def, _) => iter::zip(def.discriminants(tcx), &def.variants)
.map(|((_, discr), v)| {
- let name = v.ident.as_str();
+ let name = v.name.as_str();
let is_unsigned = match discr.ty.kind() {
ty::Int(_) => false,
ty::Uint(_) => true,
@@ -2109,8 +2087,7 @@
Some(discriminant_type_metadata) => discriminant_type_metadata,
None => {
let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx));
- let discriminant_base_type_metadata =
- type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP);
+ let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(tcx));
let item_name;
let discriminant_name = match enum_type.kind() {
@@ -2202,7 +2179,6 @@
layout,
tag_type_metadata: discriminant_type_metadata,
common_members: vec![],
- span,
}),
);
}
@@ -2272,11 +2248,8 @@
let outer_fields = match layout.variants {
Variants::Single { .. } => vec![],
Variants::Multiple { .. } => {
- let tuple_mdf = TupleMemberDescriptionFactory {
- ty: enum_type,
- component_types: outer_field_tys,
- span,
- };
+ let tuple_mdf =
+ TupleMemberDescriptionFactory { ty: enum_type, component_types: outer_field_tys };
tuple_mdf
.create_member_descriptions(cx)
.into_iter()
@@ -2352,7 +2325,6 @@
layout,
tag_type_metadata: None,
common_members: outer_fields,
- span,
}),
)
}
@@ -2368,28 +2340,28 @@
composite_type_unique_id: UniqueTypeId,
member_descriptions: Vec<MemberDescription<'ll>>,
containing_scope: Option<&'ll DIScope>,
-
- // Ignore source location information as long as it
- // can't be reconstructed for non-local crates.
- _file_metadata: &'ll DIFile,
- _definition_span: Span,
) -> &'ll DICompositeType {
+ let (size, align) = cx.size_and_align_of(composite_type);
+
// Create the (empty) struct metadata node ...
let composite_type_metadata = create_struct_stub(
cx,
- composite_type,
+ size,
+ align,
composite_type_name,
composite_type_unique_id,
containing_scope,
DIFlags::FlagZero,
+ None,
);
+
// ... and immediately create and add the member descriptions.
set_members_of_composite_type(
cx,
- composite_type,
composite_type_metadata,
member_descriptions,
None,
+ compute_type_parameters(cx, composite_type),
);
composite_type_metadata
@@ -2397,10 +2369,10 @@
fn set_members_of_composite_type<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
- composite_type: Ty<'tcx>,
composite_type_metadata: &'ll DICompositeType,
member_descriptions: Vec<MemberDescription<'ll>>,
common_members: Option<&Vec<Option<&'ll DIType>>>,
+ type_params: &'ll DIArray,
) {
// In some rare cases LLVM metadata uniquing would lead to an existing type
// description being used instead of a new one created in
@@ -2427,13 +2399,12 @@
member_metadata.extend(other_members.iter());
}
- let type_params = compute_type_parameters(cx, composite_type);
unsafe {
- let type_array = create_DIArray(DIB(cx), &member_metadata);
+ let field_array = create_DIArray(DIB(cx), &member_metadata);
llvm::LLVMRustDICompositeTypeReplaceArrays(
DIB(cx),
composite_type_metadata,
- Some(type_array),
+ Some(field_array),
Some(type_params),
);
}
@@ -2450,8 +2421,7 @@
if let GenericArgKind::Type(ty) = kind.unpack() {
let actual_type =
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
- let actual_type_metadata =
- type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+ let actual_type_metadata = type_metadata(cx, actual_type);
let name = name.as_str();
Some(unsafe {
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
@@ -2487,14 +2457,14 @@
/// with `set_members_of_composite_type()`.
fn create_struct_stub<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
- struct_type: Ty<'tcx>,
- struct_type_name: &str,
+ size: Size,
+ align: Align,
+ type_name: &str,
unique_type_id: UniqueTypeId,
containing_scope: Option<&'ll DIScope>,
flags: DIFlags,
+ vtable_holder: Option<&'ll DIType>,
) -> &'ll DICompositeType {
- let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
-
let type_map = debug_context(cx).type_map.borrow();
let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id);
@@ -2507,17 +2477,17 @@
llvm::LLVMRustDIBuilderCreateStructType(
DIB(cx),
containing_scope,
- struct_type_name.as_ptr().cast(),
- struct_type_name.len(),
+ type_name.as_ptr().cast(),
+ type_name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
- struct_size.bits(),
- struct_align.bits() as u32,
+ size.bits(),
+ align.bits() as u32,
flags,
None,
empty_array,
0,
- None,
+ vtable_holder,
unique_type_id.as_ptr().cast(),
unique_type_id.len(),
)
@@ -2593,7 +2563,7 @@
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
- let type_metadata = type_metadata(cx, variable_type, span);
+ let type_metadata = type_metadata(cx, variable_type);
let var_name = tcx.item_name(def_id);
let var_name = var_name.as_str();
let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
@@ -2623,6 +2593,14 @@
}
/// Generates LLVM debuginfo for a vtable.
+///
+/// The vtable type looks like a struct with a field for each function pointer and super-trait
+/// pointer it contains (plus the `size` and `align` fields).
+///
+/// Except for `size`, `align`, and `drop_in_place`, the field names don't try to mirror
+/// the name of the method they implement. This can be implemented in the future once there
+/// is a proper disambiguation scheme for dealing with methods from different traits that have
+/// the same name.
fn vtable_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
@@ -2639,16 +2617,81 @@
COMMON_VTABLE_ENTRIES
};
- // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is
- // correct - but we could create a more accurate description, e.g. by describing it
- // as a struct where each field has a name that corresponds to the name of the method
- // it points to.
- // However, this is not entirely straightforward because there might be multiple
- // methods with the same name if the vtable is for multiple traits. So for now we keep
- // things simple instead of adding some ad-hoc disambiguation scheme.
- let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64);
+ // All function pointers are described as opaque pointers. This could be improved in the future
+ // by describing them as actual function pointers.
+ let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit);
+ let void_pointer_type_debuginfo = type_metadata(cx, void_pointer_ty);
+ let usize_debuginfo = type_metadata(cx, tcx.types.usize);
+ let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty);
+ // If `usize` is not pointer-sized and -aligned then the size and alignment computations
+ // for the vtable as a whole would be wrong. Let's make sure this holds even on weird
+ // platforms.
+ assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align));
- type_metadata(cx, vtable_type, rustc_span::DUMMY_SP)
+ let vtable_type_name =
+ compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type);
+ let unique_type_id = debug_context(cx)
+ .type_map
+ .borrow_mut()
+ .get_unique_type_id_of_vtable_type(&vtable_type_name);
+ let size = pointer_size * vtable_entries.len() as u64;
+
+ // This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate
+ // the vtable to the type it is for.
+ let vtable_holder = type_metadata(cx, ty);
+
+ let vtable_type_metadata = create_struct_stub(
+ cx,
+ size,
+ pointer_align,
+ &vtable_type_name,
+ unique_type_id,
+ NO_SCOPE_METADATA,
+ DIFlags::FlagArtificial,
+ Some(vtable_holder),
+ );
+
+ // Create a field for each entry in the vtable.
+ let fields: Vec<_> = vtable_entries
+ .iter()
+ .enumerate()
+ .filter_map(|(index, vtable_entry)| {
+ let (field_name, field_type) = match vtable_entry {
+ ty::VtblEntry::MetadataDropInPlace => {
+ ("drop_in_place".to_string(), void_pointer_type_debuginfo)
+ }
+ ty::VtblEntry::Method(_) => {
+ // Note: This code does not try to give a proper name to each method
+ // because there might be multiple methods with the same name
+ // (coming from different traits).
+ (format!("__method{}", index), void_pointer_type_debuginfo)
+ }
+ ty::VtblEntry::TraitVPtr(_) => {
+ // Note: In the future we could try to set the type of this pointer
+ // to the type that we generate for the corresponding vtable.
+ (format!("__super_trait_ptr{}", index), void_pointer_type_debuginfo)
+ }
+ ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_debuginfo),
+ ty::VtblEntry::MetadataSize => ("size".to_string(), usize_debuginfo),
+ ty::VtblEntry::Vacant => return None,
+ };
+
+ Some(MemberDescription {
+ name: field_name,
+ type_metadata: field_type,
+ offset: pointer_size * index as u64,
+ size: pointer_size,
+ align: pointer_align,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ })
+ })
+ .collect();
+
+ let type_params = create_DIArray(DIB(cx), &[]);
+ set_members_of_composite_type(cx, vtable_type_metadata, fields, None, type_params);
+ vtable_type_metadata
}
/// Creates debug information for the given vtable, which is for the
@@ -2670,11 +2713,12 @@
return;
}
- let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref);
+ let vtable_name =
+ compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref);
+ let linkage_name = "";
unsafe {
- let linkage_name = "";
llvm::LLVMRustDIBuilderCreateStaticVariable(
DIB(cx),
NO_SCOPE_METADATA,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 01f7868..247cb9e 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -25,7 +25,7 @@
use rustc_hir::def_id::{DefId, DefIdMap};
use rustc_index::vec::IndexVec;
use rustc_middle::mir;
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
use rustc_session::config::{self, DebugInfo};
@@ -108,18 +108,29 @@
// This can be overridden using --llvm-opts -dwarf-version,N.
// Android has the same issue (#22398)
if let Some(version) = sess.target.dwarf_version {
- llvm::LLVMRustAddModuleFlag(self.llmod, "Dwarf Version\0".as_ptr().cast(), version)
+ llvm::LLVMRustAddModuleFlag(
+ self.llmod,
+ llvm::LLVMModFlagBehavior::Warning,
+ "Dwarf Version\0".as_ptr().cast(),
+ version,
+ )
}
// Indicate that we want CodeView debug information on MSVC
if sess.target.is_like_msvc {
- llvm::LLVMRustAddModuleFlag(self.llmod, "CodeView\0".as_ptr().cast(), 1)
+ llvm::LLVMRustAddModuleFlag(
+ self.llmod,
+ llvm::LLVMModFlagBehavior::Warning,
+ "CodeView\0".as_ptr().cast(),
+ 1,
+ )
}
// Prevent bitcode readers from deleting the debug info.
let ptr = "Debug Info Version\0".as_ptr();
llvm::LLVMRustAddModuleFlag(
self.llmod,
+ llvm::LLVMModFlagBehavior::Warning,
ptr.cast(),
llvm::LLVMRustDebugMetadataVersion(),
);
@@ -307,9 +318,11 @@
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
maybe_definition_llfn: Option<&'ll Value>,
) -> &'ll DIScope {
+ let tcx = self.tcx;
+
let def_id = instance.def_id();
let containing_scope = get_containing_scope(self, instance);
- let span = self.tcx.def_span(def_id);
+ let span = tcx.def_span(def_id);
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file);
@@ -319,16 +332,24 @@
};
let mut name = String::new();
- type_names::push_item_name(self.tcx(), def_id, false, &mut name);
+ type_names::push_item_name(tcx, def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.
- let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
+ let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
- // Get_template_parameters() will append a `<...>` clause to the function
- // name if necessary.
- let generics = self.tcx().generics_of(enclosing_fn_def_id);
- let substs = instance.substs.truncate_to(self.tcx(), generics);
- let template_parameters = get_template_parameters(self, generics, substs, &mut name);
+ // We look up the generics of the enclosing function and truncate the substs
+ // to their length in order to cut off extra stuff that might be in there for
+ // closures or generators.
+ let generics = tcx.generics_of(enclosing_fn_def_id);
+ let substs = instance.substs.truncate_to(tcx, generics);
+
+ type_names::push_generic_params(
+ tcx,
+ tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs),
+ &mut name,
+ );
+
+ let template_parameters = get_template_parameters(self, generics, substs);
let linkage_name = &mangled_name_of_instance(self, instance).name;
// Omit the linkage_name if it is the same as subprogram name.
@@ -350,7 +371,7 @@
if self.sess().opts.optimize != config::OptLevel::No {
spflags |= DISPFlags::SPFlagOptimized;
}
- if let Some((id, _)) = self.tcx.entry_fn(()) {
+ if let Some((id, _)) = tcx.entry_fn(()) {
if id == def_id {
spflags |= DISPFlags::SPFlagMainSubprogram;
}
@@ -390,7 +411,7 @@
signature.push(if fn_abi.ret.is_ignore() {
None
} else {
- Some(type_metadata(cx, fn_abi.ret.layout.ty, rustc_span::DUMMY_SP))
+ Some(type_metadata(cx, fn_abi.ret.layout.ty))
});
// Arguments types
@@ -409,21 +430,17 @@
let t = arg.layout.ty;
let t = match t.kind() {
ty::Array(ct, _)
- if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() =>
+ if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
{
- cx.tcx.mk_imm_ptr(ct)
+ cx.tcx.mk_imm_ptr(*ct)
}
_ => t,
};
- Some(type_metadata(cx, t, rustc_span::DUMMY_SP))
+ Some(type_metadata(cx, t))
}));
} else {
- signature.extend(
- fn_abi
- .args
- .iter()
- .map(|arg| Some(type_metadata(cx, arg.layout.ty, rustc_span::DUMMY_SP))),
- );
+ signature
+ .extend(fn_abi.args.iter().map(|arg| Some(type_metadata(cx, arg.layout.ty))));
}
create_DIArray(DIB(cx), &signature[..])
@@ -433,14 +450,7 @@
cx: &CodegenCx<'ll, 'tcx>,
generics: &ty::Generics,
substs: SubstsRef<'tcx>,
- name_to_append_suffix_to: &mut String,
) -> &'ll DIArray {
- type_names::push_generic_params(
- cx.tcx,
- cx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs),
- name_to_append_suffix_to,
- );
-
if substs.types().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}
@@ -453,8 +463,7 @@
if let GenericArgKind::Type(ty) = kind.unpack() {
let actual_type =
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
- let actual_type_metadata =
- type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+ let actual_type_metadata = type_metadata(cx, actual_type);
let name = name.as_str();
Some(unsafe {
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
@@ -507,9 +516,9 @@
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.definitely_needs_subst(cx.tcx)
+ && !impl_self_ty.needs_subst()
{
- Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
+ Some(type_metadata(cx, impl_self_ty))
} else {
Some(namespace::item_namespace(cx, def.did))
}
@@ -584,7 +593,7 @@
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file);
- let type_metadata = type_metadata(self, variable_type, span);
+ let type_metadata = type_metadata(self, variable_type);
let (argument_index, dwarf_tag) = match variable_kind {
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 953b676..acd032a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -4,7 +4,9 @@
use super::CrateDebugContext;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_target::abi::Variants;
use crate::common::CodegenCx;
use crate::llvm;
@@ -46,3 +48,53 @@
pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) enum FatPtrKind {
+ Slice,
+ Dyn,
+}
+
+/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
+/// if the second field of the fat pointer is a length or a vtable-pointer.
+/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
+/// the function returns `None`.
+pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ pointee_ty: Ty<'tcx>,
+) -> Option<FatPtrKind> {
+ let layout = cx.layout_of(pointee_ty);
+
+ if !layout.is_unsized() {
+ return None;
+ }
+
+ match *pointee_ty.kind() {
+ ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
+ ty::Dynamic(..) => Some(FatPtrKind::Dyn),
+ ty::Adt(..) | ty::Tuple(..) if matches!(layout.variants, Variants::Single { .. }) => {
+ let last_field_index = layout.fields.count() - 1;
+ debug_assert!(
+ (0..last_field_index)
+ .all(|field_index| { !layout.field(cx, field_index).is_unsized() })
+ );
+
+ let unsized_field = layout.field(cx, last_field_index);
+ debug_assert!(unsized_field.is_unsized());
+ fat_pointer_kind(cx, unsized_field.ty)
+ }
+ ty::Foreign(_) => {
+ // Assert that pointers to foreign types really are thin:
+ debug_assert_eq!(
+ cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)),
+ cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8))
+ );
+ None
+ }
+ _ => {
+ // For all other pointee types we should already have returned None
+ // at the beginning of the function.
+ panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty)
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 90d0d5c..a6e06ff 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -47,6 +47,7 @@
attributes::default_optimisation_attrs(cx.tcx.sess, llfn);
attributes::non_lazy_bind(cx.sess(), llfn);
+
llfn
}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 07d49b6..cfd23f5 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -7,7 +7,6 @@
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};
@@ -351,7 +350,7 @@
self.type_void(),
true,
false,
- ast::LlvmAsmDialect::Att,
+ llvm::AsmDialect::Att,
&[span],
false,
None,
@@ -526,9 +525,8 @@
normal.ret(bx.const_i32(0));
- let cs = catchswitch.catch_switch(None, None, 2);
- catchswitch.add_handler(cs, catchpad_rust.llbb());
- catchswitch.add_handler(cs, catchpad_foreign.llbb());
+ let cs =
+ catchswitch.catch_switch(None, None, &[catchpad_rust.llbb(), catchpad_foreign.llbb()]);
// We can't use the TypeDescriptor defined in libpanic_unwind because it
// might be in another DLL and the SEH encoding only supports specifying
@@ -791,7 +789,7 @@
)));
// `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
- vec![try_fn_ty, i8p, catch_fn_ty].into_iter(),
+ [try_fn_ty, i8p, catch_fn_ty].into_iter(),
tcx.types.i32,
false,
hir::Unsafety::Unsafe,
@@ -1134,8 +1132,8 @@
fn simd_simple_float_intrinsic<'ll, 'tcx>(
name: Symbol,
- in_elem: &::rustc_middle::ty::TyS<'_>,
- in_ty: &::rustc_middle::ty::TyS<'_>,
+ in_elem: Ty<'_>,
+ in_ty: Ty<'_>,
in_len: u64,
bx: &mut Builder<'_, 'll, 'tcx>,
span: Span,
@@ -1689,7 +1687,7 @@
bitwise_red!(simd_reduce_all: vector_reduce_and, true);
bitwise_red!(simd_reduce_any: vector_reduce_or, true);
- if name == sym::simd_cast {
+ if name == sym::simd_cast || name == sym::simd_as {
require_simd!(ret_ty, "return");
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
@@ -1715,14 +1713,26 @@
let (in_style, in_width) = match in_elem.kind() {
// vectors of pointer-sized integers should've been
// disallowed before here, so this unwrap is safe.
- ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()),
- ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()),
+ ty::Int(i) => (
+ Style::Int(true),
+ i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
+ ty::Uint(u) => (
+ Style::Int(false),
+ u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
ty::Float(f) => (Style::Float, f.bit_width()),
_ => (Style::Unsupported, 0),
};
let (out_style, out_width) = match out_elem.kind() {
- ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()),
- ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()),
+ ty::Int(i) => (
+ Style::Int(true),
+ i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
+ ty::Uint(u) => (
+ Style::Int(false),
+ u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
ty::Float(f) => (Style::Float, f.bit_width()),
_ => (Style::Unsupported, 0),
};
@@ -1749,10 +1759,10 @@
});
}
(Style::Float, Style::Int(out_is_signed)) => {
- return Ok(if out_is_signed {
- bx.fptosi(args[0].immediate(), llret_ty)
- } else {
- bx.fptoui(args[0].immediate(), llret_ty)
+ return Ok(match (out_is_signed, name == sym::simd_as) {
+ (false, false) => bx.fptoui(args[0].immediate(), llret_ty),
+ (true, false) => bx.fptosi(args[0].immediate(), llret_ty),
+ (_, true) => bx.cast_float_to_int(out_is_signed, args[0].immediate(), llret_ty),
});
}
(Style::Float, Style::Float) => {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index cea4595..75836e1 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -7,9 +7,11 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
+#![feature(let_else)]
#![feature(extern_types)]
#![feature(nll)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
use back::write::{create_informational_target_machine, create_target_machine};
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index f2782f8..657f1fc 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -61,6 +61,26 @@
ARM = 0x01c0,
}
+/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h.
+///
+/// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are
+/// resolved according to the merge behaviors specified here. Flags differing only in merge
+/// behavior are still considered to be in conflict.
+///
+/// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably,
+/// 'Error' and 'Warning' cannot be mixed for a given flag.
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum LLVMModFlagBehavior {
+ Error = 1,
+ Warning = 2,
+ Require = 3,
+ Override = 4,
+ Append = 5,
+ AppendUnique = 6,
+ Max = 7,
+}
+
// Consts for the LLVM CallConv type, pre-cast to usize.
/// LLVM CallingConv::ID. Should we wrap this?
@@ -169,6 +189,8 @@
StackProtectReq = 30,
StackProtectStrong = 31,
StackProtect = 32,
+ NoUndef = 33,
+ SanitizeMemTag = 34,
}
/// LLVMIntPredicate
@@ -423,22 +445,13 @@
}
/// LLVMRustAsmDialect
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum AsmDialect {
Att,
Intel,
}
-impl AsmDialect {
- pub fn from_generic(asm: rustc_ast::LlvmAsmDialect) -> Self {
- match asm {
- rustc_ast::LlvmAsmDialect::Att => AsmDialect::Att,
- rustc_ast::LlvmAsmDialect::Intel => AsmDialect::Intel,
- }
- }
-}
-
/// LLVMRustCodeGenOptLevel
#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
@@ -976,6 +989,7 @@
extern "C" {
pub fn LLVMRustInstallFatalErrorHandler();
+ pub fn LLVMRustDisableSystemDialogsOnCrash();
// Create and destroy contexts.
pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context;
@@ -1169,6 +1183,7 @@
pub fn LLVMRustAddByValAttr(Fn: &Value, index: c_uint, ty: &Type);
pub fn LLVMRustAddStructRetAttr(Fn: &Value, index: c_uint, ty: &Type);
pub fn LLVMRustAddFunctionAttribute(Fn: &Value, index: c_uint, attr: Attribute);
+ pub fn LLVMRustEmitUWTableAttr(Fn: &Value, async_: bool);
pub fn LLVMRustAddFunctionAttrStringValue(
Fn: &Value,
index: c_uint,
@@ -1904,7 +1919,16 @@
pub fn LLVMRustIsRustLLVM() -> bool;
- pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
+ /// Add LLVM module flags.
+ ///
+ /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What
+ /// "compatible" means depends on the merge behaviors involved.
+ pub fn LLVMRustAddModuleFlag(
+ M: &Module,
+ merge_behavior: LLVMModFlagBehavior,
+ name: *const c_char,
+ value: u32,
+ );
pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
@@ -2329,7 +2353,6 @@
pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
- pub fn LLVMRustMarkAllFunctionsNounwind(M: &Module);
pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
pub fn LLVMRustArchiveIteratorNew(AR: &Archive) -> &mut ArchiveIterator<'_>;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index a1117a1..8586b04 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -31,6 +31,10 @@
}
}
+pub fn EmitUWTableAttr(llfn: &Value, async_: bool) {
+ unsafe { LLVMRustEmitUWTableAttr(llfn, async_) }
+}
+
pub fn AddFunctionAttrStringValue(llfn: &Value, idx: AttributePlace, attr: &CStr, value: &CStr) {
unsafe {
LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), value.as_ptr())
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index d49df29..5f39d58 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -2,8 +2,8 @@
use crate::{llvm, llvm_util};
use libc::c_int;
use libloading::Library;
-use rustc_codegen_ssa::target_features::supported_target_features;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_codegen_ssa::target_features::{supported_target_features, tied_target_features};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_fs_util::path_to_c_string;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
@@ -46,6 +46,12 @@
let mut llvm_args = Vec::with_capacity(n_args + 1);
llvm::LLVMRustInstallFatalErrorHandler();
+ // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog
+ // box for the purpose of launching a debugger. However, on CI this will
+ // cause it to hang until it times out, which can take several hours.
+ if std::env::var_os("CI").is_some() {
+ llvm::LLVMRustDisableSystemDialogsOnCrash();
+ }
fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
@@ -185,30 +191,58 @@
("aarch64", "frintts") => vec!["fptoint"],
("aarch64", "fcma") => vec!["complxnum"],
("aarch64", "pmuv3") => vec!["perfmon"],
+ ("aarch64", "paca") => vec!["pauth"],
+ ("aarch64", "pacg") => vec!["pauth"],
(_, s) => vec![s],
}
}
+// Given a map from target_features to whether they are enabled or disabled,
+// ensure only valid combinations are allowed.
+pub fn check_tied_features(
+ sess: &Session,
+ features: &FxHashMap<&str, bool>,
+) -> Option<&'static [&'static str]> {
+ for tied in tied_target_features(sess) {
+ // Tied features must be set to the same value, or not set at all
+ let mut tied_iter = tied.iter();
+ let enabled = features.get(tied_iter.next().unwrap());
+
+ if tied_iter.any(|f| enabled != features.get(f)) {
+ return Some(tied);
+ }
+ }
+ None
+}
+
pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess);
- supported_target_features(sess)
- .iter()
- .filter_map(
- |&(feature, gate)| {
+ let mut features: Vec<Symbol> =
+ supported_target_features(sess)
+ .iter()
+ .filter_map(|&(feature, gate)| {
if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
- },
- )
- .filter(|feature| {
- for llvm_feature in to_llvm_feature(sess, feature) {
- let cstr = CString::new(llvm_feature).unwrap();
- if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
- return true;
+ })
+ .filter(|feature| {
+ for llvm_feature in to_llvm_feature(sess, feature) {
+ let cstr = CString::new(llvm_feature).unwrap();
+ if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
+ return true;
+ }
}
- }
- false
- })
- .map(|feature| Symbol::intern(feature))
- .collect()
+ false
+ })
+ .map(|feature| Symbol::intern(feature))
+ .collect();
+
+ // LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64
+ // (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use
+ // by compiler-builtins, to export the builtins with the expected, LLVM-version-dependent ABI.
+ // The target feature can be dropped once we no longer support older LLVM versions.
+ if sess.is_nightly_build() && get_version() >= (14, 0, 0) {
+ features.push(Symbol::intern("llvm14-builtins-abi"));
+ }
+ features
}
pub fn print_version() {
@@ -389,15 +423,19 @@
Some(_) | None => {}
};
+ fn strip(s: &str) -> &str {
+ s.strip_prefix(&['+', '-']).unwrap_or(s)
+ }
+
let filter = |s: &str| {
if s.is_empty() {
return vec![];
}
- let feature = if s.starts_with('+') || s.starts_with('-') {
- &s[1..]
- } else {
+ let feature = strip(s);
+ if feature == s {
return vec![s.to_string()];
- };
+ }
+
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
// are not passed down to LLVM.
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
@@ -414,8 +452,17 @@
features.extend(sess.target.features.split(',').flat_map(&filter));
// -Ctarget-features
- features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
-
+ let feats: Vec<&str> = sess.opts.cg.target_feature.split(',').collect();
+ // LLVM enables based on the last occurence of a feature
+ if let Some(f) =
+ check_tied_features(sess, &feats.iter().map(|f| (strip(f), !f.starts_with("-"))).collect())
+ {
+ sess.err(&format!(
+ "Target features {} must all be enabled or disabled together",
+ f.join(", ")
+ ));
+ }
+ features.extend(feats.iter().flat_map(|&f| filter(f)));
features
}
@@ -428,8 +475,9 @@
// The new pass manager is enabled by default for LLVM >= 13.
// This matches Clang, which also enables it since Clang 13.
- // FIXME: There are some perf issues with the new pass manager
- // when targeting s390x, so it is temporarily disabled for that
- // arch, see https://github.com/rust-lang/rust/issues/89609
- user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
+ // There are some perf issues with the new pass manager when targeting
+ // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
+ // See https://github.com/rust-lang/rust/issues/89609.
+ let min_version = if target_arch == "s390x" { 14 } else { 13 };
+ user_opt.unwrap_or_else(|| llvm_util::get_version() >= (min_version, 0, 0))
}
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index f8c919e..fafb9a6 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -49,7 +49,7 @@
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() && !def.variants.is_empty() {
- write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+ write!(&mut name, "::{}", def.variants[index].name).unwrap();
}
}
if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
@@ -330,7 +330,9 @@
ty::Ref(..) | ty::RawPtr(_) => {
return self.field(cx, index).llvm_type(cx);
}
- ty::Adt(def, _) if def.is_box() => {
+ // only wide pointer boxes are handled as pointers
+ // thin pointer boxes with scalar allocators are handled by the general logic below
+ ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
}
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 5c13dfd..8bbf25c 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -9,12 +9,12 @@
[dependencies]
bitflags = "1.2.1"
cc = "1.0.69"
-itertools = "0.9"
+itertools = "0.10"
tracing = "0.1"
libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
-thorin-dwp = "0.1.1"
+thorin-dwp = "0.2"
pathdiff = "0.2.0"
snap = "1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
@@ -41,6 +41,6 @@
rustc_session = { path = "../rustc_session" }
[dependencies.object]
-version = "0.26.2"
+version = "0.28.0"
default-features = false
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 3db948a..a2f74b9 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -51,7 +51,6 @@
fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
where
F: FnMut(&str) -> bool + 'static;
- fn update_symbols(&mut self);
fn build(self);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index f7fe194..58e0667 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -216,17 +216,18 @@
}
let name = &info.crate_name[&cnum];
let used_crate_source = &info.used_crate_source[&cnum];
- let path = if let Some((path, _)) = &used_crate_source.rlib {
- path
- } else if used_crate_source.rmeta.is_some() {
- return Err(format!(
- "could not find rlib for: `{}`, found rmeta (metadata) file",
- name
- ));
+ if let Some((path, _)) = &used_crate_source.rlib {
+ f(cnum, &path);
} else {
- return Err(format!("could not find rlib for: `{}`", name));
- };
- f(cnum, &path);
+ if used_crate_source.rmeta.is_some() {
+ return Err(format!(
+ "could not find rlib for: `{}`, found rmeta (metadata) file",
+ name
+ ));
+ } else {
+ return Err(format!("could not find rlib for: `{}`", name));
+ }
+ }
}
Ok(())
}
@@ -333,10 +334,6 @@
ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
}
- // After adding all files to the archive, we need to update the
- // symbol table of the archive.
- ab.update_symbols();
-
// Note that it is important that we add all of our non-object "magical
// files" *after* all of the object files in the archive. The reason for
// this is as follows:
@@ -365,13 +362,6 @@
// normal linkers for the platform.
let metadata = create_rmeta_file(sess, codegen_results.metadata.raw_data());
ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
-
- // After adding all files to the archive, we need to update the
- // symbol table of the archive. This currently dies on macOS (see
- // #11162), and isn't necessary there anyway
- if !sess.target.is_like_osx {
- ab.update_symbols();
- }
}
RlibFlavor::StaticlibBase => {
@@ -381,6 +371,7 @@
}
}
}
+
return Ok(ab);
}
@@ -509,7 +500,6 @@
sess.fatal(&e);
}
- ab.update_symbols();
ab.build();
if !all_native_libs.is_empty() {
@@ -667,7 +657,7 @@
cmd.env_remove(k);
}
- if sess.opts.debugging_opts.print_link_args {
+ if sess.opts.prints.contains(&PrintRequest::LinkArgs) {
println!("{:?}", &cmd);
}
@@ -932,7 +922,7 @@
but `link.exe` was not found",
);
sess.note_without_error(
- "please ensure that VS 2013, VS 2015, VS 2017 or VS 2019 \
+ "please ensure that VS 2013, VS 2015, VS 2017, VS 2019 or VS 2022 \
was installed with the Visual C++ option",
);
}
@@ -1159,6 +1149,7 @@
LinkerFlavor::Lld(_) => "lld",
LinkerFlavor::PtxLinker => "rust-ptx-linker",
LinkerFlavor::BpfLinker => "bpf-linker",
+ LinkerFlavor::L4Bender => "l4-bender",
}),
flavor,
)),
@@ -2309,7 +2300,6 @@
sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
- archive.update_symbols();
let mut any_objects = false;
for f in archive.src_files() {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 15d16e7..3fb56f4 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -126,7 +126,6 @@
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
// to the linker args construction.
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
-
match flavor {
LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
@@ -149,6 +148,8 @@
LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
+
+ LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>,
}
}
@@ -1355,6 +1356,157 @@
}
}
+/// Linker shepherd script for L4Re (Fiasco)
+pub struct L4Bender<'a> {
+ cmd: Command,
+ sess: &'a Session,
+ hinted_static: bool,
+}
+
+impl<'a> Linker for L4Bender<'a> {
+ fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+ bug!("dylibs are not supported on L4Re");
+ }
+ fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
+ self.hint_static();
+ self.cmd.arg(format!("-PC{}", lib));
+ }
+ fn link_rlib(&mut self, lib: &Path) {
+ self.hint_static();
+ self.cmd.arg(lib);
+ }
+ fn include_path(&mut self, path: &Path) {
+ self.cmd.arg("-L").arg(path);
+ }
+ fn framework_path(&mut self, _: &Path) {
+ bug!("frameworks are not supported on L4Re");
+ }
+ fn output_filename(&mut self, path: &Path) {
+ self.cmd.arg("-o").arg(path);
+ }
+
+ fn add_object(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn full_relro(&mut self) {
+ self.cmd.arg("-zrelro");
+ self.cmd.arg("-znow");
+ }
+
+ fn partial_relro(&mut self) {
+ self.cmd.arg("-zrelro");
+ }
+
+ fn no_relro(&mut self) {
+ self.cmd.arg("-znorelro");
+ }
+
+ fn cmd(&mut self) -> &mut Command {
+ &mut self.cmd
+ }
+
+ fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+ fn link_rust_dylib(&mut self, _: Symbol, _: &Path) {
+ panic!("Rust dylibs not supported");
+ }
+
+ fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+ bug!("frameworks not supported on L4Re");
+ }
+
+ fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+ self.hint_static();
+ self.cmd.arg("--whole-archive").arg(format!("-l{}", lib));
+ self.cmd.arg("--no-whole-archive");
+ }
+
+ fn link_whole_rlib(&mut self, lib: &Path) {
+ self.hint_static();
+ self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
+ }
+
+ fn gc_sections(&mut self, keep_metadata: bool) {
+ if !keep_metadata {
+ self.cmd.arg("--gc-sections");
+ }
+ }
+
+ fn no_gc_sections(&mut self) {
+ self.cmd.arg("--no-gc-sections");
+ }
+
+ fn optimize(&mut self) {
+ // GNU-style linkers support optimization with -O. GNU ld doesn't
+ // need a numeric argument, but other linkers do.
+ if self.sess.opts.optimize == config::OptLevel::Default
+ || self.sess.opts.optimize == config::OptLevel::Aggressive
+ {
+ self.cmd.arg("-O1");
+ }
+ }
+
+ fn pgo_gen(&mut self) {}
+
+ fn debuginfo(&mut self, strip: Strip) {
+ match strip {
+ Strip::None => {}
+ Strip::Debuginfo => {
+ self.cmd().arg("--strip-debug");
+ }
+ Strip::Symbols => {
+ self.cmd().arg("--strip-all");
+ }
+ }
+ }
+
+ fn no_default_libraries(&mut self) {
+ self.cmd.arg("-nostdlib");
+ }
+
+ fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
+ // ToDo, not implemented, copy from GCC
+ self.sess.warn("exporting symbols not implemented yet for L4Bender");
+ return;
+ }
+
+ fn subsystem(&mut self, subsystem: &str) {
+ self.cmd.arg(&format!("--subsystem {}", subsystem));
+ }
+
+ fn reset_per_library_state(&mut self) {
+ self.hint_static(); // Reset to default before returning the composed command line.
+ }
+
+ fn group_start(&mut self) {
+ self.cmd.arg("--start-group");
+ }
+
+ fn group_end(&mut self) {
+ self.cmd.arg("--end-group");
+ }
+
+ fn linker_plugin_lto(&mut self) {}
+
+ fn control_flow_guard(&mut self) {}
+
+ fn no_crt_objects(&mut self) {}
+}
+
+impl<'a> L4Bender<'a> {
+ pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
+ L4Bender { cmd: cmd, sess: sess, hinted_static: false }
+ }
+
+ fn hint_static(&mut self) {
+ if !self.hinted_static {
+ self.cmd.arg("-static");
+ self.hinted_static = true;
+ }
+ }
+}
+
pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
if let Some(ref exports) = tcx.sess.target.override_export_symbols {
return exports.clone();
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 79c24f0..9ebbcac 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -95,7 +95,7 @@
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
}
-fn create_object_file(sess: &Session) -> Option<write::Object> {
+fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
let endianness = match sess.target.options.endian {
Endian::Little => Endianness::Little,
Endian::Big => Endianness::Big,
@@ -135,12 +135,24 @@
Architecture::Mips => {
// copied from `mipsel-linux-gnu-gcc foo.c -c` and
// inspecting the resulting `e_flags` field.
- let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ let e_flags = elf::EF_MIPS_CPIC
+ | elf::EF_MIPS_PIC
+ | if sess.target.options.cpu.contains("r6") {
+ elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008
+ } else {
+ elf::EF_MIPS_ARCH_32R2
+ };
file.flags = FileFlags::Elf { e_flags };
}
Architecture::Mips64 => {
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
- let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ let e_flags = elf::EF_MIPS_CPIC
+ | elf::EF_MIPS_PIC
+ | if sess.target.options.cpu.contains("r6") {
+ elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
+ } else {
+ elf::EF_MIPS_ARCH_64R2
+ };
file.flags = FileFlags::Elf { e_flags };
}
Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
@@ -188,9 +200,7 @@
// `SHF_EXCLUDE` flag we can set on sections in an object file to get
// automatically removed from the final output.
pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
- let mut file = if let Some(file) = create_object_file(sess) {
- file
- } else {
+ let Some(mut file) = create_object_file(sess) else {
// This is used to handle all "other" targets. This includes targets
// in two categories:
//
@@ -250,9 +260,7 @@
) -> Vec<u8> {
let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
- let mut file = if let Some(file) = create_object_file(sess) {
- file
- } else {
+ let Some(mut file) = create_object_file(sess) else {
return compressed.to_vec();
};
let section = file.add_section(
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index baafa74..aeddd92 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -76,7 +76,7 @@
//
// As a result, if this id is an FFI item (foreign item) then we only
// let it through if it's included statically.
- match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
+ match tcx.hir().get_by_def_id(def_id) {
Node::ForeignItem(..) => {
tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
}
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index bea4544..f6fddbb 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -32,7 +32,7 @@
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
-use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{MergeFunctions, SanitizerSet};
use std::any::Any;
use std::fs;
@@ -313,7 +313,6 @@
pub backend: B,
pub prof: SelfProfilerRef,
pub lto: Lto,
- pub no_landing_pads: bool,
pub save_temps: bool,
pub fewer_names: bool,
pub time_trace: bool,
@@ -478,7 +477,7 @@
codegen_worker_receive,
shared_emitter_main,
future: coordinator_thread,
- output_filenames: tcx.output_filenames(()),
+ output_filenames: tcx.output_filenames(()).clone(),
}
}
@@ -1039,7 +1038,6 @@
crate_types: sess.crate_types().to_vec(),
each_linked_rlib_for_lto,
lto: sess.lto(),
- no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
fewer_names: sess.fewer_names(),
save_temps: sess.opts.cg.save_temps,
time_trace: sess.opts.debugging_opts.llvm_time_trace,
@@ -1052,7 +1050,7 @@
cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
coordinator_send,
diag_emitter: shared_emitter.clone(),
- output_filenames: tcx.output_filenames(()),
+ output_filenames: tcx.output_filenames(()).clone(),
regular_module_config: regular_config,
metadata_module_config: metadata_config,
allocator_module_config: allocator_config,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 49b785a..4a5eabc 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -843,7 +843,7 @@
used_crate_source: Default::default(),
lang_item_to_crate: Default::default(),
missing_lang_items: Default::default(),
- dependency_formats: tcx.dependency_formats(()),
+ dependency_formats: tcx.dependency_formats(()).clone(),
windows_subsystem,
};
let lang_items = tcx.lang_items();
@@ -860,7 +860,7 @@
info.native_libraries
.insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
- info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
+ info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum).clone());
if tcx.is_compiler_builtins(cnum) {
info.compiler_builtins = Some(cnum);
}
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 93bb1ae..b63851c 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -13,9 +13,9 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
+use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt};
@@ -102,14 +102,14 @@
ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
if cpp_like_debuginfo {
match mutbl {
- hir::Mutability::Not => output.push_str("ptr_const$<"),
- hir::Mutability::Mut => output.push_str("ptr_mut$<"),
+ Mutability::Not => output.push_str("ptr_const$<"),
+ Mutability::Mut => output.push_str("ptr_mut$<"),
}
} else {
output.push('*');
match mutbl {
- hir::Mutability::Not => output.push_str("const "),
- hir::Mutability::Mut => output.push_str("mut "),
+ Mutability::Not => output.push_str("const "),
+ Mutability::Mut => output.push_str("mut "),
}
}
@@ -131,8 +131,8 @@
output.push_str(mutbl.prefix_str());
} else if !is_slice_or_str {
match mutbl {
- hir::Mutability::Not => output.push_str("ref$<"),
- hir::Mutability::Mut => output.push_str("ref_mut$<"),
+ Mutability::Not => output.push_str("ref$<"),
+ Mutability::Mut => output.push_str("ref_mut$<"),
}
}
@@ -146,7 +146,7 @@
if cpp_like_debuginfo {
output.push_str("array$<");
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
- match len.val {
+ match len.val() {
ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
_ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
.unwrap(),
@@ -154,7 +154,7 @@
} else {
output.push('[');
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
- match len.val {
+ match len.val() {
ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
_ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
.unwrap(),
@@ -203,8 +203,9 @@
let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds()
.map(|bound| {
- let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
- (item_def_id, ty)
+ let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
+ // FIXME(associated_const_equality): allow for consts here
+ (item_def_id, term.ty().unwrap())
})
.collect();
@@ -342,16 +343,41 @@
// We only care about avoiding recursing
// directly back to the type we're currently
// processing
- visited.remove(t);
+ visited.remove(&t);
}
- ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
- let key = tcx.def_key(def_id);
+ ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
+ // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
+ // "{async_fn_env#0}<T1, T2, ...>", etc.
+ let def_key = tcx.def_key(def_id);
+
if qualified {
- let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
+ let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id };
push_item_name(tcx, parent_def_id, true, output);
output.push_str("::");
}
- push_unqualified_item_name(tcx, def_id, key.disambiguated_data, output);
+
+ let mut label = String::with_capacity(20);
+ write!(&mut label, "{}_env", generator_kind_label(tcx.generator_kind(def_id))).unwrap();
+
+ push_disambiguated_special_name(
+ &label,
+ def_key.disambiguated_data.disambiguator,
+ cpp_like_debuginfo,
+ output,
+ );
+
+ // We also need to add the generic arguments of the async fn/generator or
+ // the enclosing function (for closures or async blocks), so that we end
+ // up with a unique name for every instantiation.
+
+ // Find the generics of the enclosing function, as defined in the source code.
+ let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
+ let generics = tcx.generics_of(enclosing_fn_def_id);
+
+ // Truncate the substs to the length of the above generics. This will cut off
+ // anything closure- or generator-specific.
+ let substs = substs.truncate_to(tcx, generics);
+ push_generic_params_internal(tcx, substs, output, visited);
}
// Type parameters from polymorphized functions.
ty::Param(_) => {
@@ -409,14 +435,14 @@
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();
+ let dataful_variant_name = def.variants[*dataful_variant].name.as_str();
output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
} else if let Variants::Single { index: variant_idx } = &layout.variants {
// Uninhabited enums can't be constructed and should never need to be visualized so
// skip this step for them.
if def.variants.len() != 0 {
- let variant = def.variants[*variant_idx].ident.as_str();
+ let variant = def.variants[*variant_idx].name.as_str();
output.push_str(&format!(", {}", variant));
}
@@ -443,7 +469,14 @@
}
}
-/// Computes a name for the global variable storing a vtable.
+pub enum VTableNameKind {
+ // Is the name for the const/static holding the vtable?
+ GlobalVariable,
+ // Is the name for the type of the vtable?
+ Type,
+}
+
+/// Computes a name for the global variable storing a vtable (or the type of that global variable).
///
/// The name is of the form:
///
@@ -452,10 +485,15 @@
/// or, when generating C++-like names:
///
/// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$`
+///
+/// If `kind` is `VTableNameKind::Type` then the last component is `{vtable_ty}` instead of just
+/// `{vtable}`, so that the type and the corresponding global variable get assigned different
+/// names.
pub fn compute_debuginfo_vtable_name<'tcx>(
tcx: TyCtxt<'tcx>,
t: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+ kind: VTableNameKind,
) -> String {
let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
@@ -488,7 +526,12 @@
push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
- let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" };
+ let suffix = match (cpp_like_debuginfo, kind) {
+ (true, VTableNameKind::GlobalVariable) => "::vtable$",
+ (false, VTableNameKind::GlobalVariable) => "::{vtable}",
+ (true, VTableNameKind::Type) => "::vtable_type$",
+ (false, VTableNameKind::Type) => "::{vtable_type}",
+ };
vtable_name.reserve_exact(suffix.len());
vtable_name.push_str(suffix);
@@ -508,6 +551,29 @@
push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
}
+fn generator_kind_label(generator_kind: Option<GeneratorKind>) -> &'static str {
+ match generator_kind {
+ Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) => "async_block",
+ Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) => "async_closure",
+ Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) => "async_fn",
+ Some(GeneratorKind::Gen) => "generator",
+ None => "closure",
+ }
+}
+
+fn push_disambiguated_special_name(
+ label: &str,
+ disambiguator: u32,
+ cpp_like_debuginfo: bool,
+ output: &mut String,
+) {
+ if cpp_like_debuginfo {
+ write!(output, "{}${}", label, disambiguator).unwrap();
+ } else {
+ write!(output, "{{{}#{}}}", label, disambiguator).unwrap();
+ }
+}
+
fn push_unqualified_item_name(
tcx: TyCtxt<'_>,
def_id: DefId,
@@ -518,36 +584,32 @@
DefPathData::CrateRoot => {
output.push_str(tcx.crate_name(def_id.krate).as_str());
}
- DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
- // Generators look like closures, but we want to treat them differently
- // in the debug info.
- if cpp_like_debuginfo(tcx) {
- write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
- } else {
- write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
- }
+ DefPathData::ClosureExpr => {
+ let label = generator_kind_label(tcx.generator_kind(def_id));
+
+ push_disambiguated_special_name(
+ label,
+ disambiguated_data.disambiguator,
+ cpp_like_debuginfo(tcx),
+ output,
+ );
}
_ => match disambiguated_data.data.name() {
DefPathDataName::Named(name) => {
output.push_str(name.as_str());
}
DefPathDataName::Anon { namespace } => {
- if cpp_like_debuginfo(tcx) {
- write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
- } else {
- write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
- .unwrap();
- }
+ push_disambiguated_special_name(
+ namespace.as_str(),
+ disambiguated_data.disambiguator,
+ cpp_like_debuginfo(tcx),
+ output,
+ );
}
},
};
}
-// Pushes the generic parameters in the given `InternalSubsts` to the output string.
-// This ignores region parameters, since they can't reliably be
-// reconstructed for items from non-local crates. For local crates, this
-// would be possible but with inlining and LTO we have to use the least
-// common denominator - otherwise we would run into conflicts.
fn push_generic_params_internal<'tcx>(
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
@@ -583,19 +645,19 @@
true
}
-fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) {
- match ct.val {
+fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
+ match ct.val() {
ty::ConstKind::Param(param) => {
write!(output, "{}", param.name)
}
- _ => match ct.ty.kind() {
+ _ => match ct.ty().kind() {
ty::Int(ity) => {
- let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty);
+ let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
write!(output, "{}", val)
}
ty::Uint(_) => {
- let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty);
+ let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
write!(output, "{}", val)
}
ty::Bool => {
@@ -610,7 +672,7 @@
let mut hasher = StableHasher::new();
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- ct.val.hash_stable(hcx, &mut hasher);
+ ct.val().hash_stable(hcx, &mut hasher);
});
});
// Let's only emit 64 bits of the hash value. That should be plenty for
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 350199f..9bb8db0 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -7,6 +7,7 @@
#![feature(nll)]
#![feature(associated_type_bounds)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index b1b3f1d..d768d49 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -211,7 +211,6 @@
PlaceContext::MutatingUse(
MutatingUseContext::Store
- | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::AddressOf
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index dcfe5fc..4c7a09c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -477,6 +477,28 @@
helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
}
+ fn codegen_abort_terminator(
+ &mut self,
+ helper: TerminatorCodegenHelper<'tcx>,
+ mut bx: Bx,
+ terminator: &mir::Terminator<'tcx>,
+ ) {
+ let span = terminator.source_info.span;
+ self.set_debug_loc(&mut bx, terminator.source_info);
+
+ // Get the location information.
+ let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
+
+ // Obtain the panic entry point.
+ let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind);
+ let instance = ty::Instance::mono(bx.tcx(), def_id);
+ let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
+ let llfn = bx.get_fn_addr(instance);
+
+ // Codegen the actual panic invoke/call.
+ helper.do_call(self, &mut bx, fn_abi, llfn, &[location], None, None);
+ }
+
/// Returns `true` if this is indeed a panic intrinsic and codegen is done.
fn codegen_panic_intrinsic(
&mut self,
@@ -1014,10 +1036,7 @@
mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx),
mir::TerminatorKind::Abort => {
- bx.abort();
- // `abort` does not terminate the block, so we still need to generate
- // an `unreachable` terminator after it.
- bx.unreachable();
+ self.codegen_abort_terminator(helper, bx, terminator);
}
mir::TerminatorKind::Goto { target } => {
@@ -1327,8 +1346,7 @@
let mut cp_bx = self.new_block(&format!("cp_funclet{:?}", bb));
ret_llbb = cs_bx.llbb();
- let cs = cs_bx.catch_switch(None, None, 1);
- cs_bx.add_handler(cs, cp_bx.llbb());
+ let cs = cs_bx.catch_switch(None, None, &[cp_bx.llbb()]);
// The "null" here is actually a RTTI type descriptor for the
// C++ personality function, but `catch (...)` has no type so
@@ -1355,8 +1373,7 @@
let llpersonality = self.cx.eh_personality();
let llretty = self.landing_pad_type();
- let lp = bx.landing_pad(llretty, llpersonality, 1);
- bx.set_cleanup(lp);
+ let lp = bx.cleanup_landing_pad(llretty, llpersonality);
let slot = self.get_personality_slot(&mut bx);
slot.storage_live(&mut bx);
@@ -1477,7 +1494,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(self.cx.tcx()));
+ assert!(!dst_layout.ty.has_erasable_regions());
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/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 93b39dc..5cdf131 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -29,7 +29,7 @@
mir::ConstantKind::Ty(ct) => ct,
mir::ConstantKind::Val(val, _) => return Ok(val),
};
- match ct.val {
+ match ct.val() {
ty::ConstKind::Unevaluated(ct) => self
.cx
.tcx()
@@ -61,11 +61,11 @@
let c = ty::Const::from_value(bx.tcx(), val, ty);
let values: Vec<_> = bx
.tcx()
- .destructure_const(ty::ParamEnv::reveal_all().and(&c))
+ .destructure_const(ty::ParamEnv::reveal_all().and(c))
.fields
.iter()
.map(|field| {
- if let Some(prim) = field.val.try_to_scalar() {
+ if let Some(prim) = field.val().try_to_scalar() {
let layout = bx.layout_of(field_ty);
let scalar = match layout.abi {
Abi::Scalar(x) => x,
@@ -78,7 +78,7 @@
})
.collect();
let llval = bx.const_struct(&values, false);
- (llval, c.ty)
+ (llval, c.ty())
})
.unwrap_or_else(|_| {
bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 3657f80..c654232 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -369,6 +369,16 @@
}
}
+ sym::const_allocate => {
+ // returns a null pointer at runtime.
+ bx.const_null(bx.type_i8p())
+ }
+
+ sym::const_deallocate => {
+ // nop at runtime.
+ return;
+ }
+
// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
name if name_str.starts_with("atomic_") => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 1ef863e..814e4d6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -209,7 +209,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(cx.tcx()));
+ assert!(!layout.ty.has_erasable_regions());
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/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 4b07ed1..6976999 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -429,87 +429,78 @@
let cx = self.cx;
let tcx = self.cx.tcx();
- let result = match place_ref {
- mir::PlaceRef { local, projection: [] } => match self.locals[local] {
- LocalRef::Place(place) => {
- return place;
- }
- LocalRef::UnsizedPlace(place) => {
- return bx.load_operand(place).deref(cx);
- }
- LocalRef::Operand(..) => {
- bug!("using operand local {:?} as place", place_ref);
- }
- },
- mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
- // Load the pointer from its location.
- self.codegen_consume(bx, mir::PlaceRef { local, projection: proj_base })
+ let mut base = 0;
+ let mut cg_base = match self.locals[place_ref.local] {
+ LocalRef::Place(place) => place,
+ LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
+ LocalRef::Operand(..) => {
+ if let Some(elem) = place_ref
+ .projection
+ .iter()
+ .enumerate()
+ .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref))
+ {
+ base = elem.0 + 1;
+ self.codegen_consume(
+ bx,
+ mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref },
+ )
.deref(bx.cx())
- }
- mir::PlaceRef { local, projection: &[ref proj_base @ .., elem] } => {
- // FIXME turn this recursion into iteration
- let cg_base =
- self.codegen_place(bx, mir::PlaceRef { local, projection: proj_base });
-
- match elem {
- mir::ProjectionElem::Deref => bug!(),
- mir::ProjectionElem::Field(ref field, _) => {
- cg_base.project_field(bx, field.index())
- }
- mir::ProjectionElem::Index(index) => {
- let index = &mir::Operand::Copy(mir::Place::from(index));
- let index = self.codegen_operand(bx, index);
- let llindex = index.immediate();
- cg_base.project_index(bx, llindex)
- }
- mir::ProjectionElem::ConstantIndex {
- offset,
- from_end: false,
- min_length: _,
- } => {
- let lloffset = bx.cx().const_usize(offset as u64);
- cg_base.project_index(bx, lloffset)
- }
- mir::ProjectionElem::ConstantIndex {
- offset,
- from_end: true,
- min_length: _,
- } => {
- let lloffset = bx.cx().const_usize(offset as u64);
- let lllen = cg_base.len(bx.cx());
- let llindex = bx.sub(lllen, lloffset);
- cg_base.project_index(bx, llindex)
- }
- mir::ProjectionElem::Subslice { from, to, from_end } => {
- let mut subslice =
- cg_base.project_index(bx, bx.cx().const_usize(from as u64));
- let projected_ty =
- PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty;
- subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
-
- if subslice.layout.is_unsized() {
- assert!(from_end, "slice subslices should be `from_end`");
- subslice.llextra = Some(bx.sub(
- cg_base.llextra.unwrap(),
- bx.cx().const_usize((from as u64) + (to as u64)),
- ));
- }
-
- // Cast the place pointer type to the new
- // array or slice type (`*[%_; new_len]`).
- subslice.llval = bx.pointercast(
- subslice.llval,
- bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
- );
-
- subslice
- }
- mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+ } else {
+ bug!("using operand local {:?} as place", place_ref);
}
}
};
- debug!("codegen_place(place={:?}) => {:?}", place_ref, result);
- result
+ for elem in place_ref.projection[base..].iter() {
+ cg_base = match elem.clone() {
+ mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
+ mir::ProjectionElem::Field(ref field, _) => {
+ cg_base.project_field(bx, field.index())
+ }
+ mir::ProjectionElem::Index(index) => {
+ let index = &mir::Operand::Copy(mir::Place::from(index));
+ let index = self.codegen_operand(bx, index);
+ let llindex = index.immediate();
+ cg_base.project_index(bx, llindex)
+ }
+ mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => {
+ let lloffset = bx.cx().const_usize(offset as u64);
+ cg_base.project_index(bx, lloffset)
+ }
+ mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => {
+ let lloffset = bx.cx().const_usize(offset as u64);
+ let lllen = cg_base.len(bx.cx());
+ let llindex = bx.sub(lllen, lloffset);
+ cg_base.project_index(bx, llindex)
+ }
+ mir::ProjectionElem::Subslice { from, to, from_end } => {
+ let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64));
+ let projected_ty =
+ PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, *elem).ty;
+ subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
+
+ if subslice.layout.is_unsized() {
+ assert!(from_end, "slice subslices should be `from_end`");
+ subslice.llextra = Some(bx.sub(
+ cg_base.llextra.unwrap(),
+ bx.cx().const_usize((from as u64) + (to as u64)),
+ ));
+ }
+
+ // Cast the place pointer type to the new
+ // array or slice type (`*[%_; new_len]`).
+ subslice.llval = bx.pointercast(
+ subslice.llval,
+ bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
+ );
+
+ subslice
+ }
+ mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+ };
+ }
+ debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);
+ cg_base
}
pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 679c457..68decce 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -3,11 +3,10 @@
use super::{FunctionCx, LocalRef};
use crate::base;
-use crate::common::{self, IntPredicate, RealPredicate};
+use crate::common::{self, IntPredicate};
use crate::traits::*;
use crate::MemFlags;
-use rustc_apfloat::{ieee, Float, Round, Status};
use rustc_middle::mir;
use rustc_middle::ty::cast::{CastTy, IntTy};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
@@ -368,10 +367,10 @@
bx.inttoptr(usize_llval, ll_t_out)
}
(CastTy::Float, CastTy::Int(IntTy::I)) => {
- cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out)
+ bx.cast_float_to_int(true, llval, ll_t_out)
}
(CastTy::Float, CastTy::Int(_)) => {
- cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out)
+ bx.cast_float_to_int(false, llval, ll_t_out)
}
_ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty),
};
@@ -768,146 +767,3 @@
// (*) this is only true if the type is suitable
}
}
-
-fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
- bx: &mut Bx,
- signed: bool,
- x: Bx::Value,
- float_ty: Bx::Type,
- int_ty: Bx::Type,
-) -> Bx::Value {
- if let Some(false) = bx.cx().sess().opts.debugging_opts.saturating_float_casts {
- return if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
- }
-
- let try_sat_result = if signed { bx.fptosi_sat(x, int_ty) } else { bx.fptoui_sat(x, int_ty) };
- if let Some(try_sat_result) = try_sat_result {
- return try_sat_result;
- }
-
- let int_width = bx.cx().int_width(int_ty);
- let float_width = bx.cx().float_width(float_ty);
- // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
- // destination integer type after rounding towards zero. This `undef` value can cause UB in
- // safe code (see issue #10184), so we implement a saturating conversion on top of it:
- // Semantically, the mathematical value of the input is rounded towards zero to the next
- // mathematical integer, and then the result is clamped into the range of the destination
- // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
- // the destination integer type. NaN is mapped to 0.
- //
- // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
- // a value representable in int_ty.
- // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
- // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
- // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
- // representable. Note that this only works if float_ty's exponent range is sufficiently large.
- // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
- // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
- // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
- // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
- // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
- let int_max = |signed: bool, int_width: u64| -> u128 {
- let shift_amount = 128 - int_width;
- if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
- };
- let int_min = |signed: bool, int_width: u64| -> i128 {
- if signed { i128::MIN >> (128 - int_width) } else { 0 }
- };
-
- let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
- let rounded_min = ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
- assert_eq!(rounded_min.status, Status::OK);
- let rounded_max = ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
- assert!(rounded_max.value.is_finite());
- (rounded_min.value.to_bits(), rounded_max.value.to_bits())
- };
- let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
- let rounded_min = ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
- assert_eq!(rounded_min.status, Status::OK);
- let rounded_max = ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
- assert!(rounded_max.value.is_finite());
- (rounded_min.value.to_bits(), rounded_max.value.to_bits())
- };
-
- let mut float_bits_to_llval = |bits| {
- let bits_llval = match float_width {
- 32 => bx.cx().const_u32(bits as u32),
- 64 => bx.cx().const_u64(bits as u64),
- n => bug!("unsupported float width {}", n),
- };
- bx.bitcast(bits_llval, float_ty)
- };
- let (f_min, f_max) = match float_width {
- 32 => compute_clamp_bounds_single(signed, int_width),
- 64 => compute_clamp_bounds_double(signed, int_width),
- n => bug!("unsupported float width {}", n),
- };
- let f_min = float_bits_to_llval(f_min);
- let f_max = float_bits_to_llval(f_max);
- // To implement saturation, we perform the following steps:
- //
- // 1. Cast x to an integer with fpto[su]i. This may result in undef.
- // 2. Compare x to f_min and f_max, and use the comparison results to select:
- // a) int_ty::MIN if x < f_min or x is NaN
- // b) int_ty::MAX if x > f_max
- // c) the result of fpto[su]i otherwise
- // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
- //
- // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
- // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
- // undef does not introduce any non-determinism either.
- // More importantly, the above procedure correctly implements saturating conversion.
- // Proof (sketch):
- // If x is NaN, 0 is returned by definition.
- // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
- // This yields three cases to consider:
- // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
- // saturating conversion for inputs in that range.
- // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
- // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
- // than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
- // is correct.
- // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
- // int_ty::MIN and therefore the return value of int_ty::MIN is correct.
- // QED.
-
- let int_max = bx.cx().const_uint_big(int_ty, int_max(signed, int_width));
- let int_min = bx.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
- let zero = bx.cx().const_uint(int_ty, 0);
-
- // Step 1 ...
- let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
- let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min);
- let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max);
-
- // Step 2: We use two comparisons and two selects, with %s1 being the
- // result:
- // %less_or_nan = fcmp ult %x, %f_min
- // %greater = fcmp olt %x, %f_max
- // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
- // %s1 = select %greater, int_ty::MAX, %s0
- // Note that %less_or_nan uses an *unordered* comparison. This
- // comparison is true if the operands are not comparable (i.e., if x is
- // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
- // x is NaN.
- //
- // 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 an
- // ordered ("normal") comparison. Whether these optimizations will be
- // performed is ultimately up to the backend, but at least x86 does
- // perform them.
- let s0 = bx.select(less_or_nan, int_min, fptosui_result);
- let s1 = bx.select(greater, int_max, s0);
-
- // Step 3: NaN replacement.
- // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
- // Therefore we only need to execute this step for signed integer types.
- if signed {
- // LLVM has no isNaN predicate, so we use (x == x) instead
- let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x);
- bx.select(cmp, s1, zero)
- } else {
- s1
- }
-}
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 2c96987..773dc2a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -1,9 +1,7 @@
-use rustc_errors::struct_span_err;
use rustc_middle::mir;
use super::FunctionCx;
use super::LocalRef;
-use super::OperandValue;
use crate::traits::BuilderMethods;
use crate::traits::*;
@@ -66,51 +64,6 @@
}
bx
}
- mir::StatementKind::LlvmInlineAsm(ref asm) => {
- let outputs = asm
- .outputs
- .iter()
- .map(|output| self.codegen_place(&mut bx, output.as_ref()))
- .collect();
-
- let input_vals = asm.inputs.iter().fold(
- Vec::with_capacity(asm.inputs.len()),
- |mut acc, (span, input)| {
- let op = self.codegen_operand(&mut bx, input);
- if let OperandValue::Immediate(_) = op.val {
- acc.push(op.immediate());
- } else {
- struct_span_err!(
- bx.sess(),
- span.to_owned(),
- E0669,
- "invalid value for constraint in inline assembly"
- )
- .emit();
- }
- acc
- },
- );
-
- if input_vals.len() == asm.inputs.len() {
- let res = bx.codegen_llvm_inline_asm(
- &asm.asm,
- outputs,
- input_vals,
- statement.source_info.span,
- );
- if !res {
- struct_span_err!(
- bx.sess(),
- statement.source_info.span,
- E0668,
- "malformed inline assembly"
- )
- .emit();
- }
- }
- bx
- }
mir::StatementKind::Coverage(box ref coverage) => {
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
bx
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 63cc6fa..f31b0ee 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -74,8 +74,10 @@
("ssbs", Some(sym::aarch64_target_feature)),
// FEAT_SB
("sb", Some(sym::aarch64_target_feature)),
- // FEAT_PAUTH
- ("pauth", Some(sym::aarch64_target_feature)),
+ // FEAT_PAUTH (address authentication)
+ ("paca", Some(sym::aarch64_target_feature)),
+ // FEAT_PAUTH (generic authentication)
+ ("pacg", Some(sym::aarch64_target_feature)),
// FEAT_DPB
("dpb", Some(sym::aarch64_target_feature)),
// FEAT_DPB2
@@ -137,6 +139,8 @@
("v8.7a", Some(sym::aarch64_target_feature)),
];
+const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
+
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("adx", Some(sym::adx_target_feature)),
("aes", None),
@@ -256,6 +260,13 @@
}
}
+pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
+ match &*sess.target.arch {
+ "aarch64" => AARCH64_TIED_FEATURES,
+ _ => &[],
+ }
+}
+
pub(crate) fn provide(providers: &mut Providers) {
providers.supported_target_features = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs
index 65f3c75..11111a7 100644
--- a/compiler/rustc_codegen_ssa/src/traits/asm.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs
@@ -3,7 +3,6 @@
use crate::mir::place::PlaceRef;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::def_id::DefId;
-use rustc_hir::LlvmInlineAsmInner;
use rustc_middle::ty::Instance;
use rustc_span::Span;
use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -43,15 +42,6 @@
pub trait AsmBuilderMethods<'tcx>: BackendTypes {
/// Take an inline assembly expression and splat it out via LLVM
- fn codegen_llvm_inline_asm(
- &mut self,
- ia: &LlvmInlineAsmInner,
- outputs: Vec<PlaceRef<'tcx, Self::Value>>,
- inputs: Vec<Self::Value>,
- span: Span,
- ) -> bool;
-
- /// Take an inline assembly expression and splat it out via LLVM
fn codegen_inline_asm(
&mut self,
template: &[InlineAsmTemplatePiece],
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 48d8809..53fb21b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -1,18 +1,21 @@
use super::abi::AbiBuilderMethods;
use super::asm::AsmBuilderMethods;
+use super::consts::ConstMethods;
use super::coverageinfo::CoverageInfoBuilderMethods;
use super::debuginfo::DebugInfoBuilderMethods;
use super::intrinsic::IntrinsicCallMethods;
-use super::type_::ArgAbiMethods;
+use super::misc::MiscMethods;
+use super::type_::{ArgAbiMethods, BaseTypeMethods};
use super::{HasCodegen, StaticBuilderMethods};
use crate::common::{
- AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope,
+ AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
};
use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
use crate::MemFlags;
+use rustc_apfloat::{ieee, Float, Round, Status};
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_span::Span;
@@ -202,6 +205,179 @@
fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value;
fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
+ fn cast_float_to_int(
+ &mut self,
+ signed: bool,
+ x: Self::Value,
+ dest_ty: Self::Type,
+ ) -> Self::Value {
+ let in_ty = self.cx().val_ty(x);
+ let (float_ty, int_ty) = if self.cx().type_kind(dest_ty) == TypeKind::Vector
+ && self.cx().type_kind(in_ty) == TypeKind::Vector
+ {
+ (self.cx().element_type(in_ty), self.cx().element_type(dest_ty))
+ } else {
+ (in_ty, dest_ty)
+ };
+ assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double));
+ assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
+
+ if let Some(false) = self.cx().sess().opts.debugging_opts.saturating_float_casts {
+ return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
+ }
+
+ let try_sat_result =
+ if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) };
+ if let Some(try_sat_result) = try_sat_result {
+ return try_sat_result;
+ }
+
+ let int_width = self.cx().int_width(int_ty);
+ let float_width = self.cx().float_width(float_ty);
+ // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
+ // destination integer type after rounding towards zero. This `undef` value can cause UB in
+ // safe code (see issue #10184), so we implement a saturating conversion on top of it:
+ // Semantically, the mathematical value of the input is rounded towards zero to the next
+ // mathematical integer, and then the result is clamped into the range of the destination
+ // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
+ // the destination integer type. NaN is mapped to 0.
+ //
+ // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
+ // a value representable in int_ty.
+ // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
+ // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
+ // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
+ // representable. Note that this only works if float_ty's exponent range is sufficiently large.
+ // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
+ // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
+ // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
+ // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
+ // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
+ let int_max = |signed: bool, int_width: u64| -> u128 {
+ let shift_amount = 128 - int_width;
+ if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
+ };
+ let int_min = |signed: bool, int_width: u64| -> i128 {
+ if signed { i128::MIN >> (128 - int_width) } else { 0 }
+ };
+
+ let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
+ let rounded_min =
+ ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+ assert_eq!(rounded_min.status, Status::OK);
+ let rounded_max =
+ ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+ assert!(rounded_max.value.is_finite());
+ (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+ };
+ let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
+ let rounded_min =
+ ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+ assert_eq!(rounded_min.status, Status::OK);
+ let rounded_max =
+ ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+ assert!(rounded_max.value.is_finite());
+ (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+ };
+ // To implement saturation, we perform the following steps:
+ //
+ // 1. Cast x to an integer with fpto[su]i. This may result in undef.
+ // 2. Compare x to f_min and f_max, and use the comparison results to select:
+ // a) int_ty::MIN if x < f_min or x is NaN
+ // b) int_ty::MAX if x > f_max
+ // c) the result of fpto[su]i otherwise
+ // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
+ //
+ // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
+ // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
+ // undef does not introduce any non-determinism either.
+ // More importantly, the above procedure correctly implements saturating conversion.
+ // Proof (sketch):
+ // If x is NaN, 0 is returned by definition.
+ // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
+ // This yields three cases to consider:
+ // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
+ // saturating conversion for inputs in that range.
+ // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
+ // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
+ // than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
+ // is correct.
+ // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
+ // int_ty::MIN and therefore the return value of int_ty::MIN is correct.
+ // QED.
+
+ let float_bits_to_llval = |bx: &mut Self, bits| {
+ let bits_llval = match float_width {
+ 32 => bx.cx().const_u32(bits as u32),
+ 64 => bx.cx().const_u64(bits as u64),
+ n => bug!("unsupported float width {}", n),
+ };
+ bx.bitcast(bits_llval, float_ty)
+ };
+ let (f_min, f_max) = match float_width {
+ 32 => compute_clamp_bounds_single(signed, int_width),
+ 64 => compute_clamp_bounds_double(signed, int_width),
+ n => bug!("unsupported float width {}", n),
+ };
+ let f_min = float_bits_to_llval(self, f_min);
+ let f_max = float_bits_to_llval(self, f_max);
+ let int_max = self.cx().const_uint_big(int_ty, int_max(signed, int_width));
+ let int_min = self.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
+ let zero = self.cx().const_uint(int_ty, 0);
+
+ // If we're working with vectors, constants must be "splatted": the constant is duplicated
+ // into each lane of the vector. The algorithm stays the same, we are just using the
+ // same constant across all lanes.
+ let maybe_splat = |bx: &mut Self, val| {
+ if bx.cx().type_kind(dest_ty) == TypeKind::Vector {
+ bx.vector_splat(bx.vector_length(dest_ty), val)
+ } else {
+ val
+ }
+ };
+ let f_min = maybe_splat(self, f_min);
+ let f_max = maybe_splat(self, f_max);
+ let int_max = maybe_splat(self, int_max);
+ let int_min = maybe_splat(self, int_min);
+ let zero = maybe_splat(self, zero);
+
+ // Step 1 ...
+ let fptosui_result = if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
+ let less_or_nan = self.fcmp(RealPredicate::RealULT, x, f_min);
+ let greater = self.fcmp(RealPredicate::RealOGT, x, f_max);
+
+ // Step 2: We use two comparisons and two selects, with %s1 being the
+ // result:
+ // %less_or_nan = fcmp ult %x, %f_min
+ // %greater = fcmp olt %x, %f_max
+ // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
+ // %s1 = select %greater, int_ty::MAX, %s0
+ // Note that %less_or_nan uses an *unordered* comparison. This
+ // comparison is true if the operands are not comparable (i.e., if x is
+ // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
+ // x is NaN.
+ //
+ // 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 an
+ // ordered ("normal") comparison. Whether these optimizations will be
+ // performed is ultimately up to the backend, but at least x86 does
+ // perform them.
+ let s0 = self.select(less_or_nan, int_min, fptosui_result);
+ let s1 = self.select(greater, int_max, s0);
+
+ // Step 3: NaN replacement.
+ // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
+ // Therefore we only need to execute this step for signed integer types.
+ if signed {
+ // LLVM has no isNaN predicate, so we use (x == x) instead
+ let cmp = self.fcmp(RealPredicate::RealOEQ, x, x);
+ self.select(cmp, s1, zero)
+ } else {
+ s1
+ }
+ }
+
fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
@@ -245,29 +421,22 @@
fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value;
fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value;
- fn landing_pad(
- &mut self,
- ty: Self::Type,
- pers_fn: Self::Value,
- num_clauses: usize,
- ) -> Self::Value;
- fn set_cleanup(&mut self, landing_pad: Self::Value);
- fn resume(&mut self, exn: Self::Value) -> Self::Value;
+ fn set_personality_fn(&mut self, personality: Self::Value);
+
+ // These are used by everyone except msvc
+ fn cleanup_landing_pad(&mut self, ty: Self::Type, pers_fn: Self::Value) -> Self::Value;
+ fn resume(&mut self, exn: Self::Value);
+
+ // These are used only by msvc
fn cleanup_pad(&mut self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet;
- fn cleanup_ret(
- &mut self,
- funclet: &Self::Funclet,
- unwind: Option<Self::BasicBlock>,
- ) -> Self::Value;
+ fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option<Self::BasicBlock>);
fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet;
fn catch_switch(
&mut self,
parent: Option<Self::Value>,
unwind: Option<Self::BasicBlock>,
- num_handlers: usize,
+ handlers: &[Self::BasicBlock],
) -> Self::Value;
- fn add_handler(&mut self, catch_switch: Self::Value, handler: Self::BasicBlock);
- fn set_personality_fn(&mut self, personality: Self::Value);
fn atomic_cmpxchg(
&mut self,
diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
index cbf570d..e77201c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
@@ -22,7 +22,7 @@
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
/// Returns true if the function source hash was added to the coverage map (even if it had
- /// already been added, for this instance). Returns false *only* if `-Z instrument-coverage` is
+ /// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
/// not enabled (a coverage map is not being generated).
fn set_function_source_hash(
&mut self,
@@ -30,7 +30,7 @@
function_source_hash: u64,
) -> bool;
- /// Returns true if the counter was added to the coverage map; false if `-Z instrument-coverage`
+ /// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_counter(
&mut self,
@@ -40,7 +40,7 @@
) -> bool;
/// Returns true if the expression was added to the coverage map; false if
- /// `-Z instrument-coverage` is not enabled (a coverage map is not being generated).
+ /// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
@@ -51,7 +51,7 @@
region: Option<CodeRegion>,
) -> bool;
- /// Returns true if the region was added to the coverage map; false if `-Z instrument-coverage`
+ /// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
}
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 8729802..89a0f824 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -156,9 +156,37 @@
}
// Add spans for the stacktrace. Don't print a single-line backtrace though.
if self.stacktrace.len() > 1 {
+ // Helper closure to print duplicated lines.
+ let mut flush_last_line = |last_frame, times| {
+ if let Some((line, span)) = last_frame {
+ err.span_label(span, &line);
+ // Don't print [... additional calls ...] if the number of lines is small
+ if times < 3 {
+ for _ in 0..times {
+ err.span_label(span, &line);
+ }
+ } else {
+ err.span_label(
+ span,
+ format!("[... {} additional calls {} ...]", times, &line),
+ );
+ }
+ }
+ };
+
+ let mut last_frame = None;
+ let mut times = 0;
for frame_info in &self.stacktrace {
- err.span_label(frame_info.span, frame_info.to_string());
+ let frame = (frame_info.to_string(), frame_info.span);
+ if last_frame.as_ref() == Some(&frame) {
+ times += 1;
+ } else {
+ flush_last_line(last_frame, times);
+ last_frame = Some(frame);
+ times = 0;
+ }
}
+ flush_last_line(last_frame, times);
}
// Let the caller finish the job.
emit(err)
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 3ec9f3c..bfb9c40 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -6,8 +6,6 @@
ScalarMaybeUninit, StackPopCleanup,
};
-use rustc_errors::ErrorReported;
-use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
@@ -216,7 +214,7 @@
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
- assert!(key.param_env.constness() == hir::Constness::Const);
+ assert!(key.param_env.is_const());
// see comment in eval_to_allocation_raw_provider for what we're doing here
if key.param_env.reveal() == Reveal::All {
let mut key = key;
@@ -251,7 +249,7 @@
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
- assert!(key.param_env.constness() == hir::Constness::Const);
+ assert!(key.param_env.is_const());
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
@@ -282,25 +280,6 @@
let cid = key.value;
let def = cid.instance.def.with_opt_param();
-
- if let Some(def) = def.as_local() {
- if tcx.has_typeck_results(def.did) {
- if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors {
- return Err(ErrorHandled::Reported(error_reported));
- }
- }
- if !tcx.is_mir_available(def.did) {
- tcx.sess.delay_span_bug(
- tcx.def_span(def.did),
- &format!("no MIR body is available for {:?}", def.did),
- );
- return Err(ErrorHandled::Reported(ErrorReported {}));
- }
- if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured {
- return Err(ErrorHandled::Reported(error_reported));
- }
- }
-
let is_static = tcx.is_static(def.did);
let mut ecx = InterpCx::new(
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 821b048..05fbbf4 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -1,5 +1,5 @@
use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
@@ -15,7 +15,8 @@
}
}
-pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
+pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_id = tcx.hir().get_parent_node(hir_id);
matches!(
tcx.hir().get(parent_id),
@@ -29,15 +30,15 @@
/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
/// said intrinsic has a `rustc_const_{un,}stable` attribute.
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
- let node = tcx.hir().get(hir_id);
+ let def_id = def_id.expect_local();
+ let node = tcx.hir().get_by_def_id(def_id);
if let hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) =
node
{
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time.
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = tcx.hir().get_foreign_abi(hir_id) {
tcx.lookup_const_stability(def_id).is_some()
} else {
@@ -50,7 +51,7 @@
// If the function itself is not annotated with `const`, it may still be a `const fn`
// if it resides in a const trait impl.
- is_parent_const_impl_raw(tcx, hir_id)
+ is_parent_const_impl_raw(tcx, def_id)
} else {
matches!(node, hir::Node::Ctor(_))
}
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 30e9cbe..e157b58 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -1,3 +1,5 @@
+use rustc_errors::ErrorReported;
+use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty};
use std::borrow::Borrow;
@@ -243,6 +245,12 @@
ty::InstanceDef::Item(def) => {
if ecx.tcx.is_ctfe_mir_available(def.did) {
Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
+ } else if ecx.tcx.def_kind(def.did) == DefKind::AssocConst {
+ ecx.tcx.sess.delay_span_bug(
+ rustc_span::DUMMY_SP,
+ "This is likely a const item that is missing from its impl",
+ );
+ throw_inval!(AlreadyReported(ErrorReported {}));
} else {
let path = ecx.tcx.def_path_str(def.did);
Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path))
@@ -347,6 +355,33 @@
)?;
ecx.write_pointer(ptr, dest)?;
}
+ sym::const_deallocate => {
+ let ptr = ecx.read_pointer(&args[0])?;
+ let size = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
+ let align = ecx.read_scalar(&args[2])?.to_machine_usize(ecx)?;
+
+ let size = Size::from_bytes(size);
+ let align = match Align::from_bytes(align) {
+ Ok(a) => a,
+ Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
+ };
+
+ // If an allocation is created in an another const,
+ // we don't deallocate it.
+ let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?;
+ let is_allocated_in_another_const = matches!(
+ ecx.tcx.get_global_alloc(alloc_id),
+ Some(interpret::GlobalAlloc::Memory(_))
+ );
+
+ if !is_allocated_in_another_const {
+ ecx.memory.deallocate(
+ ptr,
+ Some((size, align)),
+ interpret::MemoryKind::Machine(MemoryKind::Heap),
+ )?;
+ }
+ }
_ => {
return Err(ConstEvalErrKind::NeedsRfc(format!(
"calling intrinsic `{}`",
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 91b17d1..ba1d5f4 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -11,7 +11,8 @@
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use crate::interpret::{
- intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar,
+ intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
+ MemPlaceMeta, Scalar,
};
mod error;
@@ -132,49 +133,46 @@
}
}
-/// This function uses `unwrap` copiously, because an already validated constant
-/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
-/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
-/// `read_discriminant` needs to be able to handle that.
-pub(crate) fn destructure_const<'tcx>(
+/// This function should never fail for validated constants. However, it is also invoked from the
+/// pretty printer which might attempt to format invalid constants and in that case it might fail.
+pub(crate) fn try_destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- val: &'tcx ty::Const<'tcx>,
-) -> mir::DestructuredConst<'tcx> {
+ val: ty::Const<'tcx>,
+) -> InterpResult<'tcx, mir::DestructuredConst<'tcx>> {
trace!("destructure_const: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
- let op = ecx.const_to_op(val, None).unwrap();
+ let op = ecx.const_to_op(val, None)?;
// We go to `usize` as we cannot allocate anything bigger anyway.
- let (field_count, variant, down) = match val.ty.kind() {
+ let (field_count, variant, down) = match val.ty().kind() {
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
- ty::Adt(def, _) if def.variants.is_empty() => {
- return mir::DestructuredConst { variant: None, fields: &[] };
- }
ty::Adt(def, _) => {
- let variant = ecx.read_discriminant(&op).unwrap().1;
- let down = ecx.operand_downcast(&op, variant).unwrap();
+ let variant = ecx.read_discriminant(&op)?.1;
+ let down = ecx.operand_downcast(&op, variant)?;
(def.variants[variant].fields.len(), Some(variant), down)
}
ty::Tuple(substs) => (substs.len(), None, op),
_ => bug!("cannot destructure constant {:?}", val),
};
- let fields_iter = (0..field_count).map(|i| {
- let field_op = ecx.operand_field(&down, i).unwrap();
- let val = op_to_const(&ecx, &field_op);
- ty::Const::from_value(tcx, val, field_op.layout.ty)
- });
- let fields = tcx.arena.alloc_from_iter(fields_iter);
+ let fields = (0..field_count)
+ .map(|i| {
+ let field_op = ecx.operand_field(&down, i)?;
+ let val = op_to_const(&ecx, &field_op);
+ Ok(ty::Const::from_value(tcx, val, field_op.layout.ty))
+ })
+ .collect::<InterpResult<'tcx, Vec<_>>>()?;
+ let fields = tcx.arena.alloc_from_iter(fields);
- mir::DestructuredConst { variant, fields }
+ Ok(mir::DestructuredConst { variant, fields })
}
pub(crate) fn deref_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- val: &'tcx ty::Const<'tcx>,
-) -> &'tcx ty::Const<'tcx> {
+ val: ty::Const<'tcx>,
+) -> ty::Const<'tcx> {
trace!("deref_const: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.const_to_op(val, None).unwrap();
@@ -194,7 +192,7 @@
// In case of unsized types, figure out the real type behind.
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
ty::Str => bug!("there's no sized equivalent of a `str`"),
- ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
+ ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
_ => bug!(
"type {} should not have metadata, but had {:?}",
mplace.layout.ty,
@@ -203,5 +201,5 @@
},
};
- tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
+ tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
}
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 4c4b0bd..e2c4eb1 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -315,7 +315,7 @@
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
| (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
- self.unsize_into_ptr(src, dest, s, c)
+ self.unsize_into_ptr(src, dest, *s, *c)
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 0a8112d..1b86bcf 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -509,20 +509,18 @@
instance: ty::InstanceDef<'tcx>,
promoted: Option<mir::Promoted>,
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
- // do not continue if typeck errors occurred (can only occur in local crate)
let def = instance.with_opt_param();
- if let Some(def) = def.as_local() {
- if self.tcx.has_typeck_results(def.did) {
- if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {
- throw_inval!(AlreadyReported(error_reported))
- }
- }
- }
trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
- if let Some(promoted) = promoted {
- return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
+ let body = if let Some(promoted) = promoted {
+ &self.tcx.promoted_mir_opt_const_arg(def)[promoted]
+ } else {
+ M::load_mir(self, instance)?
+ };
+ // do not continue if typeck errors occurred (can only occur in local crate)
+ if let Some(err) = body.tainted_by_errors {
+ throw_inval!(AlreadyReported(err));
}
- M::load_mir(self, instance)
+ Ok(body)
}
/// Call this on things you got out of the MIR (so it is as generic as the current
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
index ca000f9..e6f243e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
@@ -68,7 +68,7 @@
}
}
- fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
self.pretty_print_const(ct, false)
}
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index dfec450..ec5eafc 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -561,20 +561,20 @@
/// "universe" (param_env).
pub fn const_to_op(
&self,
- val: &ty::Const<'tcx>,
+ val: ty::Const<'tcx>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- match val.val {
+ match val.val() {
ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
ty::ConstKind::Unevaluated(uv) => {
- let instance = self.resolve(uv.def, uv.substs(*self.tcx))?;
+ let instance = self.resolve(uv.def, uv.substs)?;
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)
}
- ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout),
+ ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty(), layout),
}
}
@@ -584,8 +584,8 @@
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
match val {
- mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout),
- mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout),
+ mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout),
+ mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout),
}
}
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 818b95b..7b06ffa 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -462,7 +462,7 @@
let (meta, ty) = match base.layout.ty.kind() {
// It is not nice to match on the type, but that seems to be the only way to
// implement this.
- ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)),
+ ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)),
ty::Slice(..) => {
let len = Scalar::from_machine_usize(inner_len, self);
(MemPlaceMeta::Meta(len), base.layout.ty)
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 3daa1d3..57ba9b4 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -140,8 +140,6 @@
// Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly.
Nop => {}
-
- LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
}
self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index a16388d..e17bd9a 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -3,13 +3,17 @@
use std::convert::TryInto;
use std::ops::ControlFlow;
-/// Returns `true` if a used generic parameter requires substitution.
+/// Checks whether a type contains generic parameters which require substitution.
+///
+/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
+/// types may be "concrete enough" even though they still contain generic parameters in
+/// case these parameters are unused.
crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
where
T: TypeFoldable<'tcx>,
{
debug!("ensure_monomorphic_enough: ty={:?}", ty);
- if !ty.potentially_needs_subst() {
+ if !ty.needs_subst() {
return Ok(());
}
@@ -21,12 +25,8 @@
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
type BreakTy = FoundParam;
- 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.potentially_needs_subst() {
+ if !ty.needs_subst() {
return ControlFlow::CONTINUE;
}
@@ -44,7 +44,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.definitely_needs_subst(self.tcx)) {
+ match (is_used, subst.needs_subst()) {
// Just in case there are closures or generators within this subst,
// recurse.
(true, true) => return subst.super_visit_with(self),
@@ -55,7 +55,7 @@
assert!(matches!(ty.kind(), ty::Param(_)))
}
ty::subst::GenericArgKind::Const(ct) => {
- assert!(matches!(ct.val, ty::ConstKind::Param(_)))
+ assert!(matches!(ct.val(), ty::ConstKind::Param(_)))
}
ty::subst::GenericArgKind::Lifetime(..) => (),
},
@@ -68,8 +68,8 @@
}
}
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- match c.val {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match c.val() {
ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
_ => c.super_visit_with(self),
}
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 5a398c2..4060bee 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -267,14 +267,14 @@
match layout.variants {
Variants::Single { index } => {
// Inside a variant
- PathElem::Field(def.variants[index].fields[field].ident.name)
+ PathElem::Field(def.variants[index].fields[field].name)
}
Variants::Multiple { .. } => bug!("we handled variants above"),
}
}
// other ADTs
- ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),
+ ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].name),
// arrays/slices
ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field),
@@ -553,7 +553,7 @@
{
// A mutable reference inside a const? That does not seem right (except if it is
// a ZST).
- let layout = self.ecx.layout_of(ty)?;
+ let layout = self.ecx.layout_of(*ty)?;
if !layout.is_zst() {
throw_validation_failure!(self.path, { "mutable reference in a `const`" });
}
@@ -726,7 +726,7 @@
new_op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let name = match old_op.layout.ty.kind() {
- ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
+ ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].name),
// Generators also have variants
ty::Generator(..) => PathElem::GeneratorState(variant_id),
_ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
@@ -837,7 +837,7 @@
// This is the length of the array/slice.
let len = mplace.len(self.ecx)?;
// This is the element type size.
- let layout = self.ecx.layout_of(tys)?;
+ let layout = self.ecx.layout_of(*tys)?;
// This is the size in bytes of the whole array. (This checks for overflow.)
let size = layout.size * len;
@@ -896,7 +896,7 @@
// Fast path for arrays and slices of ZSTs. We only need to check a single ZST element
// of an array and not all of them, because there's only a single value of a specific
// ZST type, so either validation fails for all elements or none.
- ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => {
+ ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(*tys)?.is_zst() => {
// Validate just the first element (if any).
self.walk_aggregate(op, fields.take(1))?
}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 92854af..77d312f 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -22,6 +22,7 @@
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
@@ -40,9 +41,9 @@
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
providers.const_caller_location = const_eval::const_caller_location;
- providers.destructure_const = |tcx, param_env_and_value| {
+ providers.try_destructure_const = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
- const_eval::destructure_const(tcx, param_env, value)
+ const_eval::try_destructure_const(tcx, param_env, value).ok()
};
providers.const_to_valtree = |tcx, param_env_and_value| {
let (param_env, raw) = param_env_and_value.into_parts();
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index dd749c0..095c8f8 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -14,6 +14,7 @@
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::SelectionContext;
use std::mem;
@@ -120,7 +121,7 @@
fn in_return_place(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
- error_occured: Option<ErrorReported>,
+ tainted_by_errors: Option<ErrorReported>,
) -> ConstQualifs {
// Find the `Return` terminator if one exists.
//
@@ -134,7 +135,9 @@
.map(|(bb, _)| bb);
let return_block = match return_block {
- None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured),
+ None => {
+ return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
+ }
Some(bb) => bb,
};
@@ -166,7 +169,7 @@
needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
custom_eq,
- error_occured,
+ tainted_by_errors,
}
}
}
@@ -221,8 +224,7 @@
// Prevent const trait methods from being annotated as `stable`.
// FIXME: Do this as part of stability checking.
if self.is_const_stable_const_fn() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
+ if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
self.ccx
.tcx
.sess
@@ -292,13 +294,13 @@
}
/// Emits an error if an expression cannot be evaluated in the current context.
- pub fn check_op(&mut self, op: impl NonConstOp) {
+ pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) {
self.check_op_spanned(op, self.span);
}
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
/// context.
- pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
+ pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
let gate = match op.status_in_item(self.ccx) {
Status::Allowed => return,
@@ -348,7 +350,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(self.tcx) {
+ for ty in ty.walk() {
let ty = match ty.unpack() {
GenericArgKind::Type(ty) => ty,
@@ -752,10 +754,6 @@
self.super_statement(statement, location);
match statement.kind {
- StatementKind::LlvmInlineAsm { .. } => {
- self.check_op(ops::InlineAsm);
- }
-
StatementKind::Assign(..)
| StatementKind::SetDiscriminant { .. }
| StatementKind::FakeRead(..)
@@ -776,7 +774,7 @@
self.super_terminator(terminator, location);
match &terminator.kind {
- TerminatorKind::Call { func, args, .. } => {
+ TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
let caller = self.def_id().to_def_id();
@@ -800,20 +798,24 @@
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
if !self.tcx.features().const_trait_impl {
- self.check_op(ops::FnCallNonConst(Some((callee, substs))));
+ self.check_op(ops::FnCallNonConst {
+ caller,
+ callee,
+ substs,
+ span: *fn_span,
+ from_hir_call: *from_hir_call,
+ });
return;
}
let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
- let obligation = Obligation::new(
- ObligationCause::dummy(),
- param_env,
- Binder::dummy(TraitPredicate {
- trait_ref,
- constness: ty::BoundConstness::ConstIfConst,
- polarity: ty::ImplPolarity::Positive,
- }),
- );
+ let poly_trait_pred = Binder::dummy(TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ });
+ let obligation =
+ Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
let implsrc = tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
@@ -840,22 +842,61 @@
substs = InternalSubsts::identity_for_item(tcx, did);
callee = did;
}
+
+ if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
+ self.check_op(ops::FnCallNonConst {
+ caller,
+ callee,
+ substs,
+ span: *fn_span,
+ from_hir_call: *from_hir_call,
+ });
+ return;
+ }
}
_ 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 callee_trait.is_some()
+ && tcx.has_attr(caller, sym::default_method_body_is_const)
+ && callee_trait == tcx.trait_of_item(caller)
+ // Can only call methods when it's `<Self as TheTrait>::f`.
+ && tcx.types.self_param == substs.type_at(0)
+ {
+ nonconst_call_permission = true;
}
if !nonconst_call_permission {
- self.check_op(ops::FnCallNonConst(None));
+ let obligation = Obligation::new(
+ ObligationCause::dummy_with_span(*fn_span),
+ param_env,
+ tcx.mk_predicate(
+ poly_trait_pred.map_bound(ty::PredicateKind::Trait),
+ ),
+ );
+
+ // improve diagnostics by showing what failed. Our requirements are stricter this time
+ // as we are going to error again anyways.
+ tcx.infer_ctxt().enter(|infcx| {
+ if let Err(e) = implsrc {
+ infcx.report_selection_error(
+ obligation.clone(),
+ &obligation,
+ &e,
+ false,
+ );
+ }
+ });
+
+ self.check_op(ops::FnCallNonConst {
+ caller,
+ callee,
+ substs,
+ span: *fn_span,
+ from_hir_call: *from_hir_call,
+ });
return;
}
}
@@ -924,7 +965,13 @@
}
if !nonconst_call_permission {
- self.check_op(ops::FnCallNonConst(None));
+ self.check_op(ops::FnCallNonConst {
+ caller,
+ callee,
+ substs,
+ span: *fn_span,
+ from_hir_call: *from_hir_call,
+ });
return;
}
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 24c4a49..8c3f8e8 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -3,14 +3,22 @@
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
+use rustc_middle::mir;
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::{mir, ty::AssocKind};
+use rustc_middle::ty::{
+ suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
+};
+use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
-use rustc_span::{symbol::Ident, Span, Symbol};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, Span, Symbol};
+use rustc_trait_selection::traits::SelectionContext;
use super::ConstCx;
+use crate::util::{call_kind, CallDesugaringKind, CallKind};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
@@ -29,9 +37,9 @@
}
/// An operation that is not *always* allowed in a const context.
-pub trait NonConstOp: std::fmt::Debug {
+pub trait NonConstOp<'tcx>: std::fmt::Debug {
/// Returns an enum indicating whether this operation is allowed within the given item.
- fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+ fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Forbidden
}
@@ -39,13 +47,13 @@
DiagnosticImportance::Primary
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
}
#[derive(Debug)]
pub struct FloatingPointOp;
-impl NonConstOp for FloatingPointOp {
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
+ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() == hir::ConstContext::ConstFn {
Status::Unstable(sym::const_fn_floating_point_arithmetic)
} else {
@@ -53,7 +61,7 @@
}
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_floating_point_arithmetic,
@@ -66,77 +74,229 @@
/// A function call where the callee is a pointer.
#[derive(Debug)]
pub struct FnCallIndirect;
-impl NonConstOp for FnCallIndirect {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
}
}
/// A function call where the callee is not marked as `const`.
-#[derive(Debug)]
-pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
-impl<'a> NonConstOp for FnCallNonConst<'a> {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- let mut err = struct_span_err!(
- ccx.tcx.sess,
- span,
- E0015,
- "calls in {}s are limited to constant functions, \
- tuple structs and tuple variants",
- ccx.const_kind(),
- );
+#[derive(Debug, Clone, Copy)]
+pub struct FnCallNonConst<'tcx> {
+ pub caller: DefId,
+ pub callee: DefId,
+ pub substs: SubstsRef<'tcx>,
+ pub span: Span,
+ pub from_hir_call: bool,
+}
- if let FnCallNonConst(Some((callee, substs))) = *self {
- if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
- if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
- ccx.tcx,
- Ident::with_dummy_span(sym::eq),
- AssocKind::Fn,
- trait_def_id,
- ) {
- if callee == eq_item.def_id && substs.len() == 2 {
- match (substs[0].unpack(), substs[1].unpack()) {
- (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
- if self_ty == rhs_ty
- && self_ty.is_ref()
- && self_ty.peel_refs().is_primitive() =>
- {
- let mut num_refs = 0;
- let mut tmp_ty = self_ty;
- while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
- num_refs += 1;
- tmp_ty = inner_ty;
- }
- let deref = "*".repeat(num_refs);
+impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> {
+ let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
+ let ConstCx { tcx, param_env, .. } = *ccx;
- if let Ok(call_str) =
- ccx.tcx.sess.source_map().span_to_snippet(span)
- {
- if let Some(eq_idx) = call_str.find("==") {
- if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
- .find(|c: char| !c.is_whitespace())
- {
- let rhs_pos = span.lo()
- + BytePos::from_usize(eq_idx + 2 + rhs_idx);
- let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
- err.multipart_suggestion(
- "consider dereferencing here",
- vec![
- (span.shrink_to_lo(), deref.clone()),
- (rhs_span, deref),
- ],
- Applicability::MachineApplicable,
- );
- }
+ let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| {
+ let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
+
+ match self_ty.kind() {
+ Param(param_ty) => {
+ debug!(?param_ty);
+ if let Some(generics) = caller
+ .as_local()
+ .map(|id| tcx.hir().local_def_id_to_hir_id(id))
+ .map(|id| tcx.hir().get(id))
+ .as_ref()
+ .and_then(|node| node.generics())
+ {
+ let constraint = with_no_trimmed_paths(|| {
+ format!("~const {}", trait_ref.print_only_trait_path())
+ });
+ suggest_constraining_type_param(
+ tcx,
+ generics,
+ &mut err,
+ ¶m_ty.name.as_str(),
+ &constraint,
+ None,
+ );
+ }
+ }
+ Adt(..) => {
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ Binder::dummy(TraitPredicate {
+ trait_ref,
+ constness: BoundConstness::NotConst,
+ polarity: ImplPolarity::Positive,
+ }),
+ );
+
+ let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ selcx.select(&obligation)
+ });
+
+ if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
+ let span =
+ tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
+ err.span_note(span, "impl defined here, but it is not `const`");
+ }
+ }
+ _ => {}
+ }
+
+ err
+ };
+
+ let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
+
+ debug!(?call_kind);
+
+ let mut err = match call_kind {
+ CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
+ macro_rules! error {
+ ($fmt:literal) => {
+ struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
+ };
+ }
+
+ let err = match kind {
+ CallDesugaringKind::ForLoopIntoIter => {
+ error!("cannot convert `{}` into an iterator in {}s")
+ }
+ CallDesugaringKind::QuestionBranch => {
+ error!("`?` cannot determine the branch of `{}` in {}s")
+ }
+ CallDesugaringKind::QuestionFromResidual => {
+ error!("`?` cannot convert from residual of `{}` in {}s")
+ }
+ CallDesugaringKind::TryBlockFromOutput => {
+ error!("`try` block cannot convert `{}` to the result in {}s")
+ }
+ };
+
+ diag_trait(err, self_ty, kind.trait_def_id(tcx))
+ }
+ CallKind::FnCall { fn_trait_id, self_ty } => {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0015,
+ "cannot call non-const closure in {}s",
+ ccx.const_kind(),
+ );
+
+ match self_ty.kind() {
+ FnDef(def_id, ..) => {
+ let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id));
+ if ccx.tcx.is_const_fn_raw(*def_id) {
+ span_bug!(span, "calling const FnDef errored when it shouldn't");
+ }
+
+ err.span_note(span, "function defined here, but it is not `const`");
+ }
+ FnPtr(..) => {
+ err.note(&format!(
+ "function pointers need an RFC before allowed to be called in {}s",
+ ccx.const_kind()
+ ));
+ }
+ Closure(..) => {
+ err.note(&format!(
+ "closures need an RFC before allowed to be called in {}s",
+ ccx.const_kind()
+ ));
+ }
+ _ => {}
+ }
+
+ diag_trait(err, self_ty, fn_trait_id)
+ }
+ CallKind::Operator { trait_id, self_ty, .. } => {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0015,
+ "cannot call non-const operator in {}s",
+ ccx.const_kind()
+ );
+
+ if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
+ match (substs[0].unpack(), substs[1].unpack()) {
+ (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
+ if self_ty == rhs_ty
+ && self_ty.is_ref()
+ && self_ty.peel_refs().is_primitive() =>
+ {
+ let mut num_refs = 0;
+ let mut tmp_ty = self_ty;
+ while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
+ num_refs += 1;
+ tmp_ty = *inner_ty;
+ }
+ let deref = "*".repeat(num_refs);
+
+ if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
+ if let Some(eq_idx) = call_str.find("==") {
+ if let Some(rhs_idx) =
+ call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
+ {
+ let rhs_pos =
+ span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+ let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+ err.multipart_suggestion(
+ "consider dereferencing here",
+ vec![
+ (span.shrink_to_lo(), deref.clone()),
+ (rhs_span, deref),
+ ],
+ Applicability::MachineApplicable,
+ );
}
}
}
- _ => {}
}
+ _ => {}
}
}
+
+ diag_trait(err, self_ty, trait_id)
}
- }
+ CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0015,
+ "cannot perform deref coercion on `{}` in {}s",
+ self_ty,
+ ccx.const_kind()
+ );
+
+ err.note(&format!("attempting to deref into `{}`", deref_target_ty));
+
+ // Check first whether the source is accessible (issue #87060)
+ if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
+ err.span_note(deref_target, "deref defined here");
+ }
+
+ diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap())
+ }
+ _ => struct_span_err!(
+ ccx.tcx.sess,
+ span,
+ E0015,
+ "cannot call non-const fn `{}` in {}s",
+ ccx.tcx.def_path_str_with_substs(callee, substs),
+ ccx.const_kind(),
+ ),
+ };
+
+ err.note(&format!(
+ "calls in {}s are limited to constant functions, \
+ tuple structs and tuple variants",
+ ccx.const_kind(),
+ ));
err
}
@@ -148,8 +308,8 @@
#[derive(Debug)]
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
-impl NonConstOp for FnCallUnstable {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let FnCallUnstable(def_id, feature) = *self;
let mut err = ccx.tcx.sess.struct_span_err(
@@ -174,8 +334,8 @@
#[derive(Debug)]
pub struct FnPtrCast;
-impl NonConstOp for FnPtrCast {
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
+ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@@ -183,7 +343,7 @@
}
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_fn_ptr_basics,
@@ -195,8 +355,8 @@
#[derive(Debug)]
pub struct Generator(pub hir::GeneratorKind);
-impl NonConstOp for Generator {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for Generator {
+ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
Status::Unstable(sym::const_async_blocks)
} else {
@@ -204,7 +364,7 @@
}
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
@@ -216,8 +376,8 @@
#[derive(Debug)]
pub struct HeapAllocation;
-impl NonConstOp for HeapAllocation {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -240,8 +400,8 @@
#[derive(Debug)]
pub struct InlineAsm;
-impl NonConstOp for InlineAsm {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for InlineAsm {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
ccx.tcx.sess,
span,
@@ -256,8 +416,8 @@
pub struct LiveDrop {
pub dropped_at: Option<Span>,
}
-impl NonConstOp for LiveDrop {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for LiveDrop {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -276,8 +436,8 @@
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
/// the final value of the constant.
pub struct TransientCellBorrow;
-impl NonConstOp for TransientCellBorrow {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
+ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_refs_to_cell)
}
fn importance(&self) -> DiagnosticImportance {
@@ -285,7 +445,7 @@
// not additionally emit a feature gate error if activating the feature gate won't work.
DiagnosticImportance::Secondary
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_refs_to_cell,
@@ -300,8 +460,8 @@
/// the final value of the constant, and thus we cannot allow this (for now). We may allow
/// it in the future for static items.
pub struct CellBorrow;
-impl NonConstOp for CellBorrow {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -337,8 +497,8 @@
/// static or const items.
pub struct MutBorrow(pub hir::BorrowKind);
-impl NonConstOp for MutBorrow {
- fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for MutBorrow {
+ fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Forbidden
}
@@ -348,7 +508,7 @@
DiagnosticImportance::Secondary
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
@@ -382,12 +542,12 @@
#[derive(Debug)]
pub struct TransientMutBorrow(pub hir::BorrowKind);
-impl NonConstOp for TransientMutBorrow {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
+ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
@@ -404,8 +564,8 @@
#[derive(Debug)]
pub struct MutDeref;
-impl NonConstOp for MutDeref {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for MutDeref {
+ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
@@ -414,7 +574,7 @@
DiagnosticImportance::Secondary
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@@ -427,8 +587,8 @@
/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
#[derive(Debug)]
pub struct PanicNonStr;
-impl NonConstOp for PanicNonStr {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx.sess.struct_span_err(
span,
"argument to `panic!()` in a const context must have type `&str`",
@@ -441,8 +601,8 @@
/// allocation base addresses that are not known at compile-time.
#[derive(Debug)]
pub struct RawPtrComparison;
-impl NonConstOp for RawPtrComparison {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = ccx
.tcx
.sess
@@ -457,12 +617,12 @@
#[derive(Debug)]
pub struct RawMutPtrDeref;
-impl NonConstOp for RawMutPtrDeref {
+impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@@ -477,8 +637,8 @@
/// allocation base addresses that are not known at compile-time.
#[derive(Debug)]
pub struct RawPtrToIntCast;
-impl NonConstOp for RawPtrToIntCast {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = ccx
.tcx
.sess
@@ -494,8 +654,8 @@
/// An access to a (non-thread-local) `static`.
#[derive(Debug)]
pub struct StaticAccess;
-impl NonConstOp for StaticAccess {
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for StaticAccess {
+ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if let hir::ConstContext::Static(_) = ccx.const_kind() {
Status::Allowed
} else {
@@ -503,7 +663,7 @@
}
}
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -528,8 +688,8 @@
/// An access to a thread-local `static`.
#[derive(Debug)]
pub struct ThreadLocalAccess;
-impl NonConstOp for ThreadLocalAccess {
- fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
ccx.tcx.sess,
span,
@@ -546,8 +706,8 @@
#[derive(Debug)]
pub struct MutRef(pub mir::LocalKind);
- impl NonConstOp for MutRef {
- fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+ impl<'tcx> NonConstOp<'tcx> for MutRef {
+ fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
@@ -560,11 +720,7 @@
}
}
- fn build_error<'tcx>(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@@ -576,7 +732,7 @@
#[derive(Debug)]
pub struct FnPtr(pub mir::LocalKind);
- impl NonConstOp for FnPtr {
+ impl<'tcx> NonConstOp<'tcx> for FnPtr {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -586,7 +742,7 @@
}
}
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@@ -594,11 +750,7 @@
}
}
- fn build_error<'tcx>(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_fn_ptr_basics,
@@ -610,16 +762,12 @@
#[derive(Debug)]
pub struct ImplTrait;
- impl NonConstOp for ImplTrait {
+ impl<'tcx> NonConstOp<'tcx> for ImplTrait {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
Status::Unstable(sym::const_impl_trait)
}
- fn build_error<'tcx>(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_impl_trait,
@@ -631,7 +779,7 @@
#[derive(Debug)]
pub struct TraitBound(pub mir::LocalKind);
- impl NonConstOp for TraitBound {
+ impl<'tcx> NonConstOp<'tcx> for TraitBound {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -641,7 +789,7 @@
}
}
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@@ -649,11 +797,7 @@
}
}
- fn build_error<'tcx>(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_trait_bound,
@@ -674,7 +818,7 @@
#[derive(Debug)]
pub struct DynTrait(pub mir::LocalKind);
- impl NonConstOp for DynTrait {
+ impl<'tcx> NonConstOp<'tcx> for DynTrait {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -684,7 +828,7 @@
}
}
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+ fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@@ -692,11 +836,7 @@
}
}
- fn build_error<'tcx>(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_trait_bound,
@@ -718,16 +858,12 @@
/// A trait bound with the `?const Trait` opt-out
#[derive(Debug)]
pub struct TraitBoundNotConst;
- impl NonConstOp for TraitBoundNotConst {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+ impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
+ fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_trait_bound_opt_out)
}
- fn build_error<'tcx>(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx> {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_trait_bound_opt_out,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 27f2da3..639b798 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -4,11 +4,12 @@
use rustc_errors::ErrorReported;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::TraitEngine;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::{
- self, ImplSource, Obligation, ObligationCause, SelectionContext,
+ self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext,
};
use super::ConstCx;
@@ -16,14 +17,14 @@
pub fn in_any_value_of_ty<'tcx>(
cx: &ConstCx<'_, 'tcx>,
ty: Ty<'tcx>,
- error_occured: Option<ErrorReported>,
+ tainted_by_errors: Option<ErrorReported>,
) -> ConstQualifs {
ConstQualifs {
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
- error_occured,
+ tainted_by_errors,
}
}
@@ -145,15 +146,10 @@
qualifs.needs_non_const_drop
}
- fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
- // Avoid selecting for simple cases.
- match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() {
- Ok([]) => return false,
- Err(ty::util::AlwaysRequiresDrop) => return true,
- // If we've got a single component, select with that
- // to increase the chance that we hit the selection cache.
- Ok([t]) => ty = t,
- Ok([..]) => {}
+ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+ // Avoid selecting for simple cases, such as builtin types.
+ if ty::util::is_trivially_const_drop(ty) {
+ return false;
}
let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else {
@@ -161,28 +157,50 @@
// without having the lang item present.
return false;
};
- let trait_ref =
- ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) };
+
let obligation = Obligation::new(
ObligationCause::dummy(),
cx.param_env,
ty::Binder::dummy(ty::TraitPredicate {
- trait_ref,
+ trait_ref: ty::TraitRef {
+ def_id: drop_trait,
+ substs: cx.tcx.mk_substs_trait(ty, &[]),
+ },
constness: ty::BoundConstness::ConstIfConst,
polarity: ty::ImplPolarity::Positive,
}),
);
- let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
+ cx.tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation)
- });
- !matches!(
- implsrc,
- Ok(Some(
+ let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
+ // If we couldn't select a const drop candidate, then it's bad
+ return true;
+ };
+
+ if !matches!(
+ impl_src,
ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
- ))
- )
+ ) {
+ // If our const drop candidate is not ConstDrop or implied by the param env,
+ // then it's bad
+ return true;
+ }
+
+ if impl_src.borrow_nested_obligations().is_empty() {
+ return false;
+ }
+
+ // If we successfully found one, then select all of the predicates
+ // implied by our const drop impl.
+ let mut fcx = FulfillmentContext::new();
+ for nested in impl_src.nested_obligations() {
+ fcx.register_predicate_obligation(&infcx, nested);
+ }
+
+ // If we had any errors, then it's bad
+ !fcx.select_all_or_error(&infcx).is_empty()
+ })
}
fn in_adt_inherently<'tcx>(
@@ -210,8 +228,7 @@
// because that component may be part of an enum variant (e.g.,
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
// structural-match (`Option::None`).
- let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id());
- traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
+ traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
}
fn in_adt_inherently<'tcx>(
@@ -338,7 +355,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() {
// Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
// only for `NeedsNonConstDrop` with precise drop checking. This is the only const
// check performed after the promotion. Verify that with an assertion.
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 55fba5d..cacc001 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -496,7 +496,7 @@
if matches!(kind, CastKind::Misc) {
let operand_ty = operand.ty(self.body, self.tcx);
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+ let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
// ptr-to-int casts are not possible in consts and thus not promotable
return Err(Unpromotable);
@@ -839,21 +839,17 @@
span,
user_ty: None,
literal: tcx
- .mk_const(ty::Const {
+ .mk_const(ty::ConstS {
ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
- 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)
- }
- },
- )),
+ 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)
+ }
+ }),
promoted: Some(promoted_id),
}),
})
@@ -969,7 +965,6 @@
scope.parent_scope = None;
let promoted = Body::new(
- tcx,
body.source, // `promoted` gets filled in below
IndexVec::new(),
IndexVec::from_elem_n(scope, 1),
@@ -979,6 +974,7 @@
vec![],
body.span,
body.generator_kind(),
+ body.tainted_by_errors,
);
let promoter = Promoter {
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index c3f81a3..cf15fc4 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -55,6 +55,7 @@
reachable_blocks: traversal::reachable_as_bitset(body),
storage_liveness,
place_cache: Vec::new(),
+ value_cache: Vec::new(),
}
.visit_body(body);
}
@@ -109,6 +110,7 @@
reachable_blocks: BitSet<BasicBlock>,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
place_cache: Vec<PlaceRef<'tcx>>,
+ value_cache: Vec<u128>,
}
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@@ -352,7 +354,6 @@
StatementKind::SetDiscriminant { .. }
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
- | StatementKind::LlvmInlineAsm(..)
| StatementKind::Retag(_, _)
| StatementKind::Coverage(_)
| StatementKind::Nop => {}
@@ -399,6 +400,22 @@
self.check_edge(location, target, EdgeKind::Normal);
}
self.check_edge(location, targets.otherwise(), EdgeKind::Normal);
+
+ self.value_cache.clear();
+ self.value_cache.extend(targets.iter().map(|(value, _)| value));
+ let all_len = self.value_cache.len();
+ self.value_cache.sort_unstable();
+ self.value_cache.dedup();
+ let has_duplicates = all_len != self.value_cache.len();
+ if has_duplicates {
+ self.fail(
+ location,
+ format!(
+ "duplicated values in `SwitchInt` terminator: {:?}",
+ terminator.kind,
+ ),
+ );
+ }
}
TerminatorKind::Drop { target, unwind, .. } => {
self.check_edge(location, *target, EdgeKind::Normal);
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
new file mode 100644
index 0000000..11bb950
--- /dev/null
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -0,0 +1,143 @@
+//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`,
+//! as well as errors when attempting to call a non-const function in a const
+//! context.
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, DesugaringKind, Span};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum CallDesugaringKind {
+ /// for _ in x {} calls x.into_iter()
+ ForLoopIntoIter,
+ /// x? calls x.branch()
+ QuestionBranch,
+ /// x? calls type_of(x)::from_residual()
+ QuestionFromResidual,
+ /// try { ..; x } calls type_of(x)::from_output(x)
+ TryBlockFromOutput,
+}
+
+impl CallDesugaringKind {
+ pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
+ match self {
+ Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
+ Self::QuestionBranch | Self::TryBlockFromOutput => {
+ tcx.lang_items().try_trait().unwrap()
+ }
+ Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
+ }
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum CallKind<'tcx> {
+ /// A normal method call of the form `receiver.foo(a, b, c)`
+ Normal {
+ self_arg: Option<Ident>,
+ desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
+ /// Whether the self type of the method call has an `.as_ref()` method.
+ /// Used for better diagnostics.
+ is_option_or_result: bool,
+ },
+ /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
+ FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
+ /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
+ Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
+ DerefCoercion {
+ /// The `Span` of the `Target` associated type
+ /// in the `Deref` impl we are using.
+ deref_target: Span,
+ /// The type `T::Deref` we are dereferencing to
+ deref_target_ty: Ty<'tcx>,
+ self_ty: Ty<'tcx>,
+ },
+}
+
+pub fn call_kind<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ method_did: DefId,
+ method_substs: SubstsRef<'tcx>,
+ fn_call_span: Span,
+ from_hir_call: bool,
+ self_arg: Option<Ident>,
+) -> CallKind<'tcx> {
+ let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
+ AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
+ AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
+ });
+
+ let fn_call = parent
+ .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
+
+ let operator = (!from_hir_call)
+ .then(|| parent)
+ .flatten()
+ .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
+
+ let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
+
+ // Check for a 'special' use of 'self' -
+ // an FnOnce call, an operator (e.g. `<<`), or a
+ // deref coercion.
+ let kind = if let Some(&trait_id) = fn_call {
+ Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
+ } else if let Some(&trait_id) = operator {
+ Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
+ } else if is_deref {
+ let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
+ Instance::resolve(tcx, param_env, deref_target, method_substs).transpose()
+ });
+ if let Some(Ok(instance)) = deref_target {
+ let deref_target_ty = instance.ty(tcx, param_env);
+ Some(CallKind::DerefCoercion {
+ deref_target: tcx.def_span(instance.def_id()),
+ deref_target_ty,
+ self_ty: method_substs.type_at(0),
+ })
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+
+ kind.unwrap_or_else(|| {
+ // This isn't a 'special' use of `self`
+ debug!(?method_did, ?fn_call_span);
+ let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn()
+ && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
+ {
+ Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0)))
+ } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
+ if Some(method_did) == tcx.lang_items().branch_fn() {
+ Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0)))
+ } else if Some(method_did) == tcx.lang_items().from_residual_fn() {
+ Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0)))
+ } else {
+ None
+ }
+ } else if Some(method_did) == tcx.lang_items().from_output_fn()
+ && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
+ {
+ Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
+ } else {
+ None
+ };
+ let parent_self_ty = tcx
+ .parent(method_did)
+ .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+ .and_then(|did| match tcx.type_of(did).kind() {
+ ty::Adt(def, ..) => Some(def.did),
+ _ => None,
+ });
+ let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
+ });
+ CallKind::Normal { self_arg, desugaring, is_option_or_result }
+ })
+}
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 4a406f8..a1876be 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -1,8 +1,10 @@
pub mod aggregate;
mod alignment;
+mod call_kind;
pub mod collect_writes;
mod find_self_call;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
+pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use self::find_self_call::find_self_call;
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index e3395df..ad296c9 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@
[dependencies]
arrayvec = { version = "0.7", default-features = false }
ena = "0.14"
-indexmap = "1.5.1"
+indexmap = { version = "1.8.0", features = ["rustc-rayon"] }
tracing = "0.1"
jobserver_crate = { version = "0.1.13", package = "jobserver" }
rustc_serialize = { path = "../rustc_serialize" }
@@ -17,8 +17,8 @@
rustc_graphviz = { path = "../rustc_graphviz" }
cfg-if = "0.1.2"
stable_deref_trait = "1.0.0"
-rayon = { version = "0.3.1", package = "rustc-rayon" }
-rayon-core = { version = "0.3.1", package = "rustc-rayon-core" }
+rayon = { version = "0.3.2", package = "rustc-rayon" }
+rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
rustc-hash = "1.1.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_index = { path = "../rustc_index", package = "rustc_index" }
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index c9af35d..e931379 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -3,6 +3,9 @@
use std::convert::TryInto;
use std::hash::{Hash, Hasher};
+#[cfg(test)]
+mod tests;
+
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
#[repr(C)]
pub struct Fingerprint(u64, u64);
@@ -54,7 +57,7 @@
let c = a.wrapping_add(b);
- Fingerprint((c >> 64) as u64, c as u64)
+ Fingerprint(c as u64, (c >> 64) as u64)
}
pub fn to_hex(&self) -> String {
@@ -149,10 +152,10 @@
impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
#[inline]
- fn decode(d: &mut D) -> Result<Self, D::Error> {
+ fn decode(d: &mut D) -> Self {
let mut bytes = [0u8; 16];
- d.read_raw_bytes_into(&mut bytes)?;
- Ok(Fingerprint::from_le_bytes(bytes))
+ d.read_raw_bytes_into(&mut bytes);
+ Fingerprint::from_le_bytes(bytes)
}
}
@@ -195,8 +198,8 @@
impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
#[inline]
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- Fingerprint::decode(d).map(PackedFingerprint)
+ fn decode(d: &mut D) -> Self {
+ Self(Fingerprint::decode(d))
}
}
diff --git a/compiler/rustc_data_structures/src/fingerprint/tests.rs b/compiler/rustc_data_structures/src/fingerprint/tests.rs
new file mode 100644
index 0000000..9b0783e
--- /dev/null
+++ b/compiler/rustc_data_structures/src/fingerprint/tests.rs
@@ -0,0 +1,14 @@
+use super::*;
+
+// Check that `combine_commutative` is order independent.
+#[test]
+fn combine_commutative_is_order_independent() {
+ let a = Fingerprint::new(0xf6622fb349898b06, 0x70be9377b2f9c610);
+ let b = Fingerprint::new(0xa9562bf5a2a5303c, 0x67d9b6c82034f13d);
+ let c = Fingerprint::new(0x0d013a27811dbbc3, 0x9a3f7b3d9142ec43);
+ let permutations = [(a, b, c), (a, c, b), (b, a, c), (b, c, a), (c, a, b), (c, b, a)];
+ let f = a.combine_commutative(b).combine_commutative(c);
+ for p in &permutations {
+ assert_eq!(f, p.0.combine_commutative(p.1).combine_commutative(p.2));
+ }
+}
diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs
new file mode 100644
index 0000000..c79a5eb
--- /dev/null
+++ b/compiler/rustc_data_structures/src/intern.rs
@@ -0,0 +1,98 @@
+use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+use std::ptr;
+
+mod private {
+ #[derive(Clone, Copy, Debug)]
+ pub struct PrivateZst;
+}
+
+/// A reference to a value that is interned, and is known to be unique.
+///
+/// Note that it is possible to have a `T` and a `Interned<T>` that are (or
+/// refer to) equal but different values. But if you have two different
+/// `Interned<T>`s, they both refer to the same value, at a single location in
+/// memory. This means that equality and hashing can be done on the value's
+/// address rather than the value's contents, which can improve performance.
+///
+/// The `PrivateZst` field means you can pattern match with `Interned(v, _)`
+/// but you can only construct a `Interned` with `new_unchecked`, and not
+/// directly.
+#[derive(Debug)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst);
+
+impl<'a, T> Interned<'a, T> {
+ /// Create a new `Interned` value. The value referred to *must* be interned
+ /// and thus be unique, and it *must* remain unique in the future. This
+ /// function has `_unchecked` in the name but is not `unsafe`, because if
+ /// the uniqueness condition is violated condition it will cause incorrect
+ /// behaviour but will not affect memory safety.
+ #[inline]
+ pub const fn new_unchecked(t: &'a T) -> Self {
+ Interned(t, private::PrivateZst)
+ }
+}
+
+impl<'a, T> Clone for Interned<'a, T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'a, T> Copy for Interned<'a, T> {}
+
+impl<'a, T> Deref for Interned<'a, T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &T {
+ self.0
+ }
+}
+
+impl<'a, T> PartialEq for Interned<'a, T> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ // Pointer equality implies equality, due to the uniqueness constraint.
+ ptr::eq(self.0, other.0)
+ }
+}
+
+impl<'a, T> Eq for Interned<'a, T> {}
+
+// In practice you can't intern any `T` that doesn't implement `Eq`, because
+// that's needed for hashing. Therefore, we won't be interning any `T` that
+// implements `PartialOrd` without also implementing `Ord`. So we can have the
+// bound `T: Ord` here and avoid duplication with the `Ord` impl below.
+impl<'a, T: Ord> PartialOrd for Interned<'a, T> {
+ fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl<'a, T: Ord> Ord for Interned<'a, T> {
+ fn cmp(&self, other: &Interned<'a, T>) -> Ordering {
+ // Pointer equality implies equality, due to the uniqueness constraint,
+ // but the contents must be compared otherwise.
+ if ptr::eq(self.0, other.0) {
+ Ordering::Equal
+ } else {
+ let res = self.0.cmp(&other.0);
+ debug_assert_ne!(res, Ordering::Equal);
+ res
+ }
+ }
+}
+
+impl<'a, T> Hash for Interned<'a, T> {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // Pointer hashing is sufficient, due to the uniqueness constraint.
+ ptr::hash(self.0, s)
+ }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/intern/tests.rs b/compiler/rustc_data_structures/src/intern/tests.rs
new file mode 100644
index 0000000..09810a0
--- /dev/null
+++ b/compiler/rustc_data_structures/src/intern/tests.rs
@@ -0,0 +1,59 @@
+use super::*;
+use std::cmp::Ordering;
+
+#[derive(Debug)]
+struct S(u32);
+
+impl PartialEq for S {
+ fn eq(&self, _other: &Self) -> bool {
+ panic!("shouldn't be called");
+ }
+}
+
+impl Eq for S {}
+
+impl PartialOrd for S {
+ fn partial_cmp(&self, other: &S) -> Option<Ordering> {
+ // The `==` case should be handled by `Interned`.
+ assert_ne!(self.0, other.0);
+ self.0.partial_cmp(&other.0)
+ }
+}
+
+impl Ord for S {
+ fn cmp(&self, other: &S) -> Ordering {
+ // The `==` case should be handled by `Interned`.
+ assert_ne!(self.0, other.0);
+ self.0.cmp(&other.0)
+ }
+}
+
+#[test]
+fn test_uniq() {
+ let s1 = S(1);
+ let s2 = S(2);
+ let s3 = S(3);
+ let s4 = S(1); // violates uniqueness
+
+ let v1 = Interned::new_unchecked(&s1);
+ let v2 = Interned::new_unchecked(&s2);
+ let v3a = Interned::new_unchecked(&s3);
+ let v3b = Interned::new_unchecked(&s3);
+ let v4 = Interned::new_unchecked(&s4); // violates uniqueness
+
+ assert_ne!(v1, v2);
+ assert_ne!(v2, v3a);
+ assert_eq!(v1, v1);
+ assert_eq!(v3a, v3b);
+ assert_ne!(v1, v4); // same content but different addresses: not equal
+
+ assert_eq!(v1.cmp(&v2), Ordering::Less);
+ assert_eq!(v3a.cmp(&v2), Ordering::Greater);
+ assert_eq!(v1.cmp(&v1), Ordering::Equal); // only uses Interned::eq, not S::cmp
+ assert_eq!(v3a.cmp(&v3b), Ordering::Equal); // only uses Interned::eq, not S::cmp
+
+ assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less));
+ assert_eq!(v3a.partial_cmp(&v2), Some(Ordering::Greater));
+ assert_eq!(v1.partial_cmp(&v1), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp
+ assert_eq!(v3a.partial_cmp(&v3b), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp
+}
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 181e518..80f8314 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -21,11 +21,13 @@
#![feature(type_alias_impl_trait)]
#![feature(new_uninit)]
#![feature(once_cell)]
+#![feature(rustc_attrs)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(vec_into_raw_parts)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
@@ -67,12 +69,12 @@
pub mod functor;
pub mod fx;
pub mod graph;
+pub mod intern;
pub mod jobserver;
pub mod macros;
pub mod map_in_place;
pub mod obligation_forest;
pub mod owning_ref;
-pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
diff --git a/compiler/rustc_data_structures/src/ptr_key.rs b/compiler/rustc_data_structures/src/ptr_key.rs
deleted file mode 100644
index 440ccb0..0000000
--- a/compiler/rustc_data_structures/src/ptr_key.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use std::ops::Deref;
-use std::{hash, ptr};
-
-/// A wrapper around reference that compares and hashes like a pointer.
-/// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`.
-#[derive(Debug)]
-pub struct PtrKey<'a, T>(pub &'a T);
-
-impl<'a, T> Clone for PtrKey<'a, T> {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-impl<'a, T> Copy for PtrKey<'a, T> {}
-
-impl<'a, T> PartialEq for PtrKey<'a, T> {
- fn eq(&self, rhs: &Self) -> bool {
- ptr::eq(self.0, rhs.0)
- }
-}
-
-impl<'a, T> Eq for PtrKey<'a, T> {}
-
-impl<'a, T> hash::Hash for PtrKey<'a, T> {
- fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
- (self.0 as *const T).hash(hasher)
- }
-}
-
-impl<'a, T> Deref for PtrKey<'a, T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- self.0
- }
-}
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index 53062b9..6e5c061 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -202,28 +202,26 @@
hasher
}
- // A specialized write function for values with size <= 8.
#[inline]
- fn short_write<T>(&mut self, x: T) {
- let size = mem::size_of::<T>();
+ pub fn short_write<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
let nbuf = self.nbuf;
- debug_assert!(size <= 8);
+ debug_assert!(LEN <= 8);
debug_assert!(nbuf < BUFFER_SIZE);
- debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE);
+ debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
- if nbuf + size < BUFFER_SIZE {
+ if nbuf + LEN < BUFFER_SIZE {
unsafe {
// The memcpy call is optimized away because the size is known.
let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
- ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size);
+ ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
}
- self.nbuf = nbuf + size;
+ self.nbuf = nbuf + LEN;
return;
}
- unsafe { self.short_write_process_buffer(x) }
+ unsafe { self.short_write_process_buffer(bytes) }
}
// A specialized write function for values with size <= 8 that should only
@@ -233,18 +231,17 @@
// `self.nbuf` must cause `self.buf` to become fully initialized (and not
// overflow) if it wasn't already.
#[inline(never)]
- unsafe fn short_write_process_buffer<T>(&mut self, x: T) {
- let size = mem::size_of::<T>();
+ unsafe fn short_write_process_buffer<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
let nbuf = self.nbuf;
- debug_assert!(size <= 8);
+ debug_assert!(LEN <= 8);
debug_assert!(nbuf < BUFFER_SIZE);
- debug_assert!(nbuf + size >= BUFFER_SIZE);
- debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE);
+ debug_assert!(nbuf + LEN >= BUFFER_SIZE);
+ debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
// Copy first part of input into end of buffer, possibly into spill
// element. The memcpy call is optimized away because the size is known.
let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
- ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size);
+ ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
// Process buffer.
for i in 0..BUFFER_CAPACITY {
@@ -254,17 +251,17 @@
self.state.v0 ^= elem;
}
- // Copy remaining input into start of buffer by copying size - 1
- // elements from spill (at most size - 1 bytes could have overflowed
+ // Copy remaining input into start of buffer by copying LEN - 1
+ // elements from spill (at most LEN - 1 bytes could have overflowed
// into the spill). The memcpy call is optimized away because the size
- // is known. And the whole copy is optimized away for size == 1.
+ // is known. And the whole copy is optimized away for LEN == 1.
let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
- ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, size - 1);
+ ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1);
// This function should only be called when the write fills the buffer.
- // Therefore, when size == 1, the new `self.nbuf` must be zero. The size
- // is statically known, so the branch is optimized away.
- self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE };
+ // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
+ // LEN is statically known, so the branch is optimized away.
+ self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE };
self.processed += BUFFER_SIZE;
}
@@ -412,52 +409,52 @@
impl Hasher for SipHasher128 {
#[inline]
fn write_u8(&mut self, i: u8) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_u16(&mut self, i: u16) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_u32(&mut self, i: u32) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_u64(&mut self, i: u64) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_usize(&mut self, i: usize) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_i8(&mut self, i: i8) {
- self.short_write(i as u8);
+ self.short_write((i as u8).to_ne_bytes());
}
#[inline]
fn write_i16(&mut self, i: i16) {
- self.short_write(i as u16);
+ self.short_write((i as u16).to_ne_bytes());
}
#[inline]
fn write_i32(&mut self, i: i32) {
- self.short_write(i as u32);
+ self.short_write((i as u32).to_ne_bytes());
}
#[inline]
fn write_i64(&mut self, i: i64) {
- self.short_write(i as u64);
+ self.short_write((i as u64).to_ne_bytes());
}
#[inline]
fn write_isize(&mut self, i: isize) {
- self.short_write(i as usize);
+ self.short_write((i as usize).to_ne_bytes());
}
#[inline]
diff --git a/compiler/rustc_data_structures/src/snapshot_map/mod.rs b/compiler/rustc_data_structures/src/snapshot_map/mod.rs
index b4cc852..8a50179 100644
--- a/compiler/rustc_data_structures/src/snapshot_map/mod.rs
+++ b/compiler/rustc_data_structures/src/snapshot_map/mod.rs
@@ -13,6 +13,7 @@
pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>;
pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>;
+#[derive(Clone)]
pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> {
map: M,
undo_log: L,
@@ -30,6 +31,7 @@
}
}
+#[derive(Clone)]
pub enum UndoLog<K, V> {
Inserted(K),
Overwrite(K, V),
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 3da3517..31d6a42 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -80,22 +80,22 @@
#[inline]
fn write_u16(&mut self, i: u16) {
- self.state.write_u16(i.to_le());
+ self.state.short_write(i.to_le_bytes());
}
#[inline]
fn write_u32(&mut self, i: u32) {
- self.state.write_u32(i.to_le());
+ self.state.short_write(i.to_le_bytes());
}
#[inline]
fn write_u64(&mut self, i: u64) {
- self.state.write_u64(i.to_le());
+ self.state.short_write(i.to_le_bytes());
}
#[inline]
fn write_u128(&mut self, i: u128) {
- self.state.write_u128(i.to_le());
+ self.state.write(&i.to_le_bytes());
}
#[inline]
@@ -103,7 +103,7 @@
// Always treat usize as u64 so we get the same results on 32 and 64 bit
// platforms. This is important for symbol hashes when cross compiling,
// for example.
- self.state.write_u64((i as u64).to_le());
+ self.state.short_write((i as u64).to_le_bytes());
}
#[inline]
@@ -113,31 +113,59 @@
#[inline]
fn write_i16(&mut self, i: i16) {
- self.state.write_i16(i.to_le());
+ self.state.short_write((i as u16).to_le_bytes());
}
#[inline]
fn write_i32(&mut self, i: i32) {
- self.state.write_i32(i.to_le());
+ self.state.short_write((i as u32).to_le_bytes());
}
#[inline]
fn write_i64(&mut self, i: i64) {
- self.state.write_i64(i.to_le());
+ self.state.short_write((i as u64).to_le_bytes());
}
#[inline]
fn write_i128(&mut self, i: i128) {
- self.state.write_i128(i.to_le());
+ self.state.write(&(i as u128).to_le_bytes());
}
#[inline]
fn write_isize(&mut self, i: isize) {
- // Always treat isize as i64 so we get the same results on 32 and 64 bit
+ // Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit
// platforms. This is important for symbol hashes when cross compiling,
// for example. Sign extending here is preferable as it means that the
// same negative number hashes the same on both 32 and 64 bit platforms.
- self.state.write_i64((i as i64).to_le());
+ let value = i as u64;
+
+ // Cold path
+ #[cold]
+ #[inline(never)]
+ fn hash_value(state: &mut SipHasher128, value: u64) {
+ state.write_u8(0xFF);
+ state.short_write(value.to_le_bytes());
+ }
+
+ // `isize` values often seem to have a small (positive) numeric value in practice.
+ // To exploit this, if the value is small, we will hash a smaller amount of bytes.
+ // However, we cannot just skip the leading zero bytes, as that would produce the same hash
+ // e.g. if you hash two values that have the same bit pattern when they are swapped.
+ // See https://github.com/rust-lang/rust/pull/93014 for context.
+ //
+ // Therefore, we employ the following strategy:
+ // 1) When we encounter a value that fits within a single byte (the most common case), we
+ // hash just that byte. This is the most common case that is being optimized. However, we do
+ // not do this for the value 0xFF, as that is a reserved prefix (a bit like in UTF-8).
+ // 2) When we encounter a larger value, we hash a "marker" 0xFF and then the corresponding
+ // 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two
+ // `isize`s that fit within a different amount of bytes, they should always produce a different
+ // byte stream for the hasher.
+ if value < 0xFF {
+ self.state.write_u8(value as u8);
+ } else {
+ hash_value(&mut self.state, value);
+ }
}
}
@@ -583,3 +611,22 @@
}
}
}
+
+#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
+pub enum NodeIdHashingMode {
+ Ignore,
+ HashDefPath,
+}
+
+/// Controls what data we do or not not hash.
+/// Whenever a `HashStable` implementation caches its
+/// result, it needs to include `HashingControls` as part
+/// of the key, to ensure that is does not produce an incorrect
+/// result (for example, using a `Fingerprint` produced while
+/// hashing `Span`s when a `Fingeprint` without `Span`s is
+/// being requested)
+#[derive(Clone, Hash, Eq, PartialEq, Debug)]
+pub struct HashingControls {
+ pub hash_spans: bool,
+ pub node_id_hashing_mode: NodeIdHashingMode,
+}
diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
index 391db67..b0d66c3 100644
--- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
@@ -39,7 +39,7 @@
test_isize.hash(&mut h);
// This depends on the hashing algorithm. See note at top of file.
- let expected = (2736651863462566372, 8121090595289675650);
+ let expected = (1784307454142909076, 11471672289340283879);
assert_eq!(h.finalize(), expected);
}
@@ -67,7 +67,7 @@
test_isize.hash(&mut h);
// This depends on the hashing algorithm. See note at top of file.
- let expected = (14721296605626097289, 11385941877786388409);
+ let expected = (2789913510339652884, 674280939192711005);
assert_eq!(h.finalize(), expected);
}
@@ -98,3 +98,66 @@
assert_ne!(a, b);
assert_ne!(hash(&a), hash(&b));
}
+
+// Check that exchanging the value of two adjacent fields changes the hash.
+#[test]
+fn test_attribute_permutation() {
+ macro_rules! test_type {
+ ($ty: ty) => {{
+ struct Foo {
+ a: $ty,
+ b: $ty,
+ }
+
+ impl<CTX> HashStable<CTX> for Foo {
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.a.hash_stable(hcx, hasher);
+ self.b.hash_stable(hcx, hasher);
+ }
+ }
+
+ #[allow(overflowing_literals)]
+ let mut item = Foo { a: 0xFF, b: 0xFF_FF };
+ let hash_a = hash(&item);
+ std::mem::swap(&mut item.a, &mut item.b);
+ let hash_b = hash(&item);
+ assert_ne!(
+ hash_a,
+ hash_b,
+ "The hash stayed the same after values were swapped for type `{}`!",
+ stringify!($ty)
+ );
+ }};
+ }
+
+ test_type!(u16);
+ test_type!(u32);
+ test_type!(u64);
+ test_type!(u128);
+
+ test_type!(i16);
+ test_type!(i32);
+ test_type!(i64);
+ test_type!(i128);
+}
+
+// Check that the `isize` hashing optimization does not produce the same hash when permuting two
+// values.
+#[test]
+fn test_isize_compression() {
+ fn check_hash(a: u64, b: u64) {
+ let hash_a = hash(&(a as isize, b as isize));
+ let hash_b = hash(&(b as isize, a as isize));
+ assert_ne!(
+ hash_a, hash_b,
+ "The hash stayed the same when permuting values `{a}` and `{b}!",
+ );
+ }
+
+ check_hash(0xAA, 0xAAAA);
+ check_hash(0xFF, 0xFFFF);
+ check_hash(0xAAAA, 0xAAAAAA);
+ check_hash(0xAAAAAA, 0xAAAAAAAA);
+ check_hash(0xFF, 0xFFFFFFFFFFFFFFFF);
+ check_hash(u64::MAX /* -1 */, 1);
+}
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index ce90fba..12ef286 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -55,8 +55,8 @@
}
impl<D: Decoder> Decodable<D> for Svh {
- fn decode(d: &mut D) -> Result<Svh, D::Error> {
- d.read_u64().map(u64::from_le).map(Svh::new)
+ fn decode(d: &mut D) -> Svh {
+ Svh::new(u64::from_le(d.read_u64()))
}
}
diff --git a/compiler/rustc_data_structures/src/thin_vec/tests.rs b/compiler/rustc_data_structures/src/thin_vec/tests.rs
index 5abfd93..0221b99 100644
--- a/compiler/rustc_data_structures/src/thin_vec/tests.rs
+++ b/compiler/rustc_data_structures/src/thin_vec/tests.rs
@@ -10,8 +10,8 @@
fn test_from_iterator() {
assert_eq!(std::iter::empty().collect::<ThinVec<String>>().into_vec(), Vec::<String>::new());
assert_eq!(std::iter::once(42).collect::<ThinVec<_>>().into_vec(), vec![42]);
- assert_eq!(vec![1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
- assert_eq!(vec![1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
+ assert_eq!([1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
+ assert_eq!([1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
}
#[test]
diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs
index 9083de8..458b600 100644
--- a/compiler/rustc_data_structures/src/vec_map/tests.rs
+++ b/compiler/rustc_data_structures/src/vec_map/tests.rs
@@ -14,7 +14,7 @@
);
assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
assert_eq!(
- vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
+ [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
vec![(1, true), (2, false)]
);
}
@@ -41,7 +41,7 @@
#[test]
fn test_get() {
- let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
+ let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
assert_eq!(v.get(&1), Some(&true));
assert_eq!(v.get(&2), Some(&false));
assert_eq!(v.get(&3), None);
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 694c679..85826cf 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -8,6 +8,7 @@
#![feature(nll)]
#![feature(once_cell)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
@@ -28,7 +29,7 @@
use rustc_metadata::locator;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc_serialize::json::{self, ToJson};
+use rustc_serialize::json::ToJson;
use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS};
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
use rustc_session::cstore::MetadataLoader;
@@ -65,7 +66,7 @@
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
-const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"];
+const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
@@ -215,17 +216,18 @@
}
let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
+ let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
let (odir, ofile) = make_output(&matches);
let mut config = interface::Config {
opts: sopts,
crate_cfg: cfg,
+ crate_check_cfg: check_cfg,
input: Input::File(PathBuf::new()),
input_path: None,
output_file: ofile,
output_dir: odir,
file_loader,
diagnostic_output,
- stderr: None,
lint_caps: Default::default(),
parse_sess_created: None,
register_lints: None,
@@ -262,7 +264,7 @@
describe_lints(compiler.session(), &lint_store, registered_lints);
return;
}
- let should_stop = RustcDefaultCalls::print_crate_info(
+ let should_stop = print_crate_info(
&***compiler.codegen_backend(),
compiler.session(),
None,
@@ -291,7 +293,7 @@
interface::run_compiler(config, |compiler| {
let sess = compiler.session();
- let should_stop = RustcDefaultCalls::print_crate_info(
+ let should_stop = print_crate_info(
&***compiler.codegen_backend(),
sess,
Some(compiler.input()),
@@ -300,13 +302,9 @@
compiler.temps_dir(),
)
.and_then(|| {
- RustcDefaultCalls::list_metadata(
- sess,
- &*compiler.codegen_backend().metadata_loader(),
- compiler.input(),
- )
+ list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input())
})
- .and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler));
+ .and_then(|| try_process_rlink(sess, compiler));
if should_stop == Compilation::Stop {
return sess.compile_status();
@@ -511,10 +509,6 @@
}
}
-/// CompilerCalls instance for a regular rustc build.
-#[derive(Copy, Clone)]
-pub struct RustcDefaultCalls;
-
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
let upper_cased_code = code.to_ascii_uppercase();
let normalised = if upper_cased_code.starts_with('E') {
@@ -587,164 +581,159 @@
}
}
-impl RustcDefaultCalls {
- pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
- if sess.opts.debugging_opts.link_only {
- if let Input::File(file) = compiler.input() {
- // FIXME: #![crate_type] and #![crate_name] support not implemented yet
- sess.init_crate_types(collect_crate_types(sess, &[]));
- let outputs = compiler.build_output_filenames(sess, &[]);
- let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
- sess.fatal(&format!("failed to read rlink file: {}", err));
- });
- let codegen_results: CodegenResults =
- json::decode(&rlink_data).unwrap_or_else(|err| {
- sess.fatal(&format!("failed to decode rlink: {}", err));
- });
- let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
- abort_on_err(result, sess);
- } else {
- sess.fatal("rlink must be a file")
- }
- Compilation::Stop
+pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
+ if sess.opts.debugging_opts.link_only {
+ if let Input::File(file) = compiler.input() {
+ // FIXME: #![crate_type] and #![crate_name] support not implemented yet
+ sess.init_crate_types(collect_crate_types(sess, &[]));
+ let outputs = compiler.build_output_filenames(sess, &[]);
+ let rlink_data = fs::read(file).unwrap_or_else(|err| {
+ sess.fatal(&format!("failed to read rlink file: {}", err));
+ });
+ let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0);
+ let codegen_results: CodegenResults = rustc_serialize::Decodable::decode(&mut decoder);
+ let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
+ abort_on_err(result, sess);
} else {
- Compilation::Continue
- }
- }
-
- pub fn list_metadata(
- sess: &Session,
- metadata_loader: &dyn MetadataLoader,
- input: &Input,
- ) -> Compilation {
- if sess.opts.debugging_opts.ls {
- match *input {
- Input::File(ref ifile) => {
- let path = &(*ifile);
- let mut v = Vec::new();
- locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
- .unwrap();
- println!("{}", String::from_utf8(v).unwrap());
- }
- Input::Str { .. } => {
- early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
- }
- }
- return Compilation::Stop;
- }
-
- Compilation::Continue
- }
-
- fn print_crate_info(
- codegen_backend: &dyn CodegenBackend,
- sess: &Session,
- input: Option<&Input>,
- odir: &Option<PathBuf>,
- ofile: &Option<PathBuf>,
- temps_dir: &Option<PathBuf>,
- ) -> Compilation {
- use rustc_session::config::PrintRequest::*;
- // PrintRequest::NativeStaticLibs is special - printed during linking
- // (empty iterator returns true)
- if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
- return Compilation::Continue;
- }
-
- let attrs = match input {
- None => None,
- Some(input) => {
- let result = parse_crate_attrs(sess, input);
- match result {
- Ok(attrs) => Some(attrs),
- Err(mut parse_error) => {
- parse_error.emit();
- return Compilation::Stop;
- }
- }
- }
- };
- for req in &sess.opts.prints {
- match *req {
- TargetList => {
- let mut targets =
- rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
- targets.sort_unstable();
- println!("{}", targets.join("\n"));
- }
- Sysroot => println!("{}", sess.sysroot.display()),
- TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
- TargetSpec => println!("{}", sess.target.to_json().pretty()),
- FileNames | CrateName => {
- let input = input.unwrap_or_else(|| {
- early_error(ErrorOutputType::default(), "no input file provided")
- });
- let attrs = attrs.as_ref().unwrap();
- let t_outputs = rustc_interface::util::build_output_filenames(
- input, odir, ofile, temps_dir, attrs, sess,
- );
- let id = rustc_session::output::find_crate_name(sess, attrs, input);
- if *req == PrintRequest::CrateName {
- println!("{}", id);
- continue;
- }
- let crate_types = collect_crate_types(sess, attrs);
- for &style in &crate_types {
- let fname =
- rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
- println!("{}", fname.file_name().unwrap().to_string_lossy());
- }
- }
- Cfg => {
- let mut cfgs = sess
- .parse_sess
- .config
- .iter()
- .filter_map(|&(name, value)| {
- // Note that crt-static is a specially recognized cfg
- // directive that's printed out here as part of
- // rust-lang/rust#37406, but in general the
- // `target_feature` cfg is gated under
- // rust-lang/rust#29717. For now this is just
- // specifically allowing the crt-static cfg and that's
- // it, this is intended to get into Cargo and then go
- // through to build scripts.
- if (name != sym::target_feature || value != Some(sym::crt_dash_static))
- && !sess.is_nightly_build()
- && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
- {
- return None;
- }
-
- if let Some(value) = value {
- Some(format!("{}=\"{}\"", name, value))
- } else {
- Some(name.to_string())
- }
- })
- .collect::<Vec<String>>();
-
- cfgs.sort();
- for cfg in cfgs {
- println!("{}", cfg);
- }
- }
- RelocationModels
- | CodeModels
- | TlsModels
- | TargetCPUs
- | StackProtectorStrategies
- | TargetFeatures => {
- codegen_backend.print(*req, sess);
- }
- // Any output here interferes with Cargo's parsing of other printed output
- PrintRequest::NativeStaticLibs => {}
- }
+ sess.fatal("rlink must be a file")
}
Compilation::Stop
+ } else {
+ Compilation::Continue
}
}
+pub fn list_metadata(
+ sess: &Session,
+ metadata_loader: &dyn MetadataLoader,
+ input: &Input,
+) -> Compilation {
+ if sess.opts.debugging_opts.ls {
+ match *input {
+ Input::File(ref ifile) => {
+ let path = &(*ifile);
+ let mut v = Vec::new();
+ locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
+ println!("{}", String::from_utf8(v).unwrap());
+ }
+ Input::Str { .. } => {
+ early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
+ }
+ }
+ return Compilation::Stop;
+ }
+
+ Compilation::Continue
+}
+
+fn print_crate_info(
+ codegen_backend: &dyn CodegenBackend,
+ sess: &Session,
+ input: Option<&Input>,
+ odir: &Option<PathBuf>,
+ ofile: &Option<PathBuf>,
+ temps_dir: &Option<PathBuf>,
+) -> Compilation {
+ use rustc_session::config::PrintRequest::*;
+ // NativeStaticLibs and LinkArgs are special - printed during linking
+ // (empty iterator returns true)
+ if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
+ return Compilation::Continue;
+ }
+
+ let attrs = match input {
+ None => None,
+ Some(input) => {
+ let result = parse_crate_attrs(sess, input);
+ match result {
+ Ok(attrs) => Some(attrs),
+ Err(mut parse_error) => {
+ parse_error.emit();
+ return Compilation::Stop;
+ }
+ }
+ }
+ };
+ for req in &sess.opts.prints {
+ match *req {
+ TargetList => {
+ let mut targets = rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
+ targets.sort_unstable();
+ println!("{}", targets.join("\n"));
+ }
+ Sysroot => println!("{}", sess.sysroot.display()),
+ TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+ TargetSpec => println!("{}", sess.target.to_json().pretty()),
+ FileNames | CrateName => {
+ let input = input.unwrap_or_else(|| {
+ early_error(ErrorOutputType::default(), "no input file provided")
+ });
+ let attrs = attrs.as_ref().unwrap();
+ let t_outputs = rustc_interface::util::build_output_filenames(
+ input, odir, ofile, temps_dir, attrs, sess,
+ );
+ let id = rustc_session::output::find_crate_name(sess, attrs, input);
+ if *req == PrintRequest::CrateName {
+ println!("{}", id);
+ continue;
+ }
+ let crate_types = collect_crate_types(sess, attrs);
+ for &style in &crate_types {
+ let fname =
+ rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
+ println!("{}", fname.file_name().unwrap().to_string_lossy());
+ }
+ }
+ Cfg => {
+ let mut cfgs = sess
+ .parse_sess
+ .config
+ .iter()
+ .filter_map(|&(name, value)| {
+ // Note that crt-static is a specially recognized cfg
+ // directive that's printed out here as part of
+ // rust-lang/rust#37406, but in general the
+ // `target_feature` cfg is gated under
+ // rust-lang/rust#29717. For now this is just
+ // specifically allowing the crt-static cfg and that's
+ // it, this is intended to get into Cargo and then go
+ // through to build scripts.
+ if (name != sym::target_feature || value != Some(sym::crt_dash_static))
+ && !sess.is_nightly_build()
+ && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
+ {
+ return None;
+ }
+
+ if let Some(value) = value {
+ Some(format!("{}=\"{}\"", name, value))
+ } else {
+ Some(name.to_string())
+ }
+ })
+ .collect::<Vec<String>>();
+
+ cfgs.sort();
+ for cfg in cfgs {
+ println!("{}", cfg);
+ }
+ }
+ RelocationModels
+ | CodeModels
+ | TlsModels
+ | TargetCPUs
+ | StackProtectorStrategies
+ | TargetFeatures => {
+ codegen_backend.print(*req, sess);
+ }
+ // Any output here interferes with Cargo's parsing of other printed output
+ NativeStaticLibs => {}
+ LinkArgs => {}
+ }
+ }
+ Compilation::Stop
+}
+
/// Prints version information
pub fn version(binary: &str, matches: &getopts::Matches) {
let verbose = matches.opt_present("verbose");
@@ -847,7 +836,7 @@
let builtin = sort_lints(sess, builtin);
let (plugin_groups, builtin_groups): (Vec<_>, _) =
- lint_store.get_lint_groups().iter().cloned().partition(|&(.., p)| p);
+ lint_store.get_lint_groups().partition(|&(.., p)| p);
let plugin_groups = sort_lint_groups(plugin_groups);
let builtin_groups = sort_lint_groups(builtin_groups);
@@ -1101,31 +1090,31 @@
/// debugging, since some ICEs only happens with non-default compiler flags
/// (and the users don't always report them).
fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
- let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::<Vec<_>>();
+ let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
- // Avoid printing help because of empty args. This can suggest the compiler
- // itself is not the program root (consider RLS).
- if args.len() < 2 {
- return None;
- }
-
- let matches = handle_options(&args)?;
let mut result = Vec::new();
let mut excluded_cargo_defaults = false;
- for flag in ICE_REPORT_COMPILER_FLAGS {
- let prefix = if flag.len() == 1 { "-" } else { "--" };
-
- for content in &matches.opt_strs(flag) {
- // Split always returns the first element
- let name = if let Some(first) = content.split('=').next() { first } else { &content };
-
- let content =
- if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content };
-
- if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
- result.push(format!("{}{} {}", prefix, flag, content));
+ while let Some(arg) = args.next() {
+ if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
+ let content = if arg.len() == a.len() {
+ match args.next() {
+ Some(arg) => arg.to_string(),
+ None => continue,
+ }
+ } else if arg.get(a.len()..a.len() + 1) == Some("=") {
+ arg[a.len() + 1..].to_string()
} else {
+ arg[a.len()..].to_string()
+ };
+ if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) {
excluded_cargo_defaults = true;
+ } else {
+ result.push(a.to_string());
+ match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s))
+ {
+ Some(s) => result.push(s.to_string()),
+ None => result.push(content),
+ }
}
}
}
@@ -1241,6 +1230,15 @@
///
/// A custom rustc driver can skip calling this to set up a custom ICE hook.
pub fn install_ice_hook() {
+ // If the user has not explicitly overriden "RUST_BACKTRACE", then produce
+ // full backtraces. When a compiler ICE happens, we want to gather
+ // as much information as possible to present in the issue opened
+ // by the user. Compiler developers and other rustc users can
+ // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+ // (e.g. `RUST_BACKTRACE=1`)
+ if std::env::var("RUST_BACKTRACE").is_err() {
+ std::env::set_var("RUST_BACKTRACE", "full");
+ }
SyncLazy::force(&DEFAULT_HOOK);
}
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 79d9c55..a72681d 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -97,6 +97,7 @@
E0185: include_str!("./error_codes/E0185.md"),
E0186: include_str!("./error_codes/E0186.md"),
E0191: include_str!("./error_codes/E0191.md"),
+E0192: include_str!("./error_codes/E0192.md"),
E0193: include_str!("./error_codes/E0193.md"),
E0195: include_str!("./error_codes/E0195.md"),
E0197: include_str!("./error_codes/E0197.md"),
@@ -472,6 +473,7 @@
E0769: include_str!("./error_codes/E0769.md"),
E0770: include_str!("./error_codes/E0770.md"),
E0771: include_str!("./error_codes/E0771.md"),
+E0772: include_str!("./error_codes/E0772.md"),
E0773: include_str!("./error_codes/E0773.md"),
E0774: include_str!("./error_codes/E0774.md"),
E0775: include_str!("./error_codes/E0775.md"),
@@ -486,6 +488,7 @@
E0784: include_str!("./error_codes/E0784.md"),
E0785: include_str!("./error_codes/E0785.md"),
E0786: include_str!("./error_codes/E0786.md"),
+E0787: include_str!("./error_codes/E0787.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
@@ -520,7 +523,6 @@
// E0188, // can not cast an immutable reference to a mutable pointer
// E0189, // deprecated: can only cast a boxed pointer to a boxed object
// E0190, // deprecated: can only cast a &-pointer to an &-object
-// E0192, // negative impl only applicable to auto traits
// E0194, // merged into E0403
// E0196, // cannot determine a type for this closure
E0208,
@@ -641,5 +643,4 @@
// 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/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index ca2eaa5..584b785 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -15,7 +15,7 @@
these types can only be accessed through pointers, such as `&dyn Trait` or
`Box<dyn Trait>`. The size of such a pointer is known, but the size of the
`dyn Trait` object pointed-to by the pointer is _opaque_ to code working
- with it, and different tait objects with the same trait object type may
+ with it, and different trait objects with the same trait object type may
have different sizes.
2. The pointer used to access a trait object is paired with an extra pointer
@@ -167,7 +167,7 @@
compiler will only generate code for `foo::<bool>()`. When we have additional
type parameters, the number of monomorphized implementations the compiler
generates does not grow drastically, since the compiler will only generate an
-implementation if the function is called with unparametrized substitutions
+implementation if the function is called with unparameterized substitutions
(i.e., substitutions where none of the substituted types are themselves
parameterized).
diff --git a/compiler/rustc_error_codes/src/error_codes/E0183.md b/compiler/rustc_error_codes/src/error_codes/E0183.md
index 7e1d08d..92fa4c7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0183.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0183.md
@@ -1,4 +1,4 @@
-Manual implemetation of a `Fn*` trait.
+Manual implementation of a `Fn*` trait.
Erroneous code example:
@@ -33,7 +33,7 @@
}
```
-The argumements must be a tuple representing the argument list.
+The arguments must be a tuple representing the argument list.
For more info, see the [tracking issue][iss29625]:
[iss29625]: https://github.com/rust-lang/rust/issues/29625
diff --git a/compiler/rustc_error_codes/src/error_codes/E0192.md b/compiler/rustc_error_codes/src/error_codes/E0192.md
index 5fd951b..deca042 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0192.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0192.md
@@ -1,15 +1,17 @@
+#### Note: this error code is no longer emitted by the compiler.
+
A negative impl was added on a trait implementation.
Erroneous code example:
-```compile_fail,E0192
+```compile_fail
trait Trait {
type Bar;
}
struct Foo;
-impl !Trait for Foo { } //~ ERROR E0192
+impl !Trait for Foo { } //~ ERROR
fn main() {}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0521.md b/compiler/rustc_error_codes/src/error_codes/E0521.md
index 65dcac9..fedf636 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0521.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0521.md
@@ -10,7 +10,7 @@
};
```
-A type anotation of a closure parameter implies a new lifetime declaration.
+A type annotation of a closure parameter implies a new lifetime declaration.
Consider to drop it, the compiler is reliably able to infer them.
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0581.md b/compiler/rustc_error_codes/src/error_codes/E0581.md
index 89f6e32..02468dd 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0581.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0581.md
@@ -10,7 +10,7 @@
}
```
-The problem here is that the lifetime isn't contrained by any of the arguments,
+The problem here is that the lifetime isn't constrained by any of the arguments,
making it impossible to determine how long it's supposed to live.
To fix this issue, either use the lifetime in the arguments, or use the
diff --git a/compiler/rustc_error_codes/src/error_codes/E0604.md b/compiler/rustc_error_codes/src/error_codes/E0604.md
index adbf765..806f000 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0604.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0604.md
@@ -6,11 +6,16 @@
0u32 as char; // error: only `u8` can be cast as `char`, not `u32`
```
-As the error message indicates, only `u8` can be cast into `char`. Example:
+`char` is a Unicode Scalar Value, an integer value from 0 to 0xD7FF and
+0xE000 to 0x10FFFF. (The gap is for surrogate pairs.) Only `u8` always fits in
+those ranges so only `u8` may be cast to `char`.
+
+To allow larger values, use `char::from_u32`, which checks the value is valid.
```
-let c = 86u8 as char; // ok!
-assert_eq!(c, 'V');
+assert_eq!(86u8 as char, 'V'); // ok!
+assert_eq!(char::from_u32(0x3B1), Some('α')); // ok!
+assert_eq!(char::from_u32(0xD800), None); // not a USV.
```
For more information about casts, take a look at the Type cast section in
diff --git a/compiler/rustc_error_codes/src/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md
index 26d35f2..abf9027 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0660.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0660.md
@@ -1,12 +1,9 @@
+#### Note: this error code is no longer emitted by the compiler.
+
The argument to the `llvm_asm` macro is not well-formed.
Erroneous code example:
-```compile_fail,E0660
+```ignore (no longer emitted)
llvm_asm!("nop" "nop");
```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md
index 0b8ba7f..245f755 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0661.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0661.md
@@ -1,13 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
An invalid syntax was passed to the second argument of an `llvm_asm` macro line.
Erroneous code example:
-```compile_fail,E0661
+```ignore (no longer emitted)
let a;
llvm_asm!("nop" : "r"(a));
```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md
index 8c1bab8..ffb716f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0662.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0662.md
@@ -1,16 +1,13 @@
+#### Note: this error code is no longer emitted by the compiler.
+
An invalid input operand constraint was passed to the `llvm_asm` macro
(third line).
Erroneous code example:
-```compile_fail,E0662
+```ignore (no longer emitted)
llvm_asm!("xor %eax, %eax"
:
: "=test"("a")
);
```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md
index 53ffd33..351cfac 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0663.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0663.md
@@ -1,16 +1,13 @@
+#### Note: this error code is no longer emitted by the compiler.
+
An invalid input operand constraint was passed to the `llvm_asm` macro
(third line).
Erroneous code example:
-```compile_fail,E0663
+```ignore (no longer emitted)
llvm_asm!("xor %eax, %eax"
:
: "+test"("a")
);
```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md
index f8e72cd..34135d5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0664.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0664.md
@@ -1,16 +1,13 @@
+#### Note: this error code is no longer emitted by the compiler.
+
A clobber was surrounded by braces in the `llvm_asm` macro.
Erroneous code example:
-```compile_fail,E0664
+```ignore (no longer emitted)
llvm_asm!("mov $$0x200, %eax"
:
:
: "{eax}"
);
```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0668.md b/compiler/rustc_error_codes/src/error_codes/E0668.md
index b6fedfe..393aabe 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0668.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0668.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
Malformed inline assembly rejected by LLVM.
Erroneous code example:
-```compile_fail,E0668
+```ignore (no longer emitted)
#![feature(llvm_asm)]
fn main() {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0669.md b/compiler/rustc_error_codes/src/error_codes/E0669.md
index f078c44..2be8f04 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0669.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0669.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
Cannot convert inline assembly operand to a single LLVM value.
Erroneous code example:
-```compile_fail,E0669
+```ignore (no longer emitted)
#![feature(llvm_asm)]
fn main() {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md
new file mode 100644
index 0000000..262e523
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0772.md
@@ -0,0 +1,89 @@
+A trait object has some specific lifetime `'1`, but it was used in a way that
+requires it to have a `'static` lifetime.
+
+Example of erroneous code:
+
+```compile_fail,E0772
+trait BooleanLike {}
+trait Person {}
+
+impl BooleanLike for bool {}
+
+impl dyn Person {
+ fn is_cool(&self) -> bool {
+ // hey you, you're pretty cool
+ true
+ }
+}
+
+fn get_is_cool<'p>(person: &'p dyn Person) -> impl BooleanLike {
+ // error: `person` has an anonymous lifetime `'p` but calling
+ // `print_cool_fn` introduces an implicit `'static` lifetime
+ // requirement
+ person.is_cool()
+}
+```
+
+The trait object `person` in the function `get_is_cool`, while already being
+behind a reference with lifetime `'p`, also has it's own implicit lifetime,
+`'2`.
+
+Lifetime `'2` represents the data the trait object might hold inside, for
+example:
+
+```
+trait MyTrait {}
+
+struct MyStruct<'a>(&'a i32);
+
+impl<'a> MyTrait for MyStruct<'a> {}
+```
+
+With this scenario, if a trait object of `dyn MyTrait + '2` was made from
+`MyStruct<'a>`, `'a` must live as long, if not longer than `'2`. This allows the
+trait object's internal data to be accessed safely from any trait methods. This
+rule also goes for any lifetime any struct made into a trait object may have.
+
+In the implementation for `dyn Person`, the `'2` lifetime representing the
+internal data was ommitted, meaning that the compiler inferred the lifetime
+`'static`. As a result, the implementation's `is_cool` is inferred by the
+compiler to look like this:
+
+```
+# trait Person {}
+#
+# impl dyn Person {
+fn is_cool<'a>(self: &'a (dyn Person + 'static)) -> bool {unimplemented!()}
+# }
+```
+
+While the `get_is_cool` function is inferred to look like this:
+
+```
+# trait Person {}
+# trait BooleanLike {}
+#
+fn get_is_cool<'p, R: BooleanLike>(person: &'p (dyn Person + 'p)) -> R {
+ unimplemented!()
+}
+```
+
+Which brings us to the core of the problem; the assignment of type
+`&'_ (dyn Person + '_)` to type `&'_ (dyn Person + 'static)` is impossible.
+
+Fixing it is as simple as being generic over lifetime `'2`, as to prevent the
+compiler from inferring it as `'static`:
+
+```
+# trait Person {}
+#
+impl<'d> dyn Person + 'd {/* ... */}
+
+// This works too, and is more elegant:
+//impl dyn Person + '_ {/* ... */}
+```
+
+See the [Rust Reference on Trait Object Lifetime Bounds][trait-objects] for
+more information on trait object lifetimes.
+
+[trait-object-lifetime-bounds]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds
diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md
new file mode 100644
index 0000000..cee5082
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0787.md
@@ -0,0 +1,28 @@
+An unsupported naked function definition.
+
+Erroneous code example:
+
+```compile_fail,E0787
+#![feature(naked_functions)]
+
+#[naked]
+pub extern "C" fn f() -> u32 {
+ 42
+}
+```
+
+The naked functions must be defined using a single inline assembly
+block.
+
+The execution must never fall through past the end of the assembly
+code so the block must use `noreturn` option. The asm block can also
+use `att_syntax` and `raw` options, but others options are not allowed.
+
+The asm block must not contain any operands other than `const` and
+`sym`.
+
+### Additional information
+
+For more information, please see [RFC 2972].
+
+[RFC 2972]: https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index e5116cd..8cfecaf 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -11,6 +11,11 @@
use std::fmt;
use std::hash::{Hash, Hasher};
+/// Error type for `Diagnostic`'s `suggestions` field, indicating that
+/// `.disable_suggestions()` was called on the `Diagnostic`.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+pub struct SuggestionsDisabled;
+
#[must_use]
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct Diagnostic {
@@ -19,7 +24,7 @@
pub code: Option<DiagnosticId>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
- pub suggestions: Vec<CodeSuggestion>,
+ pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
/// This is not used for highlighting or rendering any error message. Rather, it can be used
/// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
@@ -106,7 +111,7 @@
code,
span: MultiSpan::new(),
children: vec![],
- suggestions: vec![],
+ suggestions: Ok(vec![]),
sort_span: DUMMY_SP,
is_lint: false,
}
@@ -300,6 +305,21 @@
self
}
+ /// Disallow attaching suggestions this diagnostic.
+ /// Any suggestions attached e.g. with the `span_suggestion_*` methods
+ /// (before and after the call to `disable_suggestions`) will be ignored.
+ pub fn disable_suggestions(&mut self) -> &mut Self {
+ self.suggestions = Err(SuggestionsDisabled);
+ self
+ }
+
+ /// Helper for pushing to `self.suggestions`, if available (not disable).
+ fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
+ if let Ok(suggestions) = &mut self.suggestions {
+ suggestions.push(suggestion);
+ }
+ }
+
/// Show a suggestion that has multiple parts to it.
/// In other words, multiple changes need to be applied as part of this suggestion.
pub fn multipart_suggestion(
@@ -340,7 +360,7 @@
style: SuggestionStyle,
) -> &mut Self {
assert!(!suggestion.is_empty());
- self.suggestions.push(CodeSuggestion {
+ self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: suggestion
.into_iter()
@@ -368,7 +388,7 @@
applicability: Applicability,
) -> &mut Self {
assert!(!suggestion.is_empty());
- self.suggestions.push(CodeSuggestion {
+ self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: suggestion
.into_iter()
@@ -426,7 +446,7 @@
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
- self.suggestions.push(CodeSuggestion {
+ self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
}],
@@ -471,7 +491,7 @@
.into_iter()
.map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
.collect();
- self.suggestions.push(CodeSuggestion {
+ self.push_suggestion(CodeSuggestion {
substitutions,
msg: msg.to_owned(),
style: SuggestionStyle::ShowCode,
@@ -489,7 +509,7 @@
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
- self.suggestions.push(CodeSuggestion {
+ self.push_suggestion(CodeSuggestion {
substitutions: suggestions
.map(|sugg| Substitution {
parts: sugg
@@ -578,7 +598,7 @@
applicability: Applicability,
tool_metadata: Json,
) {
- self.suggestions.push(CodeSuggestion {
+ self.push_suggestion(CodeSuggestion {
substitutions: vec![],
msg: msg.to_owned(),
style: SuggestionStyle::CompletelyHidden,
@@ -668,7 +688,7 @@
&Vec<(String, Style)>,
&Option<DiagnosticId>,
&MultiSpan,
- &Vec<CodeSuggestion>,
+ &Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
Option<&Vec<SubDiagnostic>>,
) {
(
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 6f84b0d..3c8751a 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -15,19 +15,14 @@
/// extending `HandlerFlags`, accessed via `self.handler.flags`.
#[must_use]
#[derive(Clone)]
-pub struct DiagnosticBuilder<'a>(Box<DiagnosticBuilderInner<'a>>);
-
-/// This is a large type, and often used as a return value, especially within
-/// the frequently-used `PResult` type. In theory, return value optimization
-/// (RVO) should avoid unnecessary copying. In practice, it does not (at the
-/// time of writing). The split between `DiagnosticBuilder` and
-/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls.
-#[must_use]
-#[derive(Clone)]
-struct DiagnosticBuilderInner<'a> {
+pub struct DiagnosticBuilder<'a> {
handler: &'a Handler,
- diagnostic: Diagnostic,
- allow_suggestions: bool,
+
+ /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a
+ /// return value, especially within the frequently-used `PResult` type.
+ /// In theory, return value optimization (RVO) should avoid unnecessary
+ /// copying. In practice, it does not (at the time of writing).
+ diagnostic: Box<Diagnostic>,
}
/// In general, the `DiagnosticBuilder` uses deref to allow access to
@@ -60,7 +55,7 @@
$(#[$attrs])*
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
- self.0.diagnostic.$n($($name),*);
+ self.diagnostic.$n($($name),*);
self
}
};
@@ -77,7 +72,7 @@
$(#[$attrs])*
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self {
- self.0.diagnostic.$n($($name),*);
+ self.diagnostic.$n($($name),*);
self
}
};
@@ -87,20 +82,20 @@
type Target = Diagnostic;
fn deref(&self) -> &Diagnostic {
- &self.0.diagnostic
+ &self.diagnostic
}
}
impl<'a> DerefMut for DiagnosticBuilder<'a> {
fn deref_mut(&mut self) -> &mut Diagnostic {
- &mut self.0.diagnostic
+ &mut self.diagnostic
}
}
impl<'a> DiagnosticBuilder<'a> {
/// Emit the diagnostic.
pub fn emit(&mut self) {
- self.0.handler.emit_diagnostic(&self);
+ self.handler.emit_diagnostic(&self);
self.cancel();
}
@@ -130,19 +125,19 @@
/// Converts the builder to a `Diagnostic` for later emission,
/// unless handler has disabled such buffering.
pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
- if self.0.handler.flags.dont_buffer_diagnostics
- || self.0.handler.flags.treat_err_as_bug.is_some()
+ if self.handler.flags.dont_buffer_diagnostics
+ || self.handler.flags.treat_err_as_bug.is_some()
{
self.emit();
return None;
}
- let handler = self.0.handler;
+ let handler = self.handler;
// We must use `Level::Cancelled` for `dummy` to avoid an ICE about an
// unused diagnostic.
let dummy = Diagnostic::new(Level::Cancelled, "");
- let diagnostic = std::mem::replace(&mut self.0.diagnostic, dummy);
+ let diagnostic = std::mem::replace(&mut *self.diagnostic, dummy);
// Logging here is useful to help track down where in logs an error was
// actually emitted.
@@ -169,7 +164,7 @@
/// locally in whichever way makes the most sense.
pub fn delay_as_bug(&mut self) {
self.level = Level::Bug;
- self.0.handler.delay_as_bug(self.0.diagnostic.clone());
+ self.handler.delay_as_bug((*self.diagnostic).clone());
self.cancel();
}
@@ -186,7 +181,7 @@
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self {
- self.0.diagnostic.span_label(span, label);
+ self.diagnostic.span_label(span, label);
self
}
@@ -199,7 +194,7 @@
) -> &mut Self {
let label = label.as_ref();
for span in spans {
- self.0.diagnostic.span_label(span, label);
+ self.diagnostic.span_label(span, label);
}
self
}
@@ -244,164 +239,79 @@
) -> &mut Self);
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
- /// See [`Diagnostic::multipart_suggestion()`].
- pub fn multipart_suggestion(
+ forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
+
+ forward!(pub fn multipart_suggestion(
&mut self,
msg: &str,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.multipart_suggestion(msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::multipart_suggestion()`].
- pub fn multipart_suggestion_verbose(
+ ) -> &mut Self);
+ forward!(pub fn multipart_suggestion_verbose(
&mut self,
msg: &str,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.multipart_suggestion_verbose(msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::tool_only_multipart_suggestion()`].
- pub fn tool_only_multipart_suggestion(
+ ) -> &mut Self);
+ forward!(pub fn tool_only_multipart_suggestion(
&mut self,
msg: &str,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.tool_only_multipart_suggestion(msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::span_suggestion()`].
- pub fn span_suggestion(
+ ) -> &mut Self);
+ forward!(pub fn span_suggestion(
&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.span_suggestion(sp, msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::span_suggestions()`].
- pub fn span_suggestions(
+ ) -> &mut Self);
+ forward!(pub fn span_suggestions(
&mut self,
sp: Span,
msg: &str,
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.span_suggestions(sp, msg, suggestions, applicability);
- self
- }
-
- /// See [`Diagnostic::multipart_suggestions()`].
- pub fn multipart_suggestions(
+ ) -> &mut Self);
+ forward!(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);
+ forward!(pub fn span_suggestion_short(
&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.span_suggestion_short(sp, msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::span_suggestion_verbose()`].
- pub fn span_suggestion_verbose(
+ ) -> &mut Self);
+ forward!(pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.span_suggestion_verbose(sp, msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::span_suggestion_hidden()`].
- pub fn span_suggestion_hidden(
+ ) -> &mut Self);
+ forward!(pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.span_suggestion_hidden(sp, msg, suggestion, applicability);
- self
- }
-
- /// See [`Diagnostic::tool_only_span_suggestion()`] for more information.
- pub fn tool_only_span_suggestion(
+ ) -> &mut Self);
+ forward!(pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability,
- ) -> &mut Self {
- if !self.0.allow_suggestions {
- return self;
- }
- self.0.diagnostic.tool_only_span_suggestion(sp, msg, suggestion, applicability);
- self
- }
+ ) -> &mut Self);
forward!(pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
- /// Allow attaching suggestions this diagnostic.
- /// If this is set to `false`, then any suggestions attached with the `span_suggestion_*`
- /// methods after this is set to `false` will be ignored.
- pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
- self.0.allow_suggestions = allow;
- self
- }
-
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
@@ -424,17 +334,13 @@
/// diagnostic.
crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
debug!("Created new diagnostic");
- DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
- handler,
- diagnostic,
- allow_suggestions: true,
- }))
+ DiagnosticBuilder { handler, diagnostic: Box::new(diagnostic) }
}
}
impl<'a> Debug for DiagnosticBuilder<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.diagnostic.fmt(f)
+ self.diagnostic.fmt(f)
}
}
@@ -444,7 +350,7 @@
fn drop(&mut self) {
if !panicking() && !self.cancelled() {
let mut db = DiagnosticBuilder::new(
- self.0.handler,
+ self.handler,
Level::Bug,
"the following error was constructed but not emitted",
);
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 3104bc1..f90f4d4 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -227,7 +227,8 @@
diag: &'a Diagnostic,
) -> (MultiSpan, &'a [CodeSuggestion]) {
let mut primary_span = diag.span.clone();
- if let Some((sugg, rest)) = diag.suggestions.split_first() {
+ let suggestions = diag.suggestions.as_ref().map_or(&[][..], |suggestions| &suggestions[..]);
+ if let Some((sugg, rest)) = suggestions.split_first() {
if rest.is_empty() &&
// ^ if there is only one suggestion
// don't display multi-suggestions as labels
@@ -282,10 +283,10 @@
// to be consistent. We could try to figure out if we can
// make one (or the first one) inline, but that would give
// undue importance to a semi-random suggestion
- (primary_span, &diag.suggestions)
+ (primary_span, suggestions)
}
} else {
- (primary_span, &diag.suggestions)
+ (primary_span, suggestions)
}
}
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index dde978c..ff34780 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -345,7 +345,7 @@
impl Diagnostic {
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
- let sugg = diag.suggestions.iter().map(|sugg| Diagnostic {
+ let sugg = diag.suggestions.iter().flatten().map(|sugg| Diagnostic {
message: sugg.msg.clone(),
code: None,
level: "help",
@@ -455,7 +455,7 @@
let backtrace_step = backtrace.next().map(|bt| {
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
let def_site_span =
- Self::from_span_full(bt.def_site, false, None, None, vec![].into_iter(), je);
+ Self::from_span_full(bt.def_site, false, None, None, [].into_iter(), je);
Box::new(DiagnosticSpanMacroExpansion {
span: call_site,
macro_decl_name: bt.kind.descr(),
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index d055937..c5b3d20 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -64,7 +64,7 @@
let bytes = output.lock().unwrap();
let actual_output = str::from_utf8(&bytes).unwrap();
- let actual_output: TestData = decode(actual_output).unwrap();
+ let actual_output: TestData = decode(actual_output);
assert_eq!(expected_output, actual_output)
})
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index a681298..a5c954c 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -8,6 +8,7 @@
#![feature(if_let_guard)]
#![feature(let_else)]
#![feature(nll)]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
@@ -54,9 +55,11 @@
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
-// (See also the comment on `DiagnosticBuilderInner`.)
+// (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.)
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
+rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
pub enum SuggestionStyle {
@@ -99,8 +102,8 @@
// Doesn't really need to round-trip
impl<D: Decoder> Decodable<D> for ToolMetadata {
- fn decode(_d: &mut D) -> Result<Self, D::Error> {
- Ok(ToolMetadata(None))
+ fn decode(_d: &mut D) -> Self {
+ ToolMetadata(None)
}
}
@@ -445,9 +448,6 @@
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.
@@ -563,19 +563,10 @@
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 {
@@ -946,7 +937,7 @@
}
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
- if diagnostic.cancelled() || self.quiet {
+ if diagnostic.cancelled() {
return;
}
@@ -1170,9 +1161,6 @@
}
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 6435346..e4cc44c 100644
--- a/compiler/rustc_errors/src/snippet.rs
+++ b/compiler/rustc_errors/src/snippet.rs
@@ -69,9 +69,6 @@
/// Annotation under a single line of code
Singleline,
- /// Annotation enclosing the first and last character of a multiline span
- Multiline(MultilineAnnotation),
-
// The Multiline type above is replaced with the following three in order
// to reuse the current label drawing code.
//
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 07b5e20..258320a 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -8,7 +8,7 @@
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
@@ -920,8 +920,25 @@
/// 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);
+
+ /// Tools registered with `#![register_tool]` and used by tool attributes and lints.
+ fn registered_tools(&self) -> &FxHashSet<Ident>;
}
+pub trait LintStoreExpand {
+ fn pre_expansion_lint(
+ &self,
+ sess: &Session,
+ registered_tools: &FxHashSet<Ident>,
+ node_id: NodeId,
+ attrs: &[Attribute],
+ items: &[P<Item>],
+ name: &str,
+ );
+}
+
+type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
+
#[derive(Clone, Default)]
pub struct ModuleData {
/// Path to the module starting from the crate name, like `my_crate::foo::bar`.
@@ -956,9 +973,6 @@
pub is_trailing_mac: bool,
}
-type OnExternModLoaded<'a> =
- Option<&'a dyn Fn(Ident, Vec<Attribute>, Vec<P<Item>>, Span) -> (Vec<Attribute>, Vec<P<Item>>)>;
-
/// One of these is made during expansion and incrementally updated as we go;
/// when a macro expansion occurs, the resulting nodes have the `backtrace()
/// -> expn_data` of their expansion context stored into their span.
@@ -973,10 +987,8 @@
/// (or during eager expansion, but that's a hack).
pub force_mode: bool,
pub expansions: FxHashMap<Span, Vec<String>>,
- /// Called directly after having parsed an external `mod foo;` in expansion.
- ///
- /// `Ident` is the module name.
- pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
+ /// Used for running pre-expansion lints on freshly loaded modules.
+ pub(super) lint_store: LintStoreExpandDyn<'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.
@@ -988,14 +1000,14 @@
sess: &'a Session,
ecfg: expand::ExpansionConfig<'a>,
resolver: &'a mut dyn ResolverExpand,
- extern_mod_loaded: OnExternModLoaded<'a>,
+ lint_store: LintStoreExpandDyn<'a>,
) -> ExtCtxt<'a> {
ExtCtxt {
sess,
ecfg,
reduced_recursion_limit: None,
resolver,
- extern_mod_loaded,
+ lint_store,
root_path: PathBuf::new(),
current_expansion: ExpansionData {
id: LocalExpnId::ROOT,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index db0dea4..5fa7ffd 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -238,7 +238,7 @@
}
impl<'a> StripUnconfigured<'a> {
- pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
+ pub fn configure<T: AstLike>(&self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
if self.in_cfg(node.attrs()) {
self.try_configure_tokens(&mut node);
@@ -248,7 +248,7 @@
}
}
- fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) {
+ fn try_configure_tokens<T: AstLike>(&self, node: &mut T) {
if self.config_tokens {
if let Some(Some(tokens)) = node.tokens_mut() {
let attr_annotated_tokens = tokens.create_token_stream();
@@ -257,10 +257,7 @@
}
}
- fn configure_krate_attrs(
- &mut self,
- mut attrs: Vec<ast::Attribute>,
- ) -> Option<Vec<ast::Attribute>> {
+ fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
if self.in_cfg(&attrs) { Some(attrs) } else { None }
}
@@ -269,7 +266,7 @@
/// This is only used during the invocation of `derive` proc-macros,
/// which require that we cfg-expand their entire input.
/// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
- fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
+ fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
stream.0.iter().all(|(tree, _spacing)| match tree {
AttrAnnotatedTokenTree::Attributes(_) => false,
@@ -325,12 +322,16 @@
/// Gives compiler warnings if any `cfg_attr` does not contain any
/// attributes and is in the original source code. Gives compiler errors if
/// the syntax of any `cfg_attr` is incorrect.
- fn process_cfg_attrs<T: AstLike>(&mut self, node: &mut T) {
+ fn process_cfg_attrs<T: AstLike>(&self, node: &mut T) {
node.visit_attrs(|attrs| {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
});
}
+ fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
+ if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] }
+ }
+
/// Parse and expand a single `cfg_attr` attribute into a list of attributes
/// when the configuration predicate is true, or otherwise expand into an
/// empty list of attributes.
@@ -338,11 +339,7 @@
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
- fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
- if !attr.has_name(sym::cfg_attr) {
- return vec![attr];
- }
-
+ crate fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
let (cfg_predicate, expanded_attrs) =
match rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) {
None => return vec![],
@@ -351,95 +348,109 @@
// Lint on zero attributes in source.
if expanded_attrs.is_empty() {
- return vec![attr];
+ self.sess.parse_sess.buffer_lint(
+ rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
+ attr.span,
+ ast::CRATE_NODE_ID,
+ "`#[cfg_attr]` does not expand to any attributes",
+ );
}
if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
return vec![];
}
- // We call `process_cfg_attr` recursively in case there's a
- // `cfg_attr` inside of another `cfg_attr`. E.g.
- // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
- expanded_attrs
- .into_iter()
- .flat_map(|(item, span)| {
- let orig_tokens = attr.tokens().to_tokenstream();
+ if recursive {
+ // We call `process_cfg_attr` recursively in case there's a
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+ expanded_attrs
+ .into_iter()
+ .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item)))
+ .collect()
+ } else {
+ expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect()
+ }
+ }
- // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
- // and producing an attribute of the form `#[attr]`. We
- // have captured tokens for `attr` itself, but we need to
- // synthesize tokens for the wrapper `#` and `[]`, which
- // we do below.
+ fn expand_cfg_attr_item(
+ &self,
+ attr: &Attribute,
+ (item, item_span): (ast::AttrItem, Span),
+ ) -> Attribute {
+ let orig_tokens = attr.tokens().to_tokenstream();
- // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
- // for `attr` when we expand it to `#[attr]`
- let mut orig_trees = orig_tokens.trees();
- let pound_token = match orig_trees.next().unwrap() {
- TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token,
- _ => panic!("Bad tokens for attribute {:?}", attr),
- };
- let pound_span = pound_token.span;
+ // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
+ // and producing an attribute of the form `#[attr]`. We
+ // have captured tokens for `attr` itself, but we need to
+ // synthesize tokens for the wrapper `#` and `[]`, which
+ // we do below.
- let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)];
- if attr.style == AttrStyle::Inner {
- // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
- let bang_token = match orig_trees.next().unwrap() {
- TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token,
- _ => panic!("Bad tokens for attribute {:?}", attr),
- };
- trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
- }
- // We don't really have a good span to use for the syntheized `[]`
- // in `#[attr]`, so just use the span of the `#` token.
- let bracket_group = AttrAnnotatedTokenTree::Delimited(
- DelimSpan::from_single(pound_span),
- DelimToken::Bracket,
- item.tokens
- .as_ref()
- .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
- .create_token_stream(),
- );
- trees.push((bracket_group, Spacing::Alone));
- let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
- let attr = attr::mk_attr_from_item(item, tokens, attr.style, span);
- if attr.has_name(sym::crate_type) {
- self.sess.parse_sess.buffer_lint(
- rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
- attr.span,
- ast::CRATE_NODE_ID,
- "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
- );
- }
- if attr.has_name(sym::crate_name) {
- self.sess.parse_sess.buffer_lint(
- rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
- attr.span,
- ast::CRATE_NODE_ID,
- "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
- );
- }
- self.process_cfg_attr(attr)
- })
- .collect()
+ // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
+ // for `attr` when we expand it to `#[attr]`
+ let mut orig_trees = orig_tokens.trees();
+ let pound_token = match orig_trees.next().unwrap() {
+ TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token,
+ _ => panic!("Bad tokens for attribute {:?}", attr),
+ };
+ let pound_span = pound_token.span;
+
+ let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)];
+ if attr.style == AttrStyle::Inner {
+ // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
+ let bang_token = match orig_trees.next().unwrap() {
+ TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token,
+ _ => panic!("Bad tokens for attribute {:?}", attr),
+ };
+ trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
+ }
+ // We don't really have a good span to use for the syntheized `[]`
+ // in `#[attr]`, so just use the span of the `#` token.
+ let bracket_group = AttrAnnotatedTokenTree::Delimited(
+ DelimSpan::from_single(pound_span),
+ DelimToken::Bracket,
+ item.tokens
+ .as_ref()
+ .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
+ .create_token_stream(),
+ );
+ trees.push((bracket_group, Spacing::Alone));
+ let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
+ let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span);
+ if attr.has_name(sym::crate_type) {
+ self.sess.parse_sess.buffer_lint(
+ rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ attr.span,
+ ast::CRATE_NODE_ID,
+ "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
+ );
+ }
+ if attr.has_name(sym::crate_name) {
+ self.sess.parse_sess.buffer_lint(
+ rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ attr.span,
+ ast::CRATE_NODE_ID,
+ "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
+ );
+ }
+ attr
}
/// 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(attr) {
+ attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr))
+ }
+
+ crate fn cfg_true(&self, attr: &Attribute) -> bool {
+ let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
+ Ok(meta_item) => meta_item,
+ Err(mut err) => {
+ err.emit();
return true;
}
- let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
- Ok(meta_item) => meta_item,
- Err(mut err) => {
- err.emit();
- return true;
- }
- };
- parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
- attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
- })
+ };
+ parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
+ attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
})
}
@@ -461,7 +472,7 @@
}
}
- pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
+ pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
for attr in expr.attrs.iter() {
self.maybe_emit_expr_attr_err(attr);
}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 7f49f80..9a4daa6 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,6 +1,5 @@
use crate::base::*;
use crate::config::StripUnconfigured;
-use crate::configure;
use crate::hygiene::SyntaxContext;
use crate::mbe::macro_rules::annotate_err_with_kind;
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@@ -12,13 +11,11 @@
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
-use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
-use rustc_ast::{NodeId, PatKind, Path, StmtKind};
+use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind};
+use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
+use rustc_ast::{NodeId, PatKind, StmtKind, TyKind};
use rustc_ast_pretty::pprust;
-use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
-use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, PResult};
use rustc_feature::Features;
@@ -34,7 +31,7 @@
use rustc_span::{FileName, LocalExpnId, Span};
use smallvec::SmallVec;
-use std::ops::DerefMut;
+use std::ops::Deref;
use std::path::PathBuf;
use std::rc::Rc;
use std::{iter, mem};
@@ -109,6 +106,10 @@
}
})*
+ fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
+ T::fragment_to_output(self)
+ }
+
pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
match self {
AstFragment::OptExpr(opt_expr) => {
@@ -178,10 +179,10 @@
Arms(SmallVec<[ast::Arm; 1]>) {
"match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
}
- Fields(SmallVec<[ast::ExprField; 1]>) {
+ ExprFields(SmallVec<[ast::ExprField; 1]>) {
"field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
}
- FieldPats(SmallVec<[ast::PatField; 1]>) {
+ PatFields(SmallVec<[ast::PatField; 1]>) {
"field pattern";
many fn flat_map_pat_field;
fn visit_pat_field();
@@ -196,7 +197,7 @@
Params(SmallVec<[ast::Param; 1]>) {
"function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
}
- StructFields(SmallVec<[ast::FieldDef; 1]>) {
+ FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
"field";
many fn flat_map_field_def;
fn visit_field_def();
@@ -231,11 +232,11 @@
| AstFragmentKind::ForeignItems
| AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
AstFragmentKind::Arms
- | AstFragmentKind::Fields
- | AstFragmentKind::FieldPats
+ | AstFragmentKind::ExprFields
+ | AstFragmentKind::PatFields
| AstFragmentKind::GenericParams
| AstFragmentKind::Params
- | AstFragmentKind::StructFields
+ | AstFragmentKind::FieldDefs
| AstFragmentKind::Variants => SupportsMacroExpansion::No,
}
}
@@ -249,11 +250,11 @@
AstFragmentKind::Arms => {
AstFragment::Arms(items.map(Annotatable::expect_arm).collect())
}
- AstFragmentKind::Fields => {
- AstFragment::Fields(items.map(Annotatable::expect_expr_field).collect())
+ AstFragmentKind::ExprFields => {
+ AstFragment::ExprFields(items.map(Annotatable::expect_expr_field).collect())
}
- AstFragmentKind::FieldPats => {
- AstFragment::FieldPats(items.map(Annotatable::expect_pat_field).collect())
+ AstFragmentKind::PatFields => {
+ AstFragment::PatFields(items.map(Annotatable::expect_pat_field).collect())
}
AstFragmentKind::GenericParams => {
AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect())
@@ -261,8 +262,8 @@
AstFragmentKind::Params => {
AstFragment::Params(items.map(Annotatable::expect_param).collect())
}
- AstFragmentKind::StructFields => {
- AstFragment::StructFields(items.map(Annotatable::expect_field_def).collect())
+ AstFragmentKind::FieldDefs => {
+ AstFragment::FieldDefs(items.map(Annotatable::expect_field_def).collect())
}
AstFragmentKind::Variants => {
AstFragment::Variants(items.map(Annotatable::expect_variant).collect())
@@ -315,10 +316,10 @@
pos: usize,
item: Annotatable,
// Required for resolving derive helper attributes.
- derives: Vec<Path>,
+ derives: Vec<ast::Path>,
},
Derive {
- path: Path,
+ path: ast::Path,
item: Annotatable,
},
}
@@ -676,7 +677,7 @@
krate,
),
Annotatable::Item(item_inner)
- if matches!(attr.style, ast::AttrStyle::Inner)
+ if matches!(attr.style, AttrStyle::Inner)
&& matches!(
item_inner.kind,
ItemKind::Mod(
@@ -744,7 +745,7 @@
if let SyntaxExtensionKind::Derive(..) = ext {
self.gate_proc_macro_input(&item);
}
- let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
+ let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
ExpandResult::Retry(item) => {
@@ -806,7 +807,7 @@
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind {
- ast::ItemKind::Mod(_, mod_kind)
+ ItemKind::Mod(_, mod_kind)
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
{
feature_err(
@@ -834,7 +835,7 @@
&mut self,
toks: TokenStream,
kind: AstFragmentKind,
- path: &Path,
+ path: &ast::Path,
span: Span,
) -> AstFragment {
let mut parser = self.cx.new_parser_from_tts(toks);
@@ -915,18 +916,18 @@
)?),
AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
AstFragmentKind::Arms
- | AstFragmentKind::Fields
- | AstFragmentKind::FieldPats
+ | AstFragmentKind::ExprFields
+ | AstFragmentKind::PatFields
| AstFragmentKind::GenericParams
| AstFragmentKind::Params
- | AstFragmentKind::StructFields
+ | AstFragmentKind::FieldDefs
| AstFragmentKind::Variants => panic!("unexpected AST fragment kind"),
})
}
pub fn ensure_complete_parse<'a>(
this: &mut Parser<'a>,
- macro_path: &Path,
+ macro_path: &ast::Path,
kind_name: &str,
span: Span,
) {
@@ -961,6 +962,581 @@
}
}
+/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
+/// for an AST node that supports attributes
+/// (see the `Annotatable` enum)
+/// This method assigns a `NodeId`, and sets that `NodeId`
+/// as our current 'lint node id'. If a macro call is found
+/// inside this AST node, we will use this AST node's `NodeId`
+/// to emit lints associated with that macro (allowing
+/// `#[allow]` / `#[deny]` to be applied close to
+/// the macro invocation).
+///
+/// Do *not* call this for a macro AST node
+/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
+/// at these AST nodes, since they are removed and
+/// replaced with the result of macro expansion.
+///
+/// All other `NodeId`s are assigned by `visit_id`.
+/// * `self` is the 'self' parameter for the current method,
+/// * `id` is a mutable reference to the `NodeId` field
+/// of the current AST node.
+/// * `closure` is a closure that executes the
+/// `noop_visit_*` / `noop_flat_map_*` method
+/// for the current AST node.
+macro_rules! assign_id {
+ ($self:ident, $id:expr, $closure:expr) => {{
+ let old_id = $self.cx.current_expansion.lint_node_id;
+ if $self.monotonic {
+ debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
+ let new_id = $self.cx.resolver.next_node_id();
+ *$id = new_id;
+ $self.cx.current_expansion.lint_node_id = new_id;
+ }
+ let ret = ($closure)();
+ $self.cx.current_expansion.lint_node_id = old_id;
+ ret
+ }};
+}
+
+enum AddSemicolon {
+ Yes,
+ No,
+}
+
+/// A trait implemented for all `AstFragment` nodes and providing all pieces
+/// of functionality used by `InvocationCollector`.
+trait InvocationCollectorNode: AstLike {
+ type OutputTy = SmallVec<[Self; 1]>;
+ type AttrsTy: Deref<Target = [ast::Attribute]> = Vec<ast::Attribute>;
+ const KIND: AstFragmentKind;
+ fn to_annotatable(self) -> Annotatable;
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
+ fn id(&mut self) -> &mut NodeId;
+ fn descr() -> &'static str {
+ unreachable!()
+ }
+ fn noop_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
+ unreachable!()
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, _visitor: &mut V) {
+ unreachable!()
+ }
+ fn is_mac_call(&self) -> bool {
+ false
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ unreachable!()
+ }
+ fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
+ fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
+ }
+ fn wrap_flat_map_node_noop_flat_map(
+ node: Self,
+ collector: &mut InvocationCollector<'_, '_>,
+ noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+ ) -> Result<Self::OutputTy, Self> {
+ Ok(noop_flat_map(node, collector))
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Item> {
+ const KIND: AstFragmentKind = AstFragmentKind::Items;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Item(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_item(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+ fn wrap_flat_map_node_noop_flat_map(
+ mut node: Self,
+ collector: &mut InvocationCollector<'_, '_>,
+ noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+ ) -> Result<Self::OutputTy, Self> {
+ if !matches!(node.kind, ItemKind::Mod(..)) {
+ return Ok(noop_flat_map(node, collector));
+ }
+
+ // Work around borrow checker not seeing through `P`'s deref.
+ let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs));
+ let ItemKind::Mod(_, mod_kind) = &mut node.kind else {
+ unreachable!()
+ };
+
+ let ecx = &mut collector.cx;
+ let (file_path, dir_path, dir_ownership) = match mod_kind {
+ ModKind::Loaded(_, inline, _) => {
+ // Inline `mod foo { ... }`, but we still need to push directories.
+ let (dir_path, dir_ownership) = mod_dir_path(
+ &ecx.sess,
+ ident,
+ &attrs,
+ &ecx.current_expansion.module,
+ ecx.current_expansion.dir_ownership,
+ *inline,
+ );
+ node.attrs = attrs;
+ (None, dir_path, dir_ownership)
+ }
+ ModKind::Unloaded => {
+ // We have an outline `mod foo;` so we need to parse the file.
+ let old_attrs_len = attrs.len();
+ let ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership } =
+ parse_external_mod(
+ &ecx.sess,
+ ident,
+ span,
+ &ecx.current_expansion.module,
+ ecx.current_expansion.dir_ownership,
+ &mut attrs,
+ );
+
+ if let Some(lint_store) = ecx.lint_store {
+ lint_store.pre_expansion_lint(
+ ecx.sess,
+ ecx.resolver.registered_tools(),
+ ecx.current_expansion.lint_node_id,
+ &attrs,
+ &items,
+ ident.name.as_str(),
+ );
+ }
+
+ *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
+ node.attrs = attrs;
+ if node.attrs.len() > old_attrs_len {
+ // If we loaded an out-of-line module and added some inner attributes,
+ // then we need to re-configure it and re-collect attributes for
+ // resolution and expansion.
+ return Err(node);
+ }
+ (Some(file_path), dir_path, dir_ownership)
+ }
+ };
+
+ // Set the module info before we flat map.
+ let mut module = ecx.current_expansion.module.with_dir_path(dir_path);
+ module.mod_path.push(ident);
+ if let Some(file_path) = file_path {
+ module.file_path_stack.push(file_path);
+ }
+
+ let orig_module = mem::replace(&mut ecx.current_expansion.module, Rc::new(module));
+ let orig_dir_ownership =
+ mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);
+
+ let res = Ok(noop_flat_map(node, collector));
+
+ collector.cx.current_expansion.dir_ownership = orig_dir_ownership;
+ collector.cx.current_expansion.module = orig_module;
+ res
+ }
+}
+
+struct TraitItemTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, TraitItemTag> {
+ type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+ const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::TraitItem(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_trait_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.wrapped.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_assoc_item(self.wrapped, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let item = self.wrapped.into_inner();
+ match item.kind {
+ AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+struct ImplItemTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, ImplItemTag> {
+ type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+ const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::ImplItem(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_impl_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.wrapped.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_assoc_item(self.wrapped, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let item = self.wrapped.into_inner();
+ match item.kind {
+ AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for P<ast::ForeignItem> {
+ const KIND: AstFragmentKind = AstFragmentKind::ForeignItems;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::ForeignItem(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_foreign_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_foreign_item(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ForeignItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for ast::Variant {
+ const KIND: AstFragmentKind = AstFragmentKind::Variants;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Variant(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_variants()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_variant(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::FieldDef {
+ const KIND: AstFragmentKind = AstFragmentKind::FieldDefs;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::FieldDef(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_field_defs()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_field_def(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::PatField {
+ const KIND: AstFragmentKind = AstFragmentKind::PatFields;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::PatField(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_pat_fields()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_pat_field(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::ExprField {
+ const KIND: AstFragmentKind = AstFragmentKind::ExprFields;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::ExprField(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_expr_fields()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_expr_field(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::Param {
+ const KIND: AstFragmentKind = AstFragmentKind::Params;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Param(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_params()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_param(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::GenericParam {
+ const KIND: AstFragmentKind = AstFragmentKind::GenericParams;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::GenericParam(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_generic_params()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_generic_param(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::Arm {
+ const KIND: AstFragmentKind = AstFragmentKind::Arms;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Arm(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_arms()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_arm(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::Stmt {
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::Stmts;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Stmt(P(self))
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_stmts()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_stmt(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ match &self.kind {
+ StmtKind::MacCall(..) => true,
+ StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),
+ StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),
+ StmtKind::Expr(..) => unreachable!(),
+ StmtKind::Local(..) | StmtKind::Empty => false,
+ }
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ // 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.
+ let (add_semicolon, mac, attrs) = match self.kind {
+ StmtKind::MacCall(mac) => {
+ let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
+ (style == MacStmtStyle::Semicolon, mac, attrs)
+ }
+ StmtKind::Item(item) => match item.into_inner() {
+ ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
+ (mac.args.need_semicolon(), mac, attrs.into())
+ }
+ _ => unreachable!(),
+ },
+ StmtKind::Semi(expr) => match expr.into_inner() {
+ ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => {
+ (mac.args.need_semicolon(), mac, attrs)
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ };
+ (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
+ }
+ fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
+ // If this is a macro invocation with a semicolon, then apply that
+ // semicolon to the final statement produced by expansion.
+ if matches!(add_semicolon, AddSemicolon::Yes) {
+ if let Some(stmt) = stmts.pop() {
+ stmts.push(stmt.add_trailing_semicolon());
+ }
+ }
+ }
+}
+
+impl InvocationCollectorNode for ast::Crate {
+ type OutputTy = ast::Crate;
+ const KIND: AstFragmentKind = AstFragmentKind::Crate;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Crate(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_crate()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_crate(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Ty> {
+ type OutputTy = P<ast::Ty>;
+ const KIND: AstFragmentKind = AstFragmentKind::Ty;
+ fn to_annotatable(self) -> Annotatable {
+ unreachable!()
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_ty()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_ty(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ast::TyKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Pat> {
+ type OutputTy = P<ast::Pat>;
+ const KIND: AstFragmentKind = AstFragmentKind::Pat;
+ fn to_annotatable(self) -> Annotatable {
+ unreachable!()
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_pat()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_pat(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, PatKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Expr> {
+ type OutputTy = P<ast::Expr>;
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::Expr;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Expr(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_expr()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn descr() -> &'static str {
+ "an expression"
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_expr(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ExprKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+struct OptExprTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::Expr>, OptExprTag> {
+ type OutputTy = Option<P<ast::Expr>>;
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::OptExpr;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Expr(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_opt_expr()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.wrapped.id
+ }
+ fn noop_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
+ noop_visit_expr(&mut self.wrapped, visitor);
+ Some(self.wrapped)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.wrapped.into_inner();
+ match node.kind {
+ ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+ fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) {
+ cfg.maybe_emit_expr_attr_err(&attr);
+ }
+}
+
struct InvocationCollector<'a, 'b> {
cx: &'a mut ExtCtxt<'b>,
cfg: StripUnconfigured<'a>,
@@ -996,7 +1572,7 @@
fn collect_attr(
&mut self,
- (attr, pos, derives): (ast::Attribute, usize, Vec<Path>),
+ (attr, pos, derives): (ast::Attribute, usize, Vec<ast::Path>),
item: Annotatable,
kind: AstFragmentKind,
) -> AstFragment {
@@ -1007,18 +1583,33 @@
/// its position and derives following it. We have to collect the derives in order to resolve
/// legacy derive helpers (helpers written before derives that introduce them).
fn take_first_attr(
- &mut self,
+ &self,
item: &mut impl AstLike,
- ) -> Option<(ast::Attribute, usize, Vec<Path>)> {
+ ) -> Option<(ast::Attribute, usize, Vec<ast::Path>)> {
let mut attr = None;
+ let mut cfg_pos = None;
+ let mut attr_pos = None;
+ for (pos, attr) in item.attrs().iter().enumerate() {
+ if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) {
+ let name = attr.ident().map(|ident| ident.name);
+ if name == Some(sym::cfg) || name == Some(sym::cfg_attr) {
+ cfg_pos = Some(pos); // a cfg attr found, no need to search anymore
+ break;
+ } else if attr_pos.is_none()
+ && !name.map_or(false, rustc_feature::is_builtin_attr_name)
+ {
+ attr_pos = Some(pos); // a non-cfg attr found, still may find a cfg attr
+ }
+ }
+ }
+
item.visit_attrs(|attrs| {
- attr = attrs
- .iter()
- .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..]
+ attr = Some(match (cfg_pos, attr_pos) {
+ (Some(pos), _) => (attrs.remove(pos), pos, Vec::new()),
+ (_, Some(pos)) => {
+ let attr = attrs.remove(pos);
+ let following_derives = attrs[pos..]
.iter()
.filter(|a| a.has_name(sym::derive))
.flat_map(|a| a.meta_item_list().unwrap_or_default())
@@ -1032,52 +1623,18 @@
})
.collect();
- (attr, attr_pos, following_derives)
- })
+ (attr, pos, following_derives)
+ }
+ _ => return,
+ });
});
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(item) if matches!(item.kind, ItemKind::MacCall(..)) => {
- match item.into_inner() {
- ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
- Ok((mac.args.need_semicolon(), mac, attrs))
- }
- _ => unreachable!(),
- }
- }
- StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => {
- match expr.into_inner() {
- ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => {
- Ok((mac.args.need_semicolon(), mac, attrs.into()))
- }
- _ => 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(&self, attrs: &[ast::Attribute], call: &MacCall) {
+ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
let features = self.cx.ecfg.features.unwrap();
let mut attrs = attrs.iter().peekable();
let mut span: Option<Span> = None;
@@ -1120,510 +1677,231 @@
}
}
}
-}
-/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
-/// for an AST node that supports attributes
-/// (see the `Annotatable` enum)
-/// This method assigns a `NodeId`, and sets that `NodeId`
-/// as our current 'lint node id'. If a macro call is found
-/// inside this AST node, we will use this AST node's `NodeId`
-/// to emit lints associated with that macro (allowing
-/// `#[allow]` / `#[deny]` to be applied close to
-/// the macro invocation).
-///
-/// Do *not* call this for a macro AST node
-/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
-/// at these AST nodes, since they are removed and
-/// replaced with the result of macro expansion.
-///
-/// All other `NodeId`s are assigned by `visit_id`.
-/// * `self` is the 'self' parameter for the current method,
-/// * `id` is a mutable reference to the `NodeId` field
-/// of the current AST node.
-/// * `closure` is a closure that executes the
-/// `noop_visit_*` / `noop_flat_map_*` method
-/// for the current AST node.
-macro_rules! assign_id {
- ($self:ident, $id:expr, $closure:expr) => {{
- let old_id = $self.cx.current_expansion.lint_node_id;
- if $self.monotonic {
- debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
- let new_id = $self.cx.resolver.next_node_id();
- *$id = new_id;
- $self.cx.current_expansion.lint_node_id = new_id;
+ fn expand_cfg_true(
+ &mut self,
+ node: &mut impl AstLike,
+ attr: ast::Attribute,
+ pos: usize,
+ ) -> bool {
+ let res = self.cfg.cfg_true(&attr);
+ if res {
+ // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
+ // and some tools like rustdoc and clippy rely on that. Find a way to remove them
+ // while keeping the tools working.
+ self.cx.expanded_inert_attrs.mark(&attr);
+ node.visit_attrs(|attrs| attrs.insert(pos, attr));
}
- let ret = ($closure)();
- $self.cx.current_expansion.lint_node_id = old_id;
- ret
- }};
-}
-
-impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
- fn visit_crate(&mut self, krate: &mut ast::Crate) {
- visit_clobber(krate, |krate| {
- let span = krate.span;
- let mut krate = match self.configure(krate) {
- Some(krate) => krate,
- None => {
- return ast::Crate {
- attrs: Vec::new(),
- items: Vec::new(),
- span,
- id: self.cx.resolver.next_node_id(),
- is_placeholder: false,
- };
- }
- };
-
- if let Some(attr) = self.take_first_attr(&mut krate) {
- return self
- .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate)
- .make_crate();
- }
-
- assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self));
- krate
- })
- }
-
- fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
- self.cfg.configure_expr(expr);
- visit_clobber(expr.deref_mut(), |mut expr| {
- if let Some(attr) = self.take_first_attr(&mut expr) {
- // Collect the invoc regardless of whether or not attributes are permitted here
- // expansion will eat the attribute so it won't error later.
- self.cfg.maybe_emit_expr_attr_err(&attr.0);
-
- // AstFragmentKind::Expr requires the macro to emit an expression.
- return self
- .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
- .make_expr()
- .into_inner();
- }
-
- if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs, &mac);
- self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner()
- } else {
- assign_id!(self, &mut expr.id, || {
- ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
- });
- expr
- }
- });
- }
-
- fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
- let mut arm = configure!(self, arm);
-
- if let Some(attr) = self.take_first_attr(&mut arm) {
- return self
- .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
- .make_arms();
- }
-
- assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
- }
-
- fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
- let mut field = configure!(self, field);
-
- if let Some(attr) = self.take_first_attr(&mut field) {
- return self
- .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::Fields)
- .make_expr_fields();
- }
-
- assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
- }
-
- fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
- let mut fp = configure!(self, fp);
-
- if let Some(attr) = self.take_first_attr(&mut fp) {
- return self
- .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::FieldPats)
- .make_pat_fields();
- }
-
- assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
- }
-
- fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
- let mut p = configure!(self, p);
-
- if let Some(attr) = self.take_first_attr(&mut p) {
- return self
- .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
- .make_params();
- }
-
- assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
- }
-
- fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
- let mut sf = configure!(self, sf);
-
- if let Some(attr) = self.take_first_attr(&mut sf) {
- return self
- .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::StructFields)
- .make_field_defs();
- }
-
- assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
- }
-
- fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
- let mut variant = configure!(self, variant);
-
- if let Some(attr) = self.take_first_attr(&mut variant) {
- return self
- .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
- .make_variants();
- }
-
- assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
- }
-
- fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
- let expr = configure!(self, expr);
- expr.filter_map(|mut expr| {
- if let Some(attr) = self.take_first_attr(&mut expr) {
- self.cfg.maybe_emit_expr_attr_err(&attr.0);
-
- return self
- .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
- .make_opt_expr()
- .map(|expr| expr.into_inner());
- }
-
- if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs, &mac);
- self.collect_bang(mac, AstFragmentKind::OptExpr)
- .make_opt_expr()
- .map(|expr| expr.into_inner())
- } else {
- assign_id!(self, &mut expr.id, || {
- Some({
- noop_visit_expr(&mut expr, self);
- expr
- })
- })
- }
- })
- }
-
- fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
- match pat.kind {
- PatKind::MacCall(_) => {}
- _ => return noop_visit_pat(pat, self),
- }
-
- visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) {
- PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(),
- _ => unreachable!(),
- });
- }
-
- fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
- let mut stmt = configure!(self, stmt);
-
- // 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();
- }
-
- match self.take_stmt_bang(stmt) {
- Ok((add_semicolon, mac, attrs)) => {
- self.check_attributes(&attrs, &mac);
- let mut stmts = self.collect_bang(mac, 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 add_semicolon {
- if let Some(stmt) = stmts.pop() {
- stmts.push(stmt.add_trailing_semicolon());
- }
- }
-
- return stmts;
- }
- Err(stmt) => stmt,
- }
- } else {
- stmt
- };
-
- // 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>) {
- let orig_dir_ownership = mem::replace(
- &mut self.cx.current_expansion.dir_ownership,
- DirOwnership::UnownedViaBlock,
- );
- noop_visit_block(block, self);
- self.cx.current_expansion.dir_ownership = orig_dir_ownership;
- }
-
- fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
- let mut item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
- .make_items();
- }
-
- let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck.
- let ident = item.ident;
- let span = item.span;
-
- match item.kind {
- ast::ItemKind::MacCall(ref mac) => {
- self.check_attributes(&attrs, &mac);
- item.attrs = attrs;
- item.and_then(|item| match item.kind {
- ItemKind::MacCall(mac) => {
- self.collect_bang(mac, AstFragmentKind::Items).make_items()
- }
- _ => unreachable!(),
- })
- }
- ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::empty() => {
- let (file_path, dir_path, dir_ownership) = match mod_kind {
- ModKind::Loaded(_, inline, _) => {
- // Inline `mod foo { ... }`, but we still need to push directories.
- let (dir_path, dir_ownership) = mod_dir_path(
- &self.cx.sess,
- ident,
- &attrs,
- &self.cx.current_expansion.module,
- self.cx.current_expansion.dir_ownership,
- *inline,
- );
- item.attrs = attrs;
- (None, dir_path, dir_ownership)
- }
- ModKind::Unloaded => {
- // We have an outline `mod foo;` so we need to parse the file.
- let old_attrs_len = attrs.len();
- let ParsedExternalMod {
- mut items,
- inner_span,
- file_path,
- dir_path,
- dir_ownership,
- } = parse_external_mod(
- &self.cx.sess,
- ident,
- span,
- &self.cx.current_expansion.module,
- self.cx.current_expansion.dir_ownership,
- &mut attrs,
- );
-
- if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
- (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
- }
-
- *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
- item.attrs = attrs;
- if item.attrs.len() > old_attrs_len {
- // If we loaded an out-of-line module and added some inner attributes,
- // then we need to re-configure it and re-collect attributes for
- // resolution and expansion.
- item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(
- attr,
- Annotatable::Item(item),
- AstFragmentKind::Items,
- )
- .make_items();
- }
- }
- (Some(file_path), dir_path, dir_ownership)
- }
- };
-
- // Set the module info before we flat map.
- let mut module = self.cx.current_expansion.module.with_dir_path(dir_path);
- module.mod_path.push(ident);
- if let Some(file_path) = file_path {
- module.file_path_stack.push(file_path);
- }
-
- let orig_module =
- mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
- let orig_dir_ownership =
- mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
-
- let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
-
- // Restore the module info.
- self.cx.current_expansion.dir_ownership = orig_dir_ownership;
- self.cx.current_expansion.module = orig_module;
-
- result
- }
- _ => {
- item.attrs = attrs;
- // The crate root is special - don't assign an ID to it.
- if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::empty()) {
- assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
- } else {
- noop_flat_map_item(item, self)
- }
- }
- }
- }
-
- fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
- let mut item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
- .make_trait_items();
- }
-
- match item.kind {
- 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, AstFragmentKind::TraitItems).make_trait_items()
- }
- _ => unreachable!(),
- })
- }
- _ => {
- assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
- }
- }
- }
-
- fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
- let mut item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
- .make_impl_items();
- }
-
- match item.kind {
- 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, AstFragmentKind::ImplItems).make_impl_items()
- }
- _ => unreachable!(),
- })
- }
- _ => {
- assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
- }
- }
- }
-
- fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
- match ty.kind {
- ast::TyKind::MacCall(_) => {}
- _ => return noop_visit_ty(ty, self),
- };
-
- visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) {
- ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(),
- _ => unreachable!(),
+ fn expand_cfg_attr(&self, node: &mut impl AstLike, attr: ast::Attribute, pos: usize) {
+ node.visit_attrs(|attrs| {
+ attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr, false));
});
}
+ fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
+ &mut self,
+ mut node: Node,
+ ) -> Node::OutputTy {
+ loop {
+ return match self.take_first_attr(&mut node) {
+ Some((attr, pos, derives)) => match attr.name_or_empty() {
+ sym::cfg => {
+ if self.expand_cfg_true(&mut node, attr, pos) {
+ continue;
+ }
+ Default::default()
+ }
+ sym::cfg_attr => {
+ self.expand_cfg_attr(&mut node, attr, pos);
+ continue;
+ }
+ _ => {
+ Node::pre_flat_map_node_collect_attr(&self.cfg, &attr);
+ self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
+ .make_ast::<Node>()
+ }
+ },
+ None if node.is_mac_call() => {
+ let (mac, attrs, add_semicolon) = node.take_mac_call();
+ self.check_attributes(&attrs, &mac);
+ let mut res = self.collect_bang(mac, Node::KIND).make_ast::<Node>();
+ Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
+ res
+ }
+ None => {
+ match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
+ assign_id!(this, node.id(), || node.noop_flat_map(this))
+ }) {
+ Ok(output) => output,
+ Err(returned_node) => {
+ node = returned_node;
+ continue;
+ }
+ }
+ }
+ };
+ }
+ }
+
+ fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
+ &mut self,
+ node: &mut Node,
+ ) {
+ loop {
+ return match self.take_first_attr(node) {
+ Some((attr, pos, derives)) => match attr.name_or_empty() {
+ sym::cfg => {
+ let span = attr.span;
+ if self.expand_cfg_true(node, attr, pos) {
+ continue;
+ }
+ let msg =
+ format!("removing {} is not supported in this position", Node::descr());
+ self.cx.span_err(span, &msg);
+ continue;
+ }
+ sym::cfg_attr => {
+ self.expand_cfg_attr(node, attr, pos);
+ continue;
+ }
+ _ => visit_clobber(node, |node| {
+ self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
+ .make_ast::<Node>()
+ }),
+ },
+ None if node.is_mac_call() => {
+ visit_clobber(node, |node| {
+ // Do not clobber unless it's actually a macro (uncommon case).
+ let (mac, attrs, _) = node.take_mac_call();
+ self.check_attributes(&attrs, &mac);
+ self.collect_bang(mac, Node::KIND).make_ast::<Node>()
+ })
+ }
+ None => {
+ assign_id!(self, node.id(), || node.noop_visit(self))
+ }
+ };
+ }
+ }
+}
+
+impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
+ fn flat_map_item(&mut self, node: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+ self.flat_map_node(node)
+ }
+
+ fn flat_map_trait_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+ self.flat_map_node(AstLikeWrapper::new(node, TraitItemTag))
+ }
+
+ fn flat_map_impl_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+ self.flat_map_node(AstLikeWrapper::new(node, ImplItemTag))
+ }
+
fn flat_map_foreign_item(
&mut self,
- foreign_item: P<ast::ForeignItem>,
+ node: P<ast::ForeignItem>,
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
- let mut foreign_item = configure!(self, foreign_item);
+ self.flat_map_node(node)
+ }
- if let Some(attr) = self.take_first_attr(&mut foreign_item) {
- return self
- .collect_attr(
- attr,
- Annotatable::ForeignItem(foreign_item),
- AstFragmentKind::ForeignItems,
- )
- .make_foreign_items();
- }
+ fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
+ self.flat_map_node(node)
+ }
- match foreign_item.kind {
- 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, AstFragmentKind::ForeignItems).make_foreign_items()
- }
- _ => unreachable!(),
- })
- }
- _ => {
- assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
- foreign_item,
- self
- ))
- }
- }
+ fn flat_map_field_def(&mut self, node: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
+ self.flat_map_node(node)
+ }
+
+ fn flat_map_pat_field(&mut self, node: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
+ self.flat_map_node(node)
+ }
+
+ fn flat_map_expr_field(&mut self, node: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
+ self.flat_map_node(node)
+ }
+
+ fn flat_map_param(&mut self, node: ast::Param) -> SmallVec<[ast::Param; 1]> {
+ self.flat_map_node(node)
}
fn flat_map_generic_param(
&mut self,
- param: ast::GenericParam,
+ node: ast::GenericParam,
) -> SmallVec<[ast::GenericParam; 1]> {
- let mut param = configure!(self, param);
-
- if let Some(attr) = self.take_first_attr(&mut param) {
- return self
- .collect_attr(
- attr,
- Annotatable::GenericParam(param),
- AstFragmentKind::GenericParams,
- )
- .make_generic_params();
- }
-
- assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
+ self.flat_map_node(node)
}
- fn visit_id(&mut self, id: &mut ast::NodeId) {
+ fn flat_map_arm(&mut self, node: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
+ self.flat_map_node(node)
+ }
+
+ fn flat_map_stmt(&mut self, mut node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+ // FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
+ // changing that requires some compatibility measures.
+ if node.is_expr() {
+ // 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.
+ return match &node.kind {
+ StmtKind::Expr(expr)
+ if matches!(**expr, ast::Expr { kind: 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
+ let res = noop_flat_map_stmt(node, self);
+ self.cx.current_expansion.is_trailing_mac = false;
+ res
+ }
+ _ => assign_id!(self, &mut node.id, || noop_flat_map_stmt(node, self)),
+ };
+ }
+
+ self.flat_map_node(node)
+ }
+
+ fn visit_crate(&mut self, node: &mut ast::Crate) {
+ self.visit_node(node)
+ }
+
+ fn visit_ty(&mut self, node: &mut P<ast::Ty>) {
+ self.visit_node(node)
+ }
+
+ fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
+ self.visit_node(node)
+ }
+
+ fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
+ // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
+ if let Some(attr) = node.attrs.first() {
+ self.cfg.maybe_emit_expr_attr_err(attr);
+ }
+ self.visit_node(node)
+ }
+
+ fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
+ self.flat_map_node(AstLikeWrapper::new(node, OptExprTag))
+ }
+
+ fn visit_block(&mut self, node: &mut P<ast::Block>) {
+ let orig_dir_ownership = mem::replace(
+ &mut self.cx.current_expansion.dir_ownership,
+ DirOwnership::UnownedViaBlock,
+ );
+ noop_visit_block(node, self);
+ self.cx.current_expansion.dir_ownership = orig_dir_ownership;
+ }
+
+ fn visit_id(&mut self, id: &mut NodeId) {
// We may have already assigned a `NodeId`
// by calling `assign_id`
if self.monotonic && *id == ast::DUMMY_NODE_ID {
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 47a64b4..43a310f 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,6 +1,7 @@
+#![feature(associated_type_bounds)]
+#![feature(associated_type_defaults)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
-#![cfg_attr(bootstrap, feature(destructuring_assignment))]
#![feature(if_let_guard)]
#![feature(let_else)]
#![feature(proc_macro_diagnostic)]
@@ -8,6 +9,7 @@
#![feature(proc_macro_span)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[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 8065911..f71fb58 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1039,7 +1039,7 @@
));
err.span_suggestion(
span,
- &format!("try a `pat_param` fragment specifier instead"),
+ "try a `pat_param` fragment specifier instead",
suggestion,
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 825af9a..af593e9 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -123,7 +123,7 @@
span,
is_placeholder: true,
}]),
- AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField {
+ AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
attrs: Default::default(),
expr: expr_placeholder(),
id,
@@ -132,7 +132,7 @@
span,
is_placeholder: true,
}]),
- AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField {
+ AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
attrs: Default::default(),
id,
ident,
@@ -159,7 +159,7 @@
ty: ty(),
is_placeholder: true,
}]),
- AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ast::FieldDef {
+ AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
attrs: Default::default(),
id,
ident: None,
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 5656465..efbe0b6 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -158,7 +158,7 @@
for ch in data.as_str().chars() {
escaped.extend(ch.escape_debug());
}
- let stream = vec![
+ let stream = [
Ident(sym::doc, false),
Eq,
TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
@@ -221,7 +221,7 @@
let integer = TokenKind::lit(token::Integer, symbol, suffix);
let a = tokenstream::TokenTree::token(minus, span);
let b = tokenstream::TokenTree::token(integer, span);
- return vec![a, b].into_iter().collect();
+ return [a, b].into_iter().collect();
}
TokenTree::Literal(self::Literal {
lit: token::Lit { kind: token::Float, symbol, suffix },
@@ -232,7 +232,7 @@
let float = TokenKind::lit(token::Float, symbol, suffix);
let a = tokenstream::TokenTree::token(minus, span);
let b = tokenstream::TokenTree::token(float, span);
- return vec![a, b].into_iter().collect();
+ return [a, b].into_iter().collect();
}
TokenTree::Literal(self::Literal { lit, span }) => {
return tokenstream::TokenTree::token(Literal(lit), span).into();
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 32a9d08..d43f926 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -70,6 +70,8 @@
(accepted, cfg_attr_multi, "1.33.0", Some(54881), None),
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
(accepted, cfg_doctest, "1.40.0", Some(62210), None),
+ /// Enables `#[cfg(panic = "...")]` config key.
+ (accepted, cfg_panic, "1.60.0", Some(77443), None),
/// Allows `cfg(target_feature = "...")`.
(accepted, cfg_target_feature, "1.27.0", Some(29717), None),
/// Allows `cfg(target_vendor = "...")`.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ebd12d6..5545abc 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -161,6 +161,12 @@
(active, staged_api, "1.0.0", None, None),
/// Added for testing E0705; perma-unstable.
(active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+ /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
+ /// Marked `incomplete` since perma-unstable and unsound.
+ (incomplete, unsafe_pin_internals, "1.60.0", None, None),
+ /// Use for stable + negative coherence and strict coherence depending on trait's
+ /// rustc_strict_coherence value.
+ (active, with_negative_coherence, "1.60.0", None, None),
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
@@ -274,20 +280,20 @@
(incomplete, adt_const_params, "1.56.0", Some(44580), None),
/// Allows defining an `#[alloc_error_handler]`.
(active, alloc_error_handler, "1.29.0", Some(51540), None),
- /// Allows a test to fail without failing the whole suite.
- (active, allow_fail, "1.19.0", Some(46488), None),
/// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
/// Allows trait methods with arbitrary self types.
(active, arbitrary_self_types, "1.23.0", Some(44874), None),
/// Allows using `const` operands in inline assembly.
- (active, asm_const, "1.58.0", Some(72016), None),
+ (active, asm_const, "1.58.0", Some(93332), None),
/// Enables experimental inline assembly support for additional architectures.
- (active, asm_experimental_arch, "1.58.0", Some(72016), None),
+ (active, asm_experimental_arch, "1.58.0", Some(93335), None),
/// Allows using `sym` operands in inline assembly.
- (active, asm_sym, "1.58.0", Some(72016), None),
+ (active, asm_sym, "1.58.0", Some(93333), None),
/// Allows the `may_unwind` option in inline assembly.
- (active, asm_unwind, "1.58.0", Some(72016), None),
+ (active, asm_unwind, "1.58.0", Some(93334), None),
+ /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
+ (active, associated_const_equality, "1.58.0", Some(92827), None),
/// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows associated type defaults.
@@ -300,14 +306,14 @@
(active, c_variadic, "1.34.0", Some(44930), None),
/// Allows capturing disjoint fields in a closure/generator (RFC 2229).
(incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None),
- /// Enables `#[cfg(panic = "...")]` config key.
- (active, cfg_panic, "1.49.0", Some(77443), None),
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),
/// Allows `cfg(target_abi = "...")`.
(active, cfg_target_abi, "1.55.0", Some(80970), None),
- /// Allows `cfg(target_has_atomic = "...")`.
- (active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
+ /// Allows `cfg(target_has_atomic_load_store = "...")`.
+ (active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
+ /// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
+ (active, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None),
/// Allows `cfg(target_thread_local)`.
(active, cfg_target_thread_local, "1.7.0", Some(29594), None),
/// Allow conditional compilation depending on rust version
@@ -327,7 +333,7 @@
/// Allows using and casting function pointers in a `const fn`.
(active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
/// Allows trait bounds in `const fn`.
- (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
+ (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
/// Allows `for _ in _` loops in const contexts.
(active, const_for, "1.56.0", Some(87575), None),
/// Allows argument and return position `impl Trait` in a `const fn`.
@@ -413,7 +419,7 @@
// Allows setting the threshold for the `large_assignments` lint.
(active, large_assignments, "1.52.0", Some(83518), None),
/// Allows `if/while p && let q = r && ...` chains.
- (incomplete, let_chains, "1.37.0", Some(53667), None),
+ (active, let_chains, "1.37.0", Some(53667), None),
/// Allows `let...else` statements.
(active, let_else, "1.56.0", Some(87335), None),
/// Allows `#[link(..., cfg(..))]`.
@@ -528,6 +534,8 @@
///
/// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0.
(active, untagged_unions, "1.13.0", Some(55149), None),
+ /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
+ (active, used_with_arg, "1.60.0", Some(93798), None),
/// Allows `extern "wasm" fn`
(active, wasm_abi, "1.53.0", Some(83788), None),
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 0644948..1fb1a38 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -26,16 +26,14 @@
// (name in cfg, feature, function to check if the feature is enabled)
(sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)),
(sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
- (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
- (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
(
sym::target_has_atomic_equal_alignment,
- sym::cfg_target_has_atomic,
- cfg_fn!(cfg_target_has_atomic),
+ sym::cfg_target_has_atomic_equal_alignment,
+ cfg_fn!(cfg_target_has_atomic_equal_alignment),
),
+ (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
(sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
(sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
- (sym::panic, sym::cfg_panic, cfg_fn!(cfg_panic)),
];
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
@@ -324,7 +322,7 @@
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing),
- ungated!(used, Normal, template!(Word), WarnFollowing),
+ ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing),
// Limits:
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
@@ -351,7 +349,7 @@
// Runtime
ungated!(
- windows_subsystem, Normal,
+ windows_subsystem, CrateLevel,
template!(NameValueStr: "windows|console"), FutureWarnFollowing
),
ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
@@ -359,7 +357,7 @@
// Code generation:
ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
ungated!(cold, Normal, template!(Word), WarnFollowing),
- ungated!(no_builtins, Normal, template!(Word), WarnFollowing),
+ ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
ungated!(track_caller, Normal, template!(Word), WarnFollowing),
gated!(
@@ -402,7 +400,6 @@
},
// Testing:
- gated!(allow_fail, Normal, template!(Word), WarnFollowing, experimental!(allow_fail)),
gated!(
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks,
"custom test frameworks are an unstable feature",
@@ -580,6 +577,9 @@
rustc_attr!(
rustc_trivial_field_reads, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
),
+ // Used by the `rustc::potential_query_instability` lint to warn methods which
+ // might not be stable during incremental compilation.
+ rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Const related:
@@ -622,6 +622,11 @@
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
"language items are subject to change",
),
+ rustc_attr!(
+ rustc_pass_by_value, Normal,
+ template!(Word), ErrorFollowing,
+ "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
+ ),
BuiltinAttribute {
name: sym::rustc_diagnostic_item,
type_: Normal,
@@ -676,6 +681,12 @@
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
),
+ rustc_attr!(
+ rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing,
+ "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
+ definition of a trait, it's currently in experimental form and should be changed before \
+ being exposed outside of the std"
+ ),
// ==========================================================================
// Internal attributes, Testing:
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index b9f3b5a..f5f944d 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -48,6 +48,8 @@
(removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
Some("merged into `#![feature(slice_patterns)]`")),
(removed, allocator, "1.0.0", None, None, None),
+ /// Allows a test to fail without failing the whole suite.
+ (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
(removed, await_macro, "1.38.0", Some(50547), None,
Some("subsumed by `.await` syntax")),
/// Allows comparing raw pointers during const eval.
diff --git a/compiler/rustc_graphviz/src/tests.rs b/compiler/rustc_graphviz/src/tests.rs
index a297bac..154bae4 100644
--- a/compiler/rustc_graphviz/src/tests.rs
+++ b/compiler/rustc_graphviz/src/tests.rs
@@ -56,7 +56,7 @@
match self {
UnlabelledNodes(len) => vec![None; len],
AllNodesLabelled(lbls) => lbls.into_iter().map(Some).collect(),
- SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
+ SomeNodesLabelled(lbls) => lbls,
}
}
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index edad00e..27ec461 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -30,7 +30,6 @@
[] impl_item_ref: rustc_hir::ImplItemRef,
[] item: rustc_hir::Item<'tcx>,
[] inline_asm: rustc_hir::InlineAsm<'tcx>,
- [] llvm_inline_asm: rustc_hir::LlvmInlineAsm<'tcx>,
[] local: rustc_hir::Local<'tcx>,
[] mod_: rustc_hir::Mod<'tcx>,
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index a43cb02..e99f61d 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -266,59 +266,67 @@
///
/// **Belongs to the type namespace.**
PrimTy(hir::PrimTy),
- /// The `Self` type, optionally with the trait it is associated with
- /// and optionally with the [`DefId`] of the impl it is associated with.
+ /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
+ /// optionally with the [`DefId`] of the item introducing the `Self` type alias.
///
/// **Belongs to the type namespace.**
///
- /// For example, the `Self` in
- ///
+ /// Examples:
/// ```
+ /// struct Bar(Box<Self>);
+ /// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }`
+ ///
/// trait Foo {
/// fn foo() -> Box<Self>;
+ /// // `Res::SelfTy { trait_: Some(Foo), alias_of: None }`
/// }
- /// ```
- ///
- /// would have the [`DefId`] of `Foo` associated with it. The `Self` in
- ///
- /// ```
- /// struct Bar;
///
/// impl Bar {
- /// fn new() -> Self { Bar }
+ /// fn blah() {
+ /// let _: Self;
+ /// // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }`
+ /// }
/// }
- /// ```
///
- /// would have the [`DefId`] of the impl associated with it. Finally, the `Self` in
- ///
- /// ```
/// impl Foo for Bar {
- /// fn foo() -> Box<Self> { Box::new(Bar) }
+ /// fn foo() -> Box<Self> {
+ /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+ /// let _: Self;
+ /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+ ///
+ /// todo!()
+ /// }
/// }
/// ```
///
- /// would have both the [`DefId`] of `Foo` and the [`DefId`] of the impl
- /// associated with it.
- ///
/// *See also [`Res::SelfCtor`].*
///
/// -----
///
- /// HACK(min_const_generics): impl self types also have an optional requirement to **not** mention
+ /// HACK(min_const_generics): self types also have an optional requirement to **not** mention
/// any generic parameters to allow the following with `min_const_generics`:
/// ```
/// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
+ ///
+ /// struct Bar([u8; baz::<Self>()]);
+ /// const fn baz<T>() -> usize { 10 }
/// ```
/// 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(generic_const_exprs): Remove this bodge once that feature is stable.
- SelfTy(
- /// Optionally, the trait associated with this `Self` type.
- Option<DefId>,
- /// Optionally, the impl associated with this `Self` type.
- Option<(DefId, bool)>,
- ),
+ /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint:
+ /// ```
+ /// fn foo<T>() {
+ /// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
+ /// }
+ /// ```
+ // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
+ SelfTy {
+ /// The trait this `Self` is a generic arg for.
+ trait_: Option<DefId>,
+ /// The item introducing the `Self` type alias. Can be used in the `type_of` query
+ /// to get the underlying type. Additionally whether the `Self` type is disallowed
+ /// from mentioning generics (i.e. when used in an anonymous constant).
+ alias_to: Option<(DefId, bool)>,
+ },
/// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
///
/// **Belongs to the type namespace.**
@@ -550,7 +558,7 @@
Res::Local(..)
| Res::PrimTy(..)
- | Res::SelfTy(..)
+ | Res::SelfTy { .. }
| Res::SelfCtor(..)
| Res::ToolMod
| Res::NonMacroAttr(..)
@@ -573,7 +581,7 @@
Res::SelfCtor(..) => "self constructor",
Res::PrimTy(..) => "builtin type",
Res::Local(..) => "local variable",
- Res::SelfTy(..) => "self type",
+ Res::SelfTy { .. } => "self type",
Res::ToolMod => "tool module",
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
Res::Err => "unresolved item",
@@ -596,7 +604,7 @@
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)),
- Res::SelfTy(a, b) => Res::SelfTy(a, b),
+ Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
@@ -620,7 +628,7 @@
pub fn ns(&self) -> Option<Namespace> {
match self {
Res::Def(kind, ..) => kind.ns(),
- Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS),
+ Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS),
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
Res::Err => None,
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index d813c88..d655f12 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -7,7 +7,6 @@
pub use crate::def_id::DefPathHash;
use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE};
use crate::def_path_hash_map::DefPathHashMap;
-use crate::hir;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
@@ -101,15 +100,6 @@
pub struct Definitions {
table: DefPathTable,
- /// Only [`LocalDefId`]s for items and item-like are HIR owners.
- /// The associated `HirId` has a `local_id` of `0`.
- /// Generic parameters and closures are also assigned a `LocalDefId` but are not HIR owners.
- /// Their `HirId`s are defined by their position while lowering the enclosing owner.
- // FIXME(cjgillot) Some `LocalDefId`s from `use` items are dropped during lowering and lack a `HirId`.
- pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
- /// The reverse mapping of `def_id_to_hir_id`.
- pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
-
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
@@ -324,17 +314,6 @@
})
}
- #[inline]
- #[track_caller]
- pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
- self.def_id_to_hir_id[id].unwrap()
- }
-
- #[inline]
- pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
- self.hir_id_to_def_id.get(&hir_id).copied()
- }
-
/// Adds a root definition (no parent) and a few other reserved definitions.
pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
let key = DefKey {
@@ -361,8 +340,6 @@
Definitions {
table,
- def_id_to_hir_id: Default::default(),
- hir_id_to_def_id: Default::default(),
expansions_that_defined: Default::default(),
def_id_to_span,
stable_crate_id,
@@ -414,26 +391,6 @@
def_id
}
- /// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
- /// AST to HIR lowering.
- pub fn init_def_id_to_hir_id_mapping(
- &mut self,
- mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
- ) {
- assert!(
- self.def_id_to_hir_id.is_empty(),
- "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
- );
-
- // Build the reverse mapping of `def_id_to_hir_id`.
- self.hir_id_to_def_id = mapping
- .iter_enumerated()
- .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
- .collect();
-
- self.def_id_to_hir_id = mapping;
- }
-
pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
self.expansions_that_defined.get(&id).copied().unwrap_or_else(ExpnId::root)
}
@@ -445,17 +402,21 @@
}
pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
- self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
+ self.table.def_path_hashes.indices().map(|local_def_index| LocalDefId { local_def_index })
}
#[inline(always)]
- pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> LocalDefId {
+ pub fn local_def_path_hash_to_def_id(
+ &self,
+ hash: DefPathHash,
+ err: &mut dyn FnMut() -> !,
+ ) -> LocalDefId {
debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
self.table
.def_path_hash_to_index
.get(&hash)
.map(|local_def_index| LocalDefId { local_def_index })
- .unwrap()
+ .unwrap_or_else(|| err())
}
pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index d597562..0961d01 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -5,8 +5,8 @@
use crate::LangItem;
use rustc_ast::util::parser::ExprPrecedence;
-use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
-use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObjectSyntax, UintTy};
+use rustc_ast::{self as ast, CrateSugar};
+use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -205,7 +205,6 @@
#[derive(Debug, HashStable_Generic)]
pub struct PathSegment<'hir> {
/// The identifier portion of this path segment.
- #[stable_hasher(project(name))]
pub ident: Ident,
// `id` and `res` are optional. We currently only use these in save-analysis,
// any path segments without these will not have save-analysis info and
@@ -294,10 +293,6 @@
}
}
- pub fn is_const(&self) -> bool {
- matches!(self, GenericArg::Const(_))
- }
-
pub fn is_synthetic(&self) -> bool {
matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
}
@@ -319,6 +314,13 @@
GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
}
}
+
+ pub fn is_ty_or_const(&self) -> bool {
+ match self {
+ GenericArg::Lifetime(_) => false,
+ GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => true,
+ }
+ }
}
#[derive(Debug, HashStable_Generic)]
@@ -375,7 +377,7 @@
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
_ => false,
}) || self.bindings.iter().any(|arg| match arg.kind {
- TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
+ TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err),
_ => false,
})
}
@@ -638,9 +640,8 @@
_ => return false,
};
match path.res {
- Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => {
- def_id == param_def_id
- }
+ Res::Def(DefKind::TyParam, def_id)
+ | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id,
_ => false,
}
}
@@ -705,6 +706,17 @@
pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
/// Content of local bodies.
pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
+ /// Non-owning definitions contained in this owner.
+ pub local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
+}
+
+impl<'tcx> OwnerNodes<'tcx> {
+ pub fn node(&self) -> OwnerNode<'tcx> {
+ use rustc_index::vec::Idx;
+ let node = self.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
+ let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
+ node
+ }
}
/// Full information resulting from lowering an AST node.
@@ -724,10 +736,39 @@
impl<'tcx> OwnerInfo<'tcx> {
#[inline]
pub fn node(&self) -> OwnerNode<'tcx> {
- use rustc_index::vec::Idx;
- let node = self.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
- let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
- node
+ self.nodes.node()
+ }
+}
+
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
+pub enum MaybeOwner<T> {
+ Owner(T),
+ NonOwner(HirId),
+ /// Used as a placeholder for unused LocalDefId.
+ Phantom,
+}
+
+impl<T> MaybeOwner<T> {
+ pub fn as_owner(self) -> Option<T> {
+ match self {
+ MaybeOwner::Owner(i) => Some(i),
+ MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None,
+ }
+ }
+
+ pub fn map<U>(self, f: impl FnOnce(T) -> U) -> MaybeOwner<U> {
+ match self {
+ MaybeOwner::Owner(i) => MaybeOwner::Owner(f(i)),
+ MaybeOwner::NonOwner(hir_id) => MaybeOwner::NonOwner(hir_id),
+ MaybeOwner::Phantom => MaybeOwner::Phantom,
+ }
+ }
+
+ pub fn unwrap(self) -> T {
+ match self {
+ MaybeOwner::Owner(i) => i,
+ MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => panic!("Not a HIR owner"),
+ }
}
}
@@ -739,7 +780,7 @@
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
- pub owners: IndexVec<LocalDefId, Option<OwnerInfo<'hir>>>,
+ pub owners: IndexVec<LocalDefId, MaybeOwner<&'hir OwnerInfo<'hir>>>,
pub hir_hash: Fingerprint,
}
@@ -850,7 +891,6 @@
#[stable_hasher(ignore)]
pub hir_id: HirId,
/// The identifier for the field.
- #[stable_hasher(project(name))]
pub ident: Ident,
/// The pattern the field is destructured to.
pub pat: &'hir Pat<'hir>,
@@ -1473,7 +1513,6 @@
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
- ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
ExprKind::Yield(..) => ExprPrecedence::Yield,
@@ -1533,7 +1572,6 @@
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
- | ExprKind::LlvmInlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::Lit(_)
| ExprKind::ConstBlock(..)
@@ -1616,7 +1654,6 @@
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
- | ExprKind::LlvmInlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::ConstBlock(..)
| ExprKind::Box(..)
@@ -1671,13 +1708,13 @@
Call(&'hir Expr<'hir>, &'hir [Expr<'hir>]),
/// A method call (e.g., `x.foo::<'static, Bar, Baz>(a, b, c, d)`).
///
- /// The `PathSegment`/`Span` represent the method name and its generic arguments
+ /// The `PathSegment` represents the method name and its generic arguments
/// (within the angle brackets).
- /// The first element of the vector of `Expr`s is the expression that evaluates
+ /// The first element of the `&[Expr]` is the expression that evaluates
/// to the object on which the method is being called on (the receiver),
/// and the remaining elements are the rest of the arguments.
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
- /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
+ /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`.
/// The final `Span` represents the span of the function and arguments
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
///
@@ -1685,7 +1722,7 @@
/// the `hir_id` of the `MethodCall` node itself.
///
/// [`type_dependent_def_id`]: ../ty/struct.TypeckResults.html#method.type_dependent_def_id
- MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>], Span),
+ MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(&'hir [Expr<'hir>]),
/// A binary operation (e.g., `a + b`, `a * b`).
@@ -1757,8 +1794,6 @@
/// Inline assembly (from `asm!`), with its outputs and inputs.
InlineAsm(&'hir InlineAsm<'hir>),
- /// Inline assembly (from `llvm_asm!`), with its outputs and inputs.
- LlvmInlineAsm(&'hir LlvmInlineAsm<'hir>),
/// A struct or struct-like variant literal expression.
///
@@ -2076,7 +2111,6 @@
pub ident: Ident,
pub def_id: LocalDefId,
pub vis: Visibility<'hir>,
- pub defaultness: Defaultness,
pub generics: Generics<'hir>,
pub kind: ImplItemKind<'hir>,
pub span: Span,
@@ -2127,29 +2161,52 @@
#[derive(Debug, HashStable_Generic)]
pub struct TypeBinding<'hir> {
pub hir_id: HirId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub gen_args: &'hir GenericArgs<'hir>,
pub kind: TypeBindingKind<'hir>,
pub span: Span,
}
+#[derive(Debug, HashStable_Generic)]
+pub enum Term<'hir> {
+ Ty(&'hir Ty<'hir>),
+ Const(AnonConst),
+}
+
+impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
+ fn from(ty: &'hir Ty<'hir>) -> Self {
+ Term::Ty(ty)
+ }
+}
+
+impl<'hir> From<AnonConst> for Term<'hir> {
+ fn from(c: AnonConst) -> Self {
+ Term::Const(c)
+ }
+}
+
// Represents the two kinds of type bindings.
#[derive(Debug, HashStable_Generic)]
pub enum TypeBindingKind<'hir> {
/// E.g., `Foo<Bar: Send>`.
Constraint { bounds: &'hir [GenericBound<'hir>] },
- /// E.g., `Foo<Bar = ()>`.
- Equality { ty: &'hir Ty<'hir> },
+ /// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
+ Equality { term: Term<'hir> },
}
impl TypeBinding<'_> {
pub fn ty(&self) -> &Ty<'_> {
match self.kind {
- TypeBindingKind::Equality { ref ty } => ty,
+ TypeBindingKind::Equality { term: Term::Ty(ref ty) } => ty,
_ => panic!("expected equality type binding for parenthesized generic args"),
}
}
+ pub fn opt_const(&self) -> Option<&'_ AnonConst> {
+ match self.kind {
+ TypeBindingKind::Equality { term: Term::Const(ref c) } => Some(c),
+ _ => None,
+ }
+ }
}
#[derive(Debug)]
@@ -2371,36 +2428,6 @@
pub line_spans: &'hir [Span],
}
-#[derive(Copy, Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
-pub struct LlvmInlineAsmOutput {
- pub constraint: Symbol,
- pub is_rw: bool,
- pub is_indirect: bool,
- pub span: Span,
-}
-
-// NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
-// it needs to be `Clone` and `Decodable` and use plain `Vec<T>` instead of
-// arena-allocated slice.
-#[derive(Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
-pub struct LlvmInlineAsmInner {
- pub asm: Symbol,
- pub asm_str_style: StrStyle,
- pub outputs: Vec<LlvmInlineAsmOutput>,
- pub inputs: Vec<Symbol>,
- pub clobbers: Vec<Symbol>,
- pub volatile: bool,
- pub alignstack: bool,
- pub dialect: LlvmAsmDialect,
-}
-
-#[derive(Debug, HashStable_Generic)]
-pub struct LlvmInlineAsm<'hir> {
- pub inner: LlvmInlineAsmInner,
- pub outputs_exprs: &'hir [Expr<'hir>],
- pub inputs_exprs: &'hir [Expr<'hir>],
-}
-
/// Represents a parameter in a function header.
#[derive(Debug, HashStable_Generic)]
pub struct Param<'hir> {
@@ -2515,7 +2542,6 @@
#[derive(Debug, HashStable_Generic)]
pub struct Variant<'hir> {
/// Name of the variant.
- #[stable_hasher(project(name))]
pub ident: Ident,
/// Id of the variant (not the constructor, see `VariantData::ctor_hir_id()`).
pub id: HirId,
@@ -2605,7 +2631,6 @@
#[derive(Debug, HashStable_Generic)]
pub struct FieldDef<'hir> {
pub span: Span,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub vis: Visibility<'hir>,
pub hir_id: HirId,
@@ -2745,6 +2770,10 @@
}
impl FnHeader {
+ pub fn is_async(&self) -> bool {
+ matches!(&self.asyncness, IsAsync::Async)
+ }
+
pub fn is_const(&self) -> bool {
matches!(&self.constness, Constness::Const)
}
@@ -2864,7 +2893,6 @@
#[derive(Encodable, Debug, HashStable_Generic)]
pub struct TraitItemRef {
pub id: TraitItemId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub kind: AssocItemKind,
pub span: Span,
@@ -2880,11 +2908,12 @@
#[derive(Debug, HashStable_Generic)]
pub struct ImplItemRef {
pub id: ImplItemId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub kind: AssocItemKind,
pub span: Span,
pub defaultness: Defaultness,
+ /// When we are in a trait impl, link to the trait-item's id.
+ pub trait_item_def_id: Option<DefId>,
}
#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
@@ -2919,7 +2948,6 @@
#[derive(Debug, HashStable_Generic)]
pub struct ForeignItemRef {
pub id: ForeignItemId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub span: Span,
}
@@ -3189,7 +3217,7 @@
}
}
- pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
+ pub fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> {
match self {
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
@@ -3201,6 +3229,15 @@
}
}
+ pub fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> {
+ match self {
+ Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
+ | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig),
+ _ => None,
+ }
+ }
+
pub fn body_id(&self) -> Option<BodyId> {
match self {
Node::TraitItem(TraitItem {
@@ -3264,13 +3301,13 @@
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
- rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
+ rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
rustc_data_structures::static_assert_size!(super::Ty<'static>, 80);
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
- rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 152);
+ rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 144);
rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 136);
}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 1482a96..dee391b 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -19,16 +19,23 @@
}
impl HirId {
+ #[inline]
pub fn expect_owner(self) -> LocalDefId {
assert_eq!(self.local_id.index(), 0);
self.owner
}
+ #[inline]
pub fn as_owner(self) -> Option<LocalDefId> {
if self.local_id.index() == 0 { Some(self.owner) } else { None }
}
#[inline]
+ pub fn is_owner(self) -> bool {
+ self.local_id.index() == 0
+ }
+
+ #[inline]
pub fn make_owner(owner: LocalDefId) -> Self {
Self { owner, local_id: ItemLocalId::from_u32(0) }
}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index d0eee42..c55f2a7 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -141,58 +141,46 @@
// Used when no map is actually available, forcing manual implementation of nested visitors.
impl<'hir> Map<'hir> for ! {
fn find(&self, _: HirId) -> Option<Node<'hir>> {
- unreachable!()
+ *self;
}
fn body(&self, _: BodyId) -> &'hir Body<'hir> {
- unreachable!()
+ *self;
}
fn item(&self, _: ItemId) -> &'hir Item<'hir> {
- unreachable!()
+ *self;
}
fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
- unreachable!()
+ *self;
}
fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
- unreachable!()
+ *self;
}
fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
- unreachable!()
+ *self;
}
}
-/// An erased version of `Map<'hir>`, using dynamic dispatch.
-/// NOTE: This type is effectively only usable with `NestedVisitorMap::None`.
-pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>);
+pub mod nested_filter {
+ use super::Map;
-impl<'hir> Map<'hir> for ErasedMap<'hir> {
- fn find(&self, _: HirId) -> Option<Node<'hir>> {
- None
- }
- fn body(&self, id: BodyId) -> &'hir Body<'hir> {
- self.0.body(id)
- }
- fn item(&self, id: ItemId) -> &'hir Item<'hir> {
- self.0.item(id)
- }
- fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- self.0.trait_item(id)
- }
- fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- self.0.impl_item(id)
- }
- fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- self.0.foreign_item(id)
- }
-}
+ /// Specifies what nested things a visitor wants to visit. The most
+ /// common choice is `OnlyBodies`, which will cause the visitor to
+ /// visit fn bodies for fns that it encounters, but skip over nested
+ /// item-like things.
+ ///
+ /// See the comments on `ItemLikeVisitor` for more details on the overall
+ /// visit strategy.
+ pub trait NestedFilter<'hir> {
+ type Map: Map<'hir>;
-/// Specifies what nested things a visitor wants to visit. The most
-/// common choice is `OnlyBodies`, which will cause the visitor to
-/// visit fn bodies for fns that it encounters, but skip over nested
-/// item-like things.
-///
-/// See the comments on `ItemLikeVisitor` for more details on the overall
-/// visit strategy.
-pub enum NestedVisitorMap<M> {
+ /// Whether the visitor visits nested "item-like" things.
+ /// E.g., item, impl-item.
+ const INTER: bool;
+ /// Whether the visitor visits "intra item-like" things.
+ /// E.g., function body, closure, `AnonConst`
+ const INTRA: bool;
+ }
+
/// Do not visit any nested things. When you add a new
/// "non-nested" thing, you will want to audit such uses to see if
/// they remain valid.
@@ -200,47 +188,16 @@
/// Use this if you are only walking some particular kind of tree
/// (i.e., a type, or fn signature) and you don't want to thread a
/// HIR map around.
- None,
-
- /// Do not visit nested item-like things, but visit nested things
- /// that are inside of an item-like.
- ///
- /// **This is the most common choice.** A very common pattern is
- /// to use `visit_all_item_likes()` as an outer loop,
- /// and to have the visitor that visits the contents of each item
- /// using this setting.
- OnlyBodies(M),
-
- /// Visits all nested things, including item-likes.
- ///
- /// **This is an unusual choice.** It is used when you want to
- /// process everything within their lexical context. Typically you
- /// kick off the visit by doing `walk_krate()`.
- All(M),
-}
-
-impl<M> NestedVisitorMap<M> {
- /// Returns the map to use for an "intra item-like" thing (if any).
- /// E.g., function body.
- fn intra(self) -> Option<M> {
- match self {
- NestedVisitorMap::None => None,
- NestedVisitorMap::OnlyBodies(map) => Some(map),
- NestedVisitorMap::All(map) => Some(map),
- }
- }
-
- /// Returns the map to use for an "item-like" thing (if any).
- /// E.g., item, impl-item.
- fn inter(self) -> Option<M> {
- match self {
- NestedVisitorMap::None => None,
- NestedVisitorMap::OnlyBodies(_) => None,
- NestedVisitorMap::All(map) => Some(map),
- }
+ pub struct None(());
+ impl NestedFilter<'_> for None {
+ type Map = !;
+ const INTER: bool = false;
+ const INTRA: bool = false;
}
}
+use nested_filter::NestedFilter;
+
/// Each method of the Visitor trait is a hook to be potentially
/// overridden. Each method's default implementation recursively visits
/// the substructure of the input via the corresponding `walk` method;
@@ -258,7 +215,9 @@
/// to monitor future changes to `Visitor` in case a new method with a
/// new default implementation gets introduced.)
pub trait Visitor<'v>: Sized {
- type Map: Map<'v>;
+ // this type should not be overridden, it exists for convenient usage as `Self::Map`
+ type Map: Map<'v> = <Self::NestedFilter as NestedFilter<'v>>::Map;
+ type NestedFilter: NestedFilter<'v> = nested_filter::None;
///////////////////////////////////////////////////////////////////////////
// Nested items.
@@ -279,7 +238,12 @@
/// `panic!()`. This way, if a new `visit_nested_XXX` variant is
/// added in the future, we will see the panic in your code and
/// fix it appropriately.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map>;
+ fn nested_visit_map(&mut self) -> Self::Map {
+ panic!(
+ "nested_visit_map must be implemented or consider using \
+ `type NestedFilter = nested_filter::None` (the default)"
+ );
+ }
/// Invoked when a nested item is encountered. By default does
/// nothing unless you override `nested_visit_map` to return other than
@@ -290,32 +254,40 @@
/// reason to override this method is if you want a nested pattern
/// but cannot supply a `Map`; see `nested_visit_map` for advice.
fn visit_nested_item(&mut self, id: ItemId) {
- let opt_item = self.nested_visit_map().inter().map(|map| map.item(id));
- walk_list!(self, visit_item, opt_item);
+ if Self::NestedFilter::INTER {
+ let item = self.nested_visit_map().item(id);
+ self.visit_item(item);
+ }
}
/// Like `visit_nested_item()`, but for trait items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
fn visit_nested_trait_item(&mut self, id: TraitItemId) {
- let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
- walk_list!(self, visit_trait_item, opt_item);
+ if Self::NestedFilter::INTER {
+ let item = self.nested_visit_map().trait_item(id);
+ self.visit_trait_item(item);
+ }
}
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
fn visit_nested_impl_item(&mut self, id: ImplItemId) {
- let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id));
- walk_list!(self, visit_impl_item, opt_item);
+ if Self::NestedFilter::INTER {
+ let item = self.nested_visit_map().impl_item(id);
+ self.visit_impl_item(item);
+ }
}
/// Like `visit_nested_item()`, but for foreign items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
fn visit_nested_foreign_item(&mut self, id: ForeignItemId) {
- let opt_item = self.nested_visit_map().inter().map(|map| map.foreign_item(id));
- walk_list!(self, visit_foreign_item, opt_item);
+ if Self::NestedFilter::INTER {
+ let item = self.nested_visit_map().foreign_item(id);
+ self.visit_foreign_item(item);
+ }
}
/// Invoked to visit the body of a function, method or closure. Like
@@ -323,8 +295,10 @@
/// `nested_visit_map` to return other than `None`, in which case it will walk
/// the body.
fn visit_nested_body(&mut self, id: BodyId) {
- let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
- walk_list!(self, visit_body, opt_body);
+ if Self::NestedFilter::INTRA {
+ let body = self.nested_visit_map().body(id);
+ self.visit_body(body);
+ }
}
fn visit_param(&mut self, param: &'v Param<'v>) {
@@ -827,12 +801,11 @@
visitor.visit_ident(type_binding.ident);
visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
match type_binding.kind {
- TypeBindingKind::Equality { ref ty } => {
- visitor.visit_ty(ty);
- }
- TypeBindingKind::Constraint { bounds } => {
- walk_list!(visitor, visit_param_bound, bounds);
- }
+ TypeBindingKind::Equality { ref term } => match term {
+ Term::Ty(ref ty) => visitor.visit_ty(ty),
+ Term::Const(ref c) => visitor.visit_anon_const(c),
+ },
+ TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
}
}
@@ -1047,12 +1020,10 @@
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let ImplItem { def_id: _, ident, ref vis, ref defaultness, ref generics, ref kind, span: _ } =
- *impl_item;
+ let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span: _ } = *impl_item;
visitor.visit_ident(ident);
visitor.visit_vis(vis);
- visitor.visit_defaultness(defaultness);
visitor.visit_generics(generics);
match *kind {
ImplItemKind::Const(ref ty, body) => {
@@ -1088,7 +1059,8 @@
pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let ImplItemRef { id, ident, ref kind, span: _, ref defaultness } = *impl_item_ref;
+ let ImplItemRef { id, ident, ref kind, span: _, ref defaultness, trait_item_def_id: _ } =
+ *impl_item_ref;
visitor.visit_nested_impl_item(id);
visitor.visit_ident(ident);
visitor.visit_associated_item_kind(kind);
@@ -1175,7 +1147,7 @@
visitor.visit_expr(callee_expression);
walk_list!(visitor, visit_expr, arguments);
}
- ExprKind::MethodCall(ref segment, _, arguments, _) => {
+ ExprKind::MethodCall(ref segment, arguments, _) => {
visitor.visit_path_segment(expression.span, segment);
walk_list!(visitor, visit_expr, arguments);
}
@@ -1251,10 +1223,6 @@
ExprKind::InlineAsm(ref asm) => {
walk_inline_asm(visitor, asm);
}
- ExprKind::LlvmInlineAsm(ref asm) => {
- walk_list!(visitor, visit_expr, asm.outputs_exprs);
- walk_list!(visitor, visit_expr, asm.inputs_exprs);
- }
ExprKind::Yield(ref subexpression, _) => {
visitor.visit_expr(subexpression);
}
diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs
index 0db562f..db70002 100644
--- a/compiler/rustc_hir/src/itemlikevisit.rs
+++ b/compiler/rustc_hir/src/itemlikevisit.rs
@@ -8,7 +8,7 @@
///
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
/// - Example: find all items with a `#[foo]` attribute on them.
-/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().krate().visit_all_item_likes()`.
+/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`.
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
/// - Con: Don't get information about nesting
/// - Con: Don't have methods for specific bits of HIR, like "on
@@ -19,9 +19,9 @@
/// - Example: Examine each expression to look for its type and do some check or other.
/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
/// to return `NestedVisitorMap::OnlyBodies` and use
-/// `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within
-/// your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget
-/// to invoke `intravisit::walk_expr()` to keep walking the subparts).
+/// `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
+/// `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
+/// `intravisit::walk_expr()` to keep walking the subparts).
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
/// - Pro: Integrates well into dependency tracking.
/// - Con: Don't get information about nesting between items
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index add8bd1..b299e71 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -21,9 +21,10 @@
pub enum LangItemGroup {
Op,
+ Fn,
}
-const NUM_GROUPS: usize = 1;
+const NUM_GROUPS: usize = 2;
macro_rules! expand_group {
() => {
@@ -98,11 +99,12 @@
/// Construct an empty collection of lang items and no missing ones.
pub fn new() -> Self {
fn init_none(_: LangItem) -> Option<DefId> { None }
+ const EMPTY: Vec<DefId> = Vec::new();
Self {
items: vec![$(init_none(LangItem::$variant)),*],
missing: Vec::new(),
- groups: [vec![]; NUM_GROUPS],
+ groups: [EMPTY; NUM_GROUPS],
}
}
@@ -151,20 +153,12 @@
/// Extracts the first `lang = "$name"` out of a list of attributes.
/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
/// are also extracted out when found.
-///
-/// About the `check_name` argument: passing in a `Session` would be simpler,
-/// because then we could call `Session::check_name` directly. But we want to
-/// avoid the need for `rustc_hir` to depend on `rustc_session`, so we
-/// use a closure instead.
-pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
-where
- F: Fn(&'a ast::Attribute, Symbol) -> bool,
-{
+pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| {
Some(match attr {
- _ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
- _ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
- _ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
+ _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
+ _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
+ _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span),
_ => return None,
})
})
@@ -259,9 +253,9 @@
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, 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);
+ Fn(Fn), kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnMut(Fn), sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnOnce(Fn), sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
@@ -272,8 +266,8 @@
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, GenericRequirement::Exact(1);
- PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
+ PartialEq(Op), sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
+ PartialOrd(Op), 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.
@@ -290,6 +284,7 @@
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;
+ PanicNoUnwind, sym::panic_no_unwind, panic_no_unwind, Target::Fn, GenericRequirement::Exact(0);
/// libstd panic entry point. Necessary for const eval to be able to catch it
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 1df9b5f..f1d62d0 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -2,6 +2,7 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+#![feature(associated_type_defaults)]
#![feature(const_btree_new)]
#![feature(crate_visibility_modifier)]
#![feature(once_cell)]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index a43c1f9..61f0344 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -164,13 +164,11 @@
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
- let ImplItem { def_id: _, ident, ref vis, defaultness, ref generics, ref kind, span } =
- *self;
+ let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span } = *self;
hcx.hash_hir_item_like(|hcx| {
ident.name.hash_stable(hcx, hasher);
vis.hash_stable(hcx, hasher);
- defaultness.hash_stable(hcx, hasher);
generics.hash_stable(hcx, hasher);
kind.hash_stable(hcx, hasher);
span.hash_stable(hcx, hasher);
@@ -208,8 +206,16 @@
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
// We ignore the `nodes` and `bodies` fields since these refer to information included in
// `hash` which is hashed in the collector and used for the crate hash.
- let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } =
- *self;
+ // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
+ // the body satisfies the condition of two nodes being different have different
+ // `hash_stable` results.
+ let OwnerNodes {
+ hash_including_bodies,
+ hash_without_bodies: _,
+ nodes: _,
+ bodies: _,
+ local_id_to_def_id: _,
+ } = *self;
hash_including_bodies.hash_stable(hcx, hasher);
}
}
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index 58c3065..7874820 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -18,13 +18,9 @@
map
});
-/// The `check_name` argument avoids the need for `rustc_hir` to depend on
-/// `rustc_session`.
-pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
-where
- F: Fn(&'a ast::Attribute, Symbol) -> bool
+pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
{
- lang_items::extract(check_name, attrs).and_then(|(name, _)| {
+ lang_items::extract(attrs).and_then(|(name, _)| {
$(if name == sym::$name {
Some(sym::$sym)
} else)* {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 4c9e2d7..8e45b63 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -6,7 +6,7 @@
use rustc_ast_pretty::pp::{self, Breaks};
use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir as hir;
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
@@ -139,7 +139,7 @@
}
}
-pub const INDENT_UNIT: usize = 4;
+pub const INDENT_UNIT: isize = 4;
/// Requires you to pass an input filename and reader so that
/// it can scan the input text for comments to copy forward.
@@ -170,7 +170,7 @@
ann: &'a dyn PpAnn,
) -> State<'a> {
State {
- s: pp::mk_printer(),
+ s: pp::Printer::new(),
comments: Some(Comments::new(sm, filename, input)),
attrs,
ann,
@@ -186,7 +186,7 @@
where
F: FnOnce(&mut State<'_>),
{
- let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann };
+ let mut printer = State { s: pp::Printer::new(), comments: None, attrs: &|_| &[], ann };
f(&mut printer);
printer.s.eof()
}
@@ -571,7 +571,7 @@
self.ann.nested(self, Nested::Body(body));
}
hir::ItemKind::Macro(ref macro_def) => {
- self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+ self.print_mac_def(macro_def, &item.ident, item.span, |state| {
state.print_visibility(&item.vis)
});
}
@@ -705,9 +705,7 @@
self.bclose(item.span);
}
hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
- self.head("");
- self.print_visibility(&item.vis);
- self.word_nbsp("trait");
+ self.head(visibility_qualified(&item.vis, "trait"));
self.print_ident(item.ident);
self.print_generic_params(&generics.params);
let mut real_bounds = Vec::with_capacity(bounds.len());
@@ -725,6 +723,8 @@
self.print_bounds("=", real_bounds);
self.print_where_clause(&generics.where_clause);
self.word(";");
+ self.end(); // end inner head-block
+ self.end(); // end outer head-block
}
}
self.ann.post(self, AnnNode::Item(item))
@@ -923,7 +923,6 @@
self.hardbreak_if_not_bol();
self.maybe_print_comment(ii.span.lo());
self.print_outer_attributes(self.attrs(ii.hir_id()));
- self.print_defaultness(ii.defaultness);
match ii.kind {
hir::ImplItemKind::Const(ref ty, expr) => {
@@ -1427,7 +1426,7 @@
hir::ExprKind::Call(ref func, ref args) => {
self.print_expr_call(&func, args);
}
- hir::ExprKind::MethodCall(ref segment, _, ref args, _) => {
+ hir::ExprKind::MethodCall(ref segment, ref args, _) => {
self.print_expr_method_call(segment, args);
}
hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
@@ -1581,67 +1580,6 @@
self.word("asm!");
self.print_inline_asm(asm);
}
- hir::ExprKind::LlvmInlineAsm(ref a) => {
- let i = &a.inner;
- self.word("llvm_asm!");
- self.popen();
- self.print_symbol(i.asm, i.asm_str_style);
- self.word_space(":");
-
- let mut out_idx = 0;
- self.commasep(Inconsistent, &i.outputs, |s, out| {
- let constraint = out.constraint.as_str();
- let mut ch = constraint.chars();
- match ch.next() {
- Some('=') if out.is_rw => {
- s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
- }
- _ => s.print_string(&constraint, ast::StrStyle::Cooked),
- }
- s.popen();
- s.print_expr(&a.outputs_exprs[out_idx]);
- s.pclose();
- out_idx += 1;
- });
- self.space();
- self.word_space(":");
-
- let mut in_idx = 0;
- self.commasep(Inconsistent, &i.inputs, |s, &co| {
- s.print_symbol(co, ast::StrStyle::Cooked);
- s.popen();
- s.print_expr(&a.inputs_exprs[in_idx]);
- s.pclose();
- in_idx += 1;
- });
- self.space();
- self.word_space(":");
-
- self.commasep(Inconsistent, &i.clobbers, |s, &co| {
- s.print_symbol(co, ast::StrStyle::Cooked);
- });
-
- let mut options = vec![];
- if i.volatile {
- options.push("volatile");
- }
- if i.alignstack {
- options.push("alignstack");
- }
- if i.dialect == ast::LlvmAsmDialect::Intel {
- options.push("intel");
- }
-
- if !options.is_empty() {
- self.space();
- self.word_space(":");
- self.commasep(Inconsistent, &options, |s, &co| {
- s.print_string(co, ast::StrStyle::Cooked);
- });
- }
-
- self.pclose();
- }
hir::ExprKind::Yield(ref expr, _) => {
self.word_space("yield");
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
@@ -1813,9 +1751,12 @@
self.print_generic_args(binding.gen_args, false, false);
self.space();
match generic_args.bindings[0].kind {
- hir::TypeBindingKind::Equality { ref ty } => {
+ hir::TypeBindingKind::Equality { ref term } => {
self.word_space("=");
- self.print_type(ty);
+ match term {
+ Term::Ty(ref ty) => self.print_type(ty),
+ Term::Const(ref c) => self.print_anon_const(c),
+ }
}
hir::TypeBindingKind::Constraint { bounds } => {
self.print_bounds(":", bounds);
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index dece752..d3c425a 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -9,7 +9,7 @@
[dependencies]
rustc_graphviz = { path = "../rustc_graphviz" }
tracing = "0.1"
-rand = "0.7"
+rand = "0.8.4"
rustc_middle = { path = "../rustc_middle" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 0d0d09b..60b48e9 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -39,11 +39,11 @@
use rustc_graphviz as dot;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::dep_graph::{
DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
@@ -173,10 +173,10 @@
}
impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index df64534..b4df3e1 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -5,6 +5,7 @@
#![feature(let_else)]
#![feature(nll)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 8879567..94c149d 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -28,7 +28,7 @@
use rustc_hir::Node as HirNode;
use rustc_hir::{ImplItemKind, ItemKind as HirItem, TraitItemKind};
use rustc_middle::dep_graph::{label_strs, DepNode, DepNodeExt};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
@@ -223,8 +223,7 @@
/// Return all DepNode labels that should be asserted for this item.
/// index=0 is the "name" used for error messages
fn auto_labels(&mut self, item_id: LocalDefId, attr: &Attribute) -> (&'static str, Labels) {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(item_id);
- let node = self.tcx.hir().get(hir_id);
+ let node = self.tcx.hir().get_by_def_id(item_id);
let (name, labels) = match node {
HirNode::Item(item) => {
match item.kind {
@@ -473,10 +472,10 @@
}
impl<'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_attribute(&mut self, _: hir::HirId, attr: &'tcx Attribute) {
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 392c5bd..68180a2 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -190,7 +190,7 @@
fn rustc_version(nightly_build: bool) -> String {
if nightly_build {
- if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+ if let Some(val) = env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
return val.to_string_lossy().into_owned();
}
}
diff --git a/compiler/rustc_incremental/src/persist/fs/tests.rs b/compiler/rustc_incremental/src/persist/fs/tests.rs
index 652ef6b..1847969 100644
--- a/compiler/rustc_incremental/src/persist/fs/tests.rs
+++ b/compiler/rustc_incremental/src/persist/fs/tests.rs
@@ -13,7 +13,7 @@
.keys()
.cloned()
.collect::<FxHashSet<PathBuf>>(),
- vec![PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"),]
+ [PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"),]
.into_iter()
.collect::<FxHashSet<PathBuf>>()
);
@@ -40,7 +40,7 @@
// Find newest
assert_eq!(
find_source_directory_in_iter(
- vec![
+ [
PathBuf::from("crate-dir/s-3234-0000-svh"),
PathBuf::from("crate-dir/s-2234-0000-svh"),
PathBuf::from("crate-dir/s-1234-0000-svh")
@@ -54,7 +54,7 @@
// Filter out "-working"
assert_eq!(
find_source_directory_in_iter(
- vec![
+ [
PathBuf::from("crate-dir/s-3234-0000-working"),
PathBuf::from("crate-dir/s-2234-0000-svh"),
PathBuf::from("crate-dir/s-1234-0000-svh")
@@ -66,12 +66,12 @@
);
// Handle empty
- assert_eq!(find_source_directory_in_iter(vec![].into_iter(), &already_visited), None);
+ assert_eq!(find_source_directory_in_iter([].into_iter(), &already_visited), None);
// Handle only working
assert_eq!(
find_source_directory_in_iter(
- vec![
+ [
PathBuf::from("crate-dir/s-3234-0000-working"),
PathBuf::from("crate-dir/s-2234-0000-working"),
PathBuf::from("crate-dir/s-1234-0000-working")
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index d563a6c..870c3f8 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -158,14 +158,7 @@
// Decode the list of work_products
let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
let work_products: Vec<SerializedWorkProduct> =
- Decodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
- let msg = format!(
- "Error decoding `work-products` from incremental \
- compilation session directory: {}",
- e
- );
- sess.fatal(&msg)
- });
+ Decodable::decode(&mut work_product_decoder);
for swp in work_products {
let mut all_files_exist = true;
@@ -203,8 +196,7 @@
LoadResult::Error { message } => LoadResult::Error { message },
LoadResult::Ok { data: (bytes, start_pos) } => {
let mut decoder = Decoder::new(&bytes, start_pos);
- let prev_commandline_args_hash = u64::decode(&mut decoder)
- .expect("Error reading commandline arg hash from cached dep-graph");
+ let prev_commandline_args_hash = u64::decode(&mut decoder);
if prev_commandline_args_hash != expected_hash {
if report_incremental_info {
@@ -220,8 +212,7 @@
return LoadResult::DataOutOfDate;
}
- let dep_graph = SerializedDepGraph::decode(&mut decoder)
- .expect("Error reading cached dep-graph");
+ let dep_graph = SerializedDepGraph::decode(&mut decoder);
LoadResult::Ok { data: (dep_graph, prev_work_products) }
}
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 5aa213c..7f376c5 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -852,11 +852,7 @@
Bound::Excluded(end) => end.index(),
Bound::Unbounded => self.domain_size() - 1,
};
- let len = if let Some(l) = end.checked_sub(start) {
- l
- } else {
- return;
- };
+ let Some(len) = end.checked_sub(start) else { return };
match self {
HybridBitSet::Sparse(sparse) if sparse.len() + len < SPARSE_MAX => {
// The set is sparse and has space for `elems`.
@@ -938,6 +934,12 @@
bit_set: BitSet<T>,
}
+impl<T: Idx> Default for GrowableBitSet<T> {
+ fn default() -> Self {
+ GrowableBitSet::new_empty()
+ }
+}
+
impl<T: Idx> GrowableBitSet<T> {
/// Ensure that the set can hold at least `min_domain_size` elements.
pub fn ensure(&mut self, min_domain_size: usize) {
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index 359b185..7919e40 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -9,7 +9,3 @@
pub mod bit_set;
pub mod interval;
pub mod vec;
-
-// FIXME(#56935): Work around ICEs during cross-compilation.
-#[allow(unused)]
-extern crate rustc_macros;
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index e3c6528..8b61530 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -395,8 +395,8 @@
(@serializable $type:ident) => (
impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for $type {
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- d.read_u32().map(Self::from_u32)
+ fn decode(d: &mut D) -> Self {
+ Self::from_u32(d.read_u32())
}
}
impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for $type {
@@ -527,8 +527,8 @@
}
impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> {
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- Decodable::decode(d).map(|v| IndexVec { raw: v, _marker: PhantomData })
+ fn decode(d: &mut D) -> Self {
+ IndexVec { raw: Decodable::decode(d), _marker: PhantomData }
}
}
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index cff848e..94991fd 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -51,6 +51,28 @@
) -> At<'a, 'tcx> {
At { infcx: self, cause, param_env }
}
+
+ /// Forks the inference context, creating a new inference context with the same inference
+ /// variables in the same state. This can be used to "branch off" many tests from the same
+ /// common state. Used in coherence.
+ pub fn fork(&self) -> Self {
+ Self {
+ tcx: self.tcx.clone(),
+ defining_use_anchor: self.defining_use_anchor.clone(),
+ in_progress_typeck_results: self.in_progress_typeck_results.clone(),
+ inner: self.inner.clone(),
+ skip_leak_check: self.skip_leak_check.clone(),
+ lexical_region_resolutions: self.lexical_region_resolutions.clone(),
+ selection_cache: self.selection_cache.clone(),
+ evaluation_cache: self.evaluation_cache.clone(),
+ reported_trait_errors: self.reported_trait_errors.clone(),
+ reported_closure_mismatch: self.reported_closure_mismatch.clone(),
+ tainted_by_errors_flag: self.tainted_by_errors_flag.clone(),
+ err_count_on_creation: self.err_count_on_creation,
+ in_snapshot: self.in_snapshot.clone(),
+ universe: self.universe.clone(),
+ }
+ }
}
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
@@ -258,7 +280,10 @@
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
}
@@ -274,7 +299,7 @@
}
}
-impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
+impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
@@ -282,7 +307,22 @@
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
+ }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
+ fn to_trace(
+ _: TyCtxt<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ a_is_expected: bool,
+ a: Self,
+ b: Self,
+ ) -> TypeTrace<'tcx> {
+ TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) }
}
}
@@ -328,7 +368,7 @@
let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
TypeTrace {
cause: cause.clone(),
- values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+ values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 6023973..5e67c8c 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -49,6 +49,31 @@
Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
}
+ /// Like [Self::canonicalize_query], but preserves distinct universes. For
+ /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
+ /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
+ /// in `U2`.
+ ///
+ /// This is used for Chalk integration.
+ pub fn canonicalize_query_preserving_universes<V>(
+ &self,
+ value: V,
+ query_state: &mut OriginalQueryValues<'tcx>,
+ ) -> Canonicalized<'tcx, V>
+ where
+ V: TypeFoldable<'tcx>,
+ {
+ self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
+
+ Canonicalizer::canonicalize(
+ value,
+ self,
+ self.tcx,
+ &CanonicalizeAllFreeRegionsPreservingUniverses,
+ query_state,
+ )
+ }
+
/// Canonicalizes a query *response* `V`. When we canonicalize a
/// query response, we only canonicalize unbound inference
/// variables, and we leave other free regions alone. So,
@@ -133,7 +158,7 @@
/// maximally general query. But if we are canonicalizing a *query
/// response*, then we don't typically replace free regions, as they
/// must have been introduced from other parts of the system.
-trait CanonicalizeRegionMode {
+trait CanonicalizeMode {
fn canonicalize_free_region<'tcx>(
&self,
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -141,17 +166,20 @@
) -> ty::Region<'tcx>;
fn any(&self) -> bool;
+
+ // Do we preserve universe of variables.
+ fn preserve_universes(&self) -> bool;
}
struct CanonicalizeQueryResponse;
-impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
+impl CanonicalizeMode for CanonicalizeQueryResponse {
fn canonicalize_free_region<'tcx>(
&self,
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
- match r {
+ match *r {
ty::ReFree(_)
| ty::ReErased
| ty::ReStatic
@@ -159,12 +187,12 @@
| ty::ReEarlyBound(..) => r,
ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
- CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) },
+ CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
r,
),
ty::ReVar(vid) => {
- let universe = canonicalizer.region_var_universe(*vid);
+ let universe = canonicalizer.region_var_universe(vid);
canonicalizer.canonical_var_for_region(
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
r,
@@ -198,17 +226,21 @@
fn any(&self) -> bool {
false
}
+
+ fn preserve_universes(&self) -> bool {
+ true
+ }
}
struct CanonicalizeUserTypeAnnotation;
-impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
+impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
fn canonicalize_free_region<'tcx>(
&self,
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
- match r {
+ match *r {
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
_ => {
@@ -221,11 +253,15 @@
fn any(&self) -> bool {
false
}
+
+ fn preserve_universes(&self) -> bool {
+ false
+ }
}
struct CanonicalizeAllFreeRegions;
-impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
+impl CanonicalizeMode for CanonicalizeAllFreeRegions {
fn canonicalize_free_region<'tcx>(
&self,
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -237,26 +273,54 @@
fn any(&self) -> bool {
true
}
+
+ fn preserve_universes(&self) -> bool {
+ false
+ }
}
-struct CanonicalizeFreeRegionsOtherThanStatic;
+struct CanonicalizeAllFreeRegionsPreservingUniverses;
-impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
+impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
fn canonicalize_free_region<'tcx>(
&self,
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
- if let ty::ReStatic = r {
- r
- } else {
- canonicalizer.canonical_var_for_region_in_root_universe(r)
- }
+ let universe = canonicalizer.infcx.universe_of_region(r);
+ canonicalizer.canonical_var_for_region(
+ CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
+ r,
+ )
}
fn any(&self) -> bool {
true
}
+
+ fn preserve_universes(&self) -> bool {
+ true
+ }
+}
+
+struct CanonicalizeFreeRegionsOtherThanStatic;
+
+impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
+ fn canonicalize_free_region<'tcx>(
+ &self,
+ canonicalizer: &mut Canonicalizer<'_, 'tcx>,
+ r: ty::Region<'tcx>,
+ ) -> ty::Region<'tcx> {
+ if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) }
+ }
+
+ fn any(&self) -> bool {
+ true
+ }
+
+ fn preserve_universes(&self) -> bool {
+ false
+ }
}
struct Canonicalizer<'cx, 'tcx> {
@@ -267,7 +331,7 @@
// Note that indices is only used once `var_values` is big enough to be
// heap-allocated.
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
- canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
+ canonicalize_mode: &'cx dyn CanonicalizeMode,
needs_canonical_flags: TypeFlags,
binder_index: ty::DebruijnIndex,
@@ -311,7 +375,7 @@
vid, r
);
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
- self.canonicalize_region_mode.canonicalize_free_region(self, r)
+ self.canonicalize_mode.canonicalize_free_region(self, r)
}
ty::ReStatic
@@ -319,7 +383,7 @@
| ty::ReFree(_)
| ty::ReEmpty(_)
| ty::RePlaceholder(..)
- | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
+ | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
}
}
@@ -337,8 +401,10 @@
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
// result.
Err(mut ui) => {
- // FIXME: perf problem described in #55921.
- ui = ty::UniverseIndex::ROOT;
+ if !self.canonicalize_mode.preserve_universes() {
+ // FIXME: perf problem described in #55921.
+ ui = ty::UniverseIndex::ROOT;
+ }
self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
@@ -409,8 +475,8 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- match ct.val {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ match ct.val() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
debug!("canonical: const var found with vid {:?}", vid);
match self.infcx.probe_const_var(vid) {
@@ -422,10 +488,12 @@
// `ConstVar(vid)` is unresolved, track its universe index in the
// canonicalized result
Err(mut ui) => {
- // FIXME: perf problem described in #55921.
- ui = ty::UniverseIndex::ROOT;
+ if !self.canonicalize_mode.preserve_universes() {
+ // FIXME: perf problem described in #55921.
+ ui = ty::UniverseIndex::ROOT;
+ }
return self.canonicalize_const_var(
- CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
+ CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) },
ct,
);
}
@@ -462,7 +530,7 @@
value: V,
infcx: &InferCtxt<'_, 'tcx>,
tcx: TyCtxt<'tcx>,
- canonicalize_region_mode: &dyn CanonicalizeRegionMode,
+ canonicalize_region_mode: &dyn CanonicalizeMode,
query_state: &mut OriginalQueryValues<'tcx>,
) -> Canonicalized<'tcx, V>
where
@@ -470,7 +538,7 @@
{
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::NEEDS_INFER |
- TypeFlags::HAS_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_POTENTIAL_FREE_REGIONS`
+ TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
} else {
@@ -493,7 +561,7 @@
let mut canonicalizer = Canonicalizer {
infcx,
tcx,
- canonicalize_region_mode,
+ canonicalize_mode: canonicalize_region_mode,
needs_canonical_flags,
variables: SmallVec::new(),
query_state,
@@ -504,10 +572,11 @@
// Once we have canonicalized `out_value`, it should not
// contain anything that ties it to this inference context
- // anymore, so it should live in the global arena.
- debug_assert!(!out_value.needs_infer());
+ // anymore.
+ debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
- let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
+ let canonical_variables =
+ tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
let max_universe = canonical_variables
.iter()
@@ -527,6 +596,19 @@
let var_values = &mut query_state.var_values;
+ let universe = info.universe();
+ if universe != ty::UniverseIndex::ROOT {
+ assert!(self.canonicalize_mode.preserve_universes());
+
+ // Insert universe into the universe map. To preserve the order of the
+ // universes in the value being canonicalized, we don't update the
+ // universe in `info` until we have finished canonicalizing.
+ match query_state.universe_map.binary_search(&universe) {
+ Err(idx) => query_state.universe_map.insert(idx, universe),
+ Ok(_) => {}
+ }
+ }
+
// This code is hot. `variables` and `var_values` are usually small
// (fewer than 8 elements ~95% of the time). They are SmallVec's to
// avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +651,61 @@
}
}
+ /// Replaces the universe indexes used in `var_values` with their index in
+ /// `query_state.universe_map`. This minimizes the maximum universe used in
+ /// the canonicalized value.
+ fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
+ if self.query_state.universe_map.len() == 1 {
+ return self.variables;
+ }
+
+ let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self
+ .query_state
+ .universe_map
+ .iter()
+ .enumerate()
+ .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
+ .collect();
+
+ self.variables
+ .iter()
+ .map(|v| CanonicalVarInfo {
+ kind: match v.kind {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+ return *v;
+ }
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
+ }
+ CanonicalVarKind::Region(u) => {
+ CanonicalVarKind::Region(reverse_universe_map[&u])
+ }
+ CanonicalVarKind::Const(u, t) => {
+ CanonicalVarKind::Const(reverse_universe_map[&u], t)
+ }
+ CanonicalVarKind::PlaceholderTy(placeholder) => {
+ CanonicalVarKind::PlaceholderTy(ty::Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ })
+ }
+ CanonicalVarKind::PlaceholderRegion(placeholder) => {
+ CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ })
+ }
+ CanonicalVarKind::PlaceholderConst(placeholder) => {
+ CanonicalVarKind::PlaceholderConst(ty::Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ })
+ }
+ },
+ })
+ .collect()
+ }
+
/// Shorthand helper that creates a canonical region variable for
/// `r` (always in the root universe). The reason that we always
/// put these variables into the root universe is because this
@@ -632,17 +769,17 @@
fn canonicalize_const_var(
&mut self,
info: CanonicalVarInfo<'tcx>,
- const_var: &'tcx ty::Const<'tcx>,
- ) -> &'tcx ty::Const<'tcx> {
+ const_var: ty::Const<'tcx>,
+ ) -> ty::Const<'tcx> {
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(const_var);
if bound_to != const_var {
self.fold_const(bound_to)
} else {
let var = self.canonical_var(info, const_var.into());
- self.tcx().mk_const(ty::Const {
+ self.tcx().mk_const(ty::ConstS {
val: ty::ConstKind::Bound(self.binder_index, var),
- ty: self.fold_ty(const_var.ty),
+ ty: self.fold_ty(const_var.ty()),
})
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 0c26639..7985686 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -137,12 +137,9 @@
self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
}
- CanonicalVarKind::Const(ui) => self
+ CanonicalVarKind::Const(ui, ty) => self
.next_const_var_in_universe(
- self.next_ty_var_in_universe(
- TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span },
- universe_map(ui),
- ),
+ ty,
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
universe_map(ui),
)
@@ -152,7 +149,7 @@
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
self.tcx
- .mk_const(ty::Const {
+ .mk_const(ty::ConstS {
val: ty::ConstKind::Placeholder(placeholder_mapped),
ty: name.ty,
})
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 5b4a9d9..48d5c21 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -237,10 +237,9 @@
v.var_values[BoundVar::new(index)]
});
match (original_value.unpack(), result_value.unpack()) {
- (
- GenericArgKind::Lifetime(ty::ReErased),
- GenericArgKind::Lifetime(ty::ReErased),
- ) => {
+ (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
+ if re1.is_erased() && re2.is_erased() =>
+ {
// No action needed.
}
@@ -429,7 +428,7 @@
}
GenericArgKind::Lifetime(result_value) => {
// e.g., here `result_value` might be `'?1` in the example above...
- if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value {
+ if let ty::ReLateBound(debruijn, br) = *result_value {
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
// We only allow a `ty::INNERMOST` index in substitutions.
@@ -438,12 +437,12 @@
}
}
GenericArgKind::Const(result_value) => {
- if let ty::Const { val: ty::ConstKind::Bound(debrujin, b), .. } = result_value {
+ if let ty::ConstKind::Bound(debrujin, b) = result_value.val() {
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
// We only allow a `ty::INNERMOST` index in substitutions.
- assert_eq!(*debrujin, ty::INNERMOST);
- opt_values[*b] = Some(*original_value);
+ assert_eq!(debrujin, ty::INNERMOST);
+ opt_values[b] = Some(*original_value);
}
}
}
@@ -558,10 +557,9 @@
obligations
.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
}
- (
- GenericArgKind::Lifetime(ty::ReErased),
- GenericArgKind::Lifetime(ty::ReErased),
- ) => {
+ (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
+ if re1.is_erased() && re2.is_erased() =>
+ {
// no action needed
}
(GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
@@ -672,7 +670,7 @@
});
}
- fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
+ fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {
span_bug!(
self.cause.span(self.infcx.tcx),
"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 da71edb..e1b5d04 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -123,14 +123,12 @@
pub fn super_combine_consts<R>(
&self,
relation: &mut R,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>>
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);
@@ -141,7 +139,7 @@
let a_is_expected = relation.a_is_expected();
- match (a.val, b.val) {
+ match (a.val(), b.val()) {
(
ty::ConstKind::Infer(InferConst::Var(a_vid)),
ty::ConstKind::Infer(InferConst::Var(b_vid)),
@@ -228,9 +226,9 @@
&self,
param_env: ty::ParamEnv<'tcx>,
target_vid: ty::ConstVid<'tcx>,
- ct: &'tcx ty::Const<'tcx>,
+ ct: ty::Const<'tcx>,
vid_is_expected: bool,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
let (for_universe, span) = {
let mut inner = self.inner.borrow_mut();
let variable_table = &mut inner.const_unification_table();
@@ -453,8 +451,8 @@
pub fn add_const_equate_obligation(
&mut self,
a_is_expected: bool,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
) {
let predicate = if a_is_expected {
ty::PredicateKind::ConstEquate(a, b)
@@ -718,12 +716,12 @@
fn consts(
&mut self,
- c: &'tcx ty::Const<'tcx>,
- c2: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ c: ty::Const<'tcx>,
+ c2: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
- match c.val {
+ match c.val() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
let mut inner = self.infcx.inner.borrow_mut();
let variable_table = &mut inner.const_unification_table();
@@ -741,23 +739,24 @@
origin: var_value.origin,
val: ConstVariableValue::Unknown { universe: self.for_universe },
});
- Ok(self.tcx().mk_const_var(new_var_id, c.ty))
+ Ok(self.tcx().mk_const_var(new_var_id, c.ty()))
}
}
}
}
- ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
- assert_eq!(uv.promoted, None);
- let substs = uv.substs(self.tcx());
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+ if self.tcx().lazy_normalization() =>
+ {
+ assert_eq!(promoted, None);
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
substs,
substs,
)?;
- Ok(self.tcx().mk_const(ty::Const {
- ty: c.ty,
- val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
+ Ok(self.tcx().mk_const(ty::ConstS {
+ ty: c.ty(),
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
}))
}
_ => relate::super_relate_consts(self, c, c),
@@ -769,7 +768,7 @@
/// Register an obligation that both constants must be equal to each other.
///
/// If they aren't equal then the relation doesn't hold.
- fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
+ fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
}
pub trait RelateResultCompare<'tcx, T> {
@@ -789,7 +788,7 @@
pub fn const_unification_error<'tcx>(
a_is_expected: bool,
- (a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>),
+ (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
) -> TypeError<'tcx> {
TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b))
}
@@ -916,7 +915,7 @@
debug_assert_eq!(r, _r);
debug!("ConstInferUnifier: r={:?}", r);
- match r {
+ match *r {
// Never make variables for regions bound within the type itself,
// nor for erased regions.
ty::ReLateBound(..) | ty::ReErased => {
@@ -946,13 +945,13 @@
#[tracing::instrument(level = "debug", skip(self))]
fn consts(
&mut self,
- c: &'tcx ty::Const<'tcx>,
- _c: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ c: ty::Const<'tcx>,
+ _c: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
debug_assert_eq!(c, _c);
debug!("ConstInferUnifier: c={:?}", c);
- match c.val {
+ match c.val() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
// Check if the current unification would end up
// unifying `target_vid` with a const which contains
@@ -986,23 +985,24 @@
},
},
);
- Ok(self.tcx().mk_const_var(new_var_id, c.ty))
+ Ok(self.tcx().mk_const_var(new_var_id, c.ty()))
}
}
}
}
- ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
- assert_eq!(uv.promoted, None);
- let substs = uv.substs(self.tcx());
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+ if self.tcx().lazy_normalization() =>
+ {
+ assert_eq!(promoted, None);
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
substs,
substs,
)?;
- Ok(self.tcx().mk_const(ty::Const {
- ty: c.ty,
- val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
+ Ok(self.tcx().mk_const(ty::ConstS {
+ ty: c.ty(),
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
}))
}
_ => 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 90c0ff9..5ac9ad68 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -117,9 +117,9 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
@@ -143,7 +143,7 @@
}
impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
- fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+ fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index f0c73d0..d900379 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -65,11 +65,11 @@
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
+ error::TypeError,
subst::{GenericArgKind, Subst, SubstsRef},
- Region, Ty, TyCtxt, TypeFoldable,
+ Binder, Region, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
use rustc_target::spec::abi;
@@ -151,11 +151,10 @@
) -> (String, Span) {
let sm = tcx.sess.source_map();
- let scope = region.free_region_binding_scope(tcx);
- let node = tcx.hir().local_def_id_to_hir_id(scope.expect_local());
+ let scope = region.free_region_binding_scope(tcx).expect_local();
match *region {
ty::ReEarlyBound(ref br) => {
- let mut sp = sm.guess_head_span(tcx.hir().span(node));
+ let mut sp = sm.guess_head_span(tcx.def_span(scope));
if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
{
@@ -166,7 +165,7 @@
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
}) => {
- let mut sp = sm.guess_head_span(tcx.hir().span(node));
+ let mut sp = sm.guess_head_span(tcx.def_span(scope));
if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
{
@@ -181,13 +180,13 @@
} else {
(
format!("the anonymous lifetime #{} defined here", idx + 1),
- tcx.hir().span(node),
+ tcx.def_span(scope),
)
}
}
_ => (
format!("the lifetime `{}` as defined here", region),
- sm.guess_head_span(tcx.hir().span(node)),
+ sm.guess_head_span(tcx.def_span(scope)),
),
},
_ => bug!(),
@@ -240,7 +239,7 @@
);
// Explain the region we are capturing.
- match hidden_region {
+ match *hidden_region {
ty::ReEmpty(ty::UniverseIndex::ROOT) => {
// All lifetimes shorter than the function body are `empty` in
// lexical region resolution. The default explanation of "an empty
@@ -516,7 +515,7 @@
Err(NonTrivialPath)
}
- fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
Err(NonTrivialPath)
}
@@ -771,7 +770,7 @@
self.suggest_boxing_for_return_impl_trait(
err,
ret_sp,
- vec![then, else_sp].into_iter(),
+ [then, else_sp].into_iter(),
);
}
}
@@ -807,11 +806,8 @@
);
let sugg = arm_spans
.flat_map(|sp| {
- vec![
- (sp.shrink_to_lo(), "Box::new(".to_string()),
- (sp.shrink_to_hi(), ")".to_string()),
- ]
- .into_iter()
+ [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
+ .into_iter()
})
.collect::<Vec<_>>();
err.multipart_suggestion(
@@ -919,13 +915,13 @@
) -> Option<()> {
for (i, ta) in sub.types().enumerate() {
if ta == other_ty {
- self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
+ self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
return Some(());
}
if let ty::Adt(def, _) = ta.kind() {
let path_ = self.tcx.def_path_str(def.did);
if path_ == other_path {
- self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
+ self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
return Some(());
}
}
@@ -1040,7 +1036,7 @@
let len2 = sig2.inputs().len();
if len1 == len2 {
for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
- let (x1, x2) = self.cmp(l, r);
+ let (x1, x2) = self.cmp(*l, *r);
(values.0).0.extend(x1.0);
(values.1).0.extend(x2.0);
self.push_comma(&mut values.0, &mut values.1, len1, i);
@@ -1118,7 +1114,7 @@
}
fn push_ty_ref<'tcx>(
- region: &ty::Region<'tcx>,
+ region: ty::Region<'tcx>,
ty: Ty<'tcx>,
mutbl: hir::Mutability,
s: &mut DiagnosticStyledString,
@@ -1267,7 +1263,7 @@
path1.clone(),
sub_no_defaults_1,
path2.clone(),
- &t2,
+ t2,
)
.is_some()
{
@@ -1285,7 +1281,7 @@
path2,
sub_no_defaults_2,
path1,
- &t1,
+ t1,
)
.is_some()
{
@@ -1337,26 +1333,26 @@
}
// When finding T != &T, highlight only the borrow
- (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => {
+ (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(ref_ty1, t2) => {
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
- push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
+ push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
values.1.push_normal(t2.to_string());
values
}
- (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => {
+ (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(t1, ref_ty2) => {
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
values.0.push_normal(t1.to_string());
- push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
+ push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
values
}
// When encountering &T != &mut T, highlight only the borrow
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
- if equals(&ref_ty1, &ref_ty2) =>
+ if equals(ref_ty1, ref_ty2) =>
{
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
- push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
- push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
+ push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
+ push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
values
}
@@ -1553,10 +1549,6 @@
}
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);
@@ -1590,18 +1582,18 @@
None => (None, Mismatch::Fixed("type"), false),
Some(values) => {
let (is_simple_error, exp_found) = match values {
- ValuePairs::Types(exp_found) => {
- let is_simple_err =
- exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
- OpaqueTypesVisitor::visit_expected_found(
- self.tcx,
- exp_found.expected,
- exp_found.found,
- span,
- )
- .report(diag);
+ ValuePairs::Terms(infer::ExpectedFound {
+ expected: ty::Term::Ty(expected),
+ found: ty::Term::Ty(found),
+ }) => {
+ let is_simple_err = expected.is_simple_text() && found.is_simple_text();
+ OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+ .report(diag);
- (is_simple_err, Mismatch::Variable(exp_found))
+ (
+ is_simple_err,
+ Mismatch::Variable(infer::ExpectedFound { expected, found }),
+ )
}
ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
_ => (false, Mismatch::Fixed("type")),
@@ -1632,7 +1624,7 @@
};
if let Some((sp, msg)) = secondary_span {
if swap_secondary_and_primary {
- let terr = if let Some(infer::ValuePairs::Types(infer::ExpectedFound {
+ let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound {
expected,
..
})) = values
@@ -1762,8 +1754,7 @@
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values {
if let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() {
if let Some(def_id) = def_id.as_local() {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let span = self.tcx.hir().span(hir_id);
+ let span = self.tcx.def_span(def_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
}
}
@@ -1774,7 +1765,7 @@
self.note_error_origin(diag, cause, exp_found, terr);
}
- pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
if let ty::Opaque(def_id, substs) = ty.kind() {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
// Future::Output
@@ -1784,13 +1775,20 @@
for (predicate, _) in bounds {
let predicate = predicate.subst(self.tcx, substs);
- if let ty::PredicateKind::Projection(projection_predicate) =
- predicate.kind().skip_binder()
- {
- if projection_predicate.projection_ty.item_def_id == item_def_id {
- // We don't account for multiple `Future::Output = Ty` contraints.
- return Some(projection_predicate.ty);
- }
+ let output = predicate
+ .kind()
+ .map_bound(|kind| match kind {
+ ty::PredicateKind::Projection(projection_predicate)
+ if projection_predicate.projection_ty.item_def_id == item_def_id =>
+ {
+ projection_predicate.term.ty()
+ }
+ _ => None,
+ })
+ .transpose();
+ if output.is_some() {
+ // We don't account for multiple `Future::Output = Ty` contraints.
+ return output;
}
}
}
@@ -1832,8 +1830,8 @@
}
match (
- self.get_impl_future_output_ty(exp_found.expected),
- self.get_impl_future_output_ty(exp_found.found),
+ self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder),
+ self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder),
) {
(Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() {
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
@@ -1924,8 +1922,8 @@
.fields
.iter()
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
- .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
- .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
+ .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
+ .find(|(_, ty)| same_type_modulo_infer(*ty, exp_found.found))
{
if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -2038,27 +2036,14 @@
}
FailureCode::Error0308(failure_str) => {
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
- if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
- trace.values
- {
+ if let Some((expected, found)) = trace.values.ty() {
match (expected.kind(), found.kind()) {
(ty::Tuple(_), ty::Tuple(_)) => {}
// If a tuple of length one was expected and the found expression has
// parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100)
- (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
- if let Some(code) =
- code.strip_prefix('(').and_then(|s| s.strip_suffix(')'))
- {
- err.span_suggestion(
- span,
- "use a trailing comma to create a tuple with one element",
- format!("({},)", code),
- Applicability::MaybeIncorrect,
- );
- }
- }
+ (ty::Tuple(_), _) => {
+ self.emit_tuple_wrap_err(&mut err, span, found, expected)
}
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
@@ -2068,7 +2053,7 @@
if let Some(code) =
code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
{
- if code.chars().nth(1).is_none() {
+ if code.chars().count() == 1 {
err.span_suggestion(
span,
"if you meant to write a `char` literal, use single quotes",
@@ -2121,14 +2106,48 @@
diag
}
+ fn emit_tuple_wrap_err(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ span: Span,
+ found: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ ) {
+ let [expected_tup_elem] = &expected.tuple_fields().collect::<Vec<_>>()[..]
+ else { return };
+
+ if !same_type_modulo_infer(*expected_tup_elem, found) {
+ return;
+ }
+
+ let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ else { return };
+
+ let msg = "use a trailing comma to create a tuple with one element";
+ if code.starts_with('(') && code.ends_with(')') {
+ let before_close = span.hi() - BytePos::from_u32(1);
+ err.span_suggestion(
+ span.with_hi(before_close).shrink_to_hi(),
+ msg,
+ ",".into(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.multipart_suggestion(
+ msg,
+ vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())],
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
fn values_str(
&self,
values: ValuePairs<'tcx>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
match values {
- infer::Types(exp_found) => self.expected_found_str_ty(exp_found),
infer::Regions(exp_found) => self.expected_found_str(exp_found),
- infer::Consts(exp_found) => self.expected_found_str(exp_found),
+ infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
infer::TraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(),
@@ -2156,16 +2175,22 @@
}
}
- fn expected_found_str_ty(
+ fn expected_found_str_term(
&self,
- exp_found: ty::error::ExpectedFound<Ty<'tcx>>,
+ exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
}
- Some(self.cmp(exp_found.expected, exp_found.found))
+ Some(match (exp_found.expected, exp_found.found) {
+ (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
+ (expected, found) => (
+ DiagnosticStyledString::highlighted(expected.to_string()),
+ DiagnosticStyledString::highlighted(found.to_string()),
+ ),
+ })
}
/// Returns a string of the form "expected `{}`, found `{}`".
@@ -2201,7 +2226,7 @@
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
) -> DiagnosticBuilder<'a> {
- let hir = &self.tcx.hir();
+ let hir = self.tcx.hir();
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
let generics = self
@@ -2215,9 +2240,9 @@
if let Some(Node::Item(Item {
kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
..
- })) = hir.find(parent_id)
+ })) = hir.find_by_def_id(parent_id)
{
- Some(self.tcx.generics_of(hir.local_def_id(parent_id).to_def_id()))
+ Some(self.tcx.generics_of(parent_id))
} else {
None
},
@@ -2248,7 +2273,7 @@
if let Node::GenericParam(param) = hir.get(id) {
has_bounds = !param.bounds.is_empty();
}
- let sp = hir.span(id);
+ let sp = self.tcx.def_span(def_id);
// `sp` only covers `T`, change it so that it covers
// `T:` when appropriate
let is_impl_trait = bound_kind.to_string().starts_with("impl ");
@@ -2294,12 +2319,7 @@
.as_ref()
.and_then(|(_, g, _)| g.params.first())
.and_then(|param| param.def_id.as_local())
- .map(|def_id| {
- (
- hir.span(hir.local_def_id_to_hir_id(def_id)).shrink_to_lo(),
- format!("{}, ", new_lt),
- )
- });
+ .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt)));
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
@@ -2657,7 +2677,7 @@
infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br),
- self.tcx.associated_item(def_id).ident
+ self.tcx.associated_item(def_id).name
),
infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
infer::UpvarRegion(ref upvar_id, _) => {
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 9cf6cde..205ad04 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
@@ -4,15 +4,15 @@
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::kw;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use std::borrow::Cow;
struct FindHirNodeVisitor<'a, 'tcx> {
@@ -52,7 +52,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(self.infcx.tcx).any(|inner| {
+ ty.walk().any(|inner| {
inner == self.target
|| match (inner.unpack(), self.target.unpack()) {
(GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
@@ -83,10 +83,10 @@
}
impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.infcx.tcx.hir()
}
fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
@@ -121,8 +121,8 @@
}
}
}
- if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
- if call_span == self.target_span
+ if let ExprKind::MethodCall(segment, exprs, _) = expr.kind {
+ if segment.ident.span == self.target_span
&& Some(self.target)
== self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
typeck_results
@@ -369,7 +369,7 @@
pub fn extract_inference_diagnostics_data(
&self,
arg: GenericArg<'tcx>,
- highlight: Option<ty::print::RegionHighlightMode>,
+ highlight: Option<ty::print::RegionHighlightMode<'tcx>>,
) -> InferenceDiagnosticsData {
match arg.unpack() {
GenericArgKind::Type(ty) => {
@@ -409,7 +409,7 @@
}
}
GenericArgKind::Const(ct) => {
- match ct.val {
+ match ct.val() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
let origin = self
.inner
@@ -445,9 +445,7 @@
parent: None,
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated {
- substs_: Some(substs), ..
- }) => {
+ ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
assert!(substs.has_infer_types_or_consts());
// FIXME: We only use the first inference variable we encounter in
@@ -461,7 +459,7 @@
}
_ => {}
},
- GenericArgKind::Const(c) => match c.val {
+ GenericArgKind::Const(c) => match c.val() {
ty::ConstKind::Infer(InferConst::Var(_)) => {
return self.extract_inference_diagnostics_data(s, None);
}
@@ -499,16 +497,32 @@
let ty_to_string = |ty: Ty<'tcx>| -> String {
let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
- let mut inner = self.inner.borrow_mut();
- let ty_vars = inner.type_variables();
- let getter = move |ty_vid| {
- let var_origin = ty_vars.var_origin(ty_vid);
- if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
- return Some(name.to_string());
+ let ty_getter = move |ty_vid| {
+ if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
+ self.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
+ {
+ Some(name.to_string())
+ } else {
+ None
}
- None
};
- printer.name_resolver = Some(Box::new(&getter));
+ printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
+ let const_getter = move |ct_vid| {
+ if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = self
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .probe_value(ct_vid)
+ .origin
+ .kind
+ {
+ return Some(name.to_string());
+ } else {
+ None
+ }
+ };
+ printer.const_infer_name_resolver = Some(Box::new(const_getter));
+
let _ = if let ty::FnDef(..) = ty.kind() {
// We don't want the regular output for `fn`s because it includes its path in
// invalid pseudo-syntax, we want the `fn`-pointer output instead.
@@ -533,18 +547,18 @@
// 3 | let _ = x.sum() as f64;
// | ^^^ cannot infer type for `S`
span
- } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) =
+ } else if let Some(ExprKind::MethodCall(segment, ..)) =
local_visitor.found_method_call.map(|e| &e.kind)
{
// Point at the call instead of the whole expression:
// error[E0284]: type annotations needed
// --> file.rs:2:5
// |
- // 2 | vec![Ok(2)].into_iter().collect()?;
- // | ^^^^^^^ cannot infer type
+ // 2 | [Ok(2)].into_iter().collect()?;
+ // | ^^^^^^^ cannot infer type
// |
// = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
- if span.contains(*call_span) { *call_span } else { span }
+ if span.contains(segment.ident.span) { segment.ident.span } else { span }
} else {
span
};
@@ -555,8 +569,7 @@
let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
(_, Some(_)) => String::new(),
(Some(ty), _) if ty.is_closure() => {
- let substs =
- if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
+ let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
let fn_sig = substs.as_closure().sig();
let args = closure_args(&fn_sig);
let ret = fn_sig.output().skip_binder().to_string();
@@ -599,8 +612,7 @@
let param_type = arg_data.kind.descr();
let suffix = match local_visitor.found_node_ty {
Some(ty) if ty.is_closure() => {
- let substs =
- if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
+ let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
let fn_sig = substs.as_closure().sig();
let ret = fn_sig.output().skip_binder().to_string();
@@ -711,7 +723,7 @@
};
err.span_label(pattern.span, msg);
} else if let Some(e) = local_visitor.found_method_call {
- if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
+ if let ExprKind::MethodCall(segment, exprs, _) = &e.kind {
// Suggest impl candidates:
//
// error[E0283]: type annotations needed
@@ -937,9 +949,9 @@
}
/// Replace not yet inferred const params with their def name.
- fn replace_infers(&self, c: &'tcx Const<'tcx>, index: u32, name: Symbol) -> &'tcx Const<'tcx> {
- match c.val {
- ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty),
+ fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> {
+ match c.val() {
+ ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()),
_ => c,
}
}
@@ -964,7 +976,7 @@
.map(|(subst, param)| match &(subst.unpack(), ¶m.kind) {
(_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
(crate::infer::GenericArgKind::Const(c), _) => {
- self.replace_infers(c, param.index, param.name).into()
+ self.replace_infers(*c, param.index, param.name).into()
}
_ => subst.super_fold_with(self),
})
@@ -987,7 +999,7 @@
}
}
ty::Ref(_, ty, _) => {
- let ty = self.fold_ty(ty);
+ let ty = self.fold_ty(*ty);
match ty.kind() {
// Avoid `&_`, these can be safely presented as `_`.
ty::Error(_) => self.tcx().ty_error(),
@@ -1003,9 +1015,9 @@
| ty::Opaque(..)
| ty::Projection(_)
| ty::Never => t.super_fold_with(self),
- ty::Array(ty, c) => self
- .tcx()
- .mk_ty(ty::Array(self.fold_ty(ty), self.replace_infers(c, 0, Symbol::intern("N")))),
+ ty::Array(ty, c) => {
+ self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N)))
+ }
// We don't want to hide type params that haven't been resolved yet.
// This would be the type that will be written out with the type param
// name in the output.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index ac57796..4eec492 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -106,90 +106,47 @@
None => String::new(),
};
- let (span_1, span_2, main_label, span_label, future_return_type) =
- match (sup_is_ret_type, sub_is_ret_type) {
- (None, None) => {
- let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
- (
- "this type is declared with multiple lifetimes...".to_owned(),
- "...but data with one lifetime flows into the other here".to_owned(),
- )
- } else {
- (
- "these two types are declared with different lifetimes...".to_owned(),
- format!("...but data{} flows{} here", span_label_var1, span_label_var2),
- )
- };
- (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None)
- }
-
- (Some(ret_span), _) => {
- let sup_future = self.future_return_type(scope_def_id_sup);
- let (return_type, action) = if sup_future.is_some() {
- ("returned future", "held across an await point")
- } else {
- ("return type", "returned")
- };
-
- (
- ty_sub.span,
- ret_span,
- format!(
- "this parameter and the {} are declared with different lifetimes...",
- return_type
- ),
- format!("...but data{} is {} here", span_label_var1, action),
- sup_future,
- )
- }
- (_, Some(ret_span)) => {
- let sub_future = self.future_return_type(scope_def_id_sub);
- let (return_type, action) = if sub_future.is_some() {
- ("returned future", "held across an await point")
- } else {
- ("return type", "returned")
- };
-
- (
- ty_sup.span,
- ret_span,
- format!(
- "this parameter and the {} are declared with different lifetimes...",
- return_type
- ),
- format!("...but data{} is {} here", span_label_var1, action),
- sub_future,
- )
- }
- };
+ debug!(
+ "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
+ sub_is_ret_type, sup_is_ret_type
+ );
let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
- err.span_label(span_1, main_label);
- err.span_label(span_2, String::new());
- err.span_label(span, span_label);
+ match (sup_is_ret_type, sub_is_ret_type) {
+ (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
+ let param_span =
+ if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
+
+ err.span_label(
+ param_span,
+ "this parameter and the return type are declared with different lifetimes...",
+ );
+ err.span_label(ret_span, "");
+ err.span_label(span, format!("...but data{} is returned here", span_label_var1));
+ }
+
+ (None, None) => {
+ if ty_sup.hir_id == ty_sub.hir_id {
+ err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
+ err.span_label(ty_sub.span, "");
+ err.span_label(span, "...but data with one lifetime flows into the other here");
+ } else {
+ err.span_label(
+ ty_sup.span,
+ "these two types are declared with different lifetimes...",
+ );
+ err.span_label(ty_sub.span, "");
+ err.span_label(
+ span,
+ format!("...but data{} flows{} here", span_label_var1, span_label_var2),
+ );
+ }
+ }
+ }
self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
- if let Some(t) = future_return_type {
- let snip = self
- .tcx()
- .sess
- .source_map()
- .span_to_snippet(t.span)
- .ok()
- .and_then(|s| match (&t.kind, s.as_str()) {
- (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()),
- (_, "") => None,
- _ => Some(s),
- })
- .unwrap_or_else(|| "{unnamed_type}".to_string());
-
- err.span_label(
- t.span,
- &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
- );
- }
err.emit();
Some(ErrorReported)
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index 8902310..b153570 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -1,7 +1,7 @@
use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::Node;
+use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::{self, Region, TyCtxt};
@@ -24,25 +24,19 @@
tcx: TyCtxt<'tcx>,
region: Region<'tcx>,
br: &ty::BoundRegionKind,
-) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> {
+) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
if let Some(anon_reg) = tcx.is_suitable_region(region) {
let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
- let fndecl = match tcx.hir().get(hir_id) {
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
- | Node::TraitItem(&hir::TraitItem {
- kind: hir::TraitItemKind::Fn(ref m, ..), ..
- })
- | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => {
- &m.decl
- }
- _ => return None,
+ let Some(fn_sig) = tcx.hir().get(hir_id).fn_sig() else {
+ return None
};
- fndecl
+ fn_sig
+ .decl
.inputs
.iter()
.find_map(|arg| find_component_for_bound_region(tcx, arg, br))
- .map(|ty| (ty, &**fndecl))
+ .map(|ty| (ty, fn_sig))
} else {
None
}
@@ -84,10 +78,10 @@
}
impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
@@ -208,10 +202,10 @@
}
impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Map<'tcx>> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Map<'tcx> {
+ self.tcx.hir()
}
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
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 d3b47e3..ef4c9c2 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
@@ -10,7 +10,7 @@
use rustc_errors::{Applicability, ErrorReported};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::{self, TypeVisitor};
+use rustc_middle::ty::TypeVisitor;
use rustc_span::MultiSpan;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -22,7 +22,7 @@
RegionResolutionError::ConcreteFailure(origin, sub, sup) => (origin, sub, sup),
_ => return None,
};
- if *sub != ty::RegionKind::ReStatic {
+ if !sub.is_static() {
return None;
}
let cause = match origin {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index fd295b7..f44e6e0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -64,11 +64,11 @@
.or_else(|| self.try_report_mismatched_static_lifetime())
}
- pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
+ pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
- (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
+ (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)),
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
- Some((origin.span(), sub, sup))
+ Some((origin.span(), *sub, *sup))
}
(None, Some((span, sub, sup))) => Some((span, sub, sup)),
_ => None,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index eb1c80e..17ff5d4 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -48,7 +48,7 @@
// Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect,
// and can steer users down the wrong path.
- if *named == ty::ReStatic {
+ if named.is_static() {
return None;
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 7178bfa..7d82c60 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -3,13 +3,14 @@
use crate::infer::ValuePairs;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCause, ObligationCauseCode};
+use rustc_data_structures::intern::Interned;
use rustc_errors::DiagnosticBuilder;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
use std::fmt::{self, Write};
@@ -31,15 +32,15 @@
vid,
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
- sub_placeholder @ ty::RePlaceholder(_),
+ sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
_,
- sup_placeholder @ ty::RePlaceholder(_),
+ sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
_,
)) => self.try_report_trait_placeholder_mismatch(
- Some(self.tcx().mk_region(ty::ReVar(*vid))),
+ Some(self.tcx().mk_region(ReVar(*vid))),
cause,
- Some(sub_placeholder),
- Some(sup_placeholder),
+ Some(*sub_placeholder),
+ Some(*sup_placeholder),
values,
),
@@ -47,14 +48,14 @@
vid,
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
- sub_placeholder @ ty::RePlaceholder(_),
+ sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
_,
_,
_,
)) => self.try_report_trait_placeholder_mismatch(
- Some(self.tcx().mk_region(ty::ReVar(*vid))),
+ Some(self.tcx().mk_region(ReVar(*vid))),
cause,
- Some(sub_placeholder),
+ Some(*sub_placeholder),
None,
values,
),
@@ -65,10 +66,10 @@
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
_,
_,
- sup_placeholder @ ty::RePlaceholder(_),
+ sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
_,
)) => self.try_report_trait_placeholder_mismatch(
- Some(self.tcx().mk_region(ty::ReVar(*vid))),
+ Some(self.tcx().mk_region(ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
@@ -81,10 +82,10 @@
_,
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
- sup_placeholder @ ty::RePlaceholder(_),
+ sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
_,
)) => self.try_report_trait_placeholder_mismatch(
- Some(self.tcx().mk_region(ty::ReVar(*vid))),
+ Some(self.tcx().mk_region(ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
@@ -96,9 +97,9 @@
_,
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
- sup_placeholder @ ty::RePlaceholder(_),
+ sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
)) => self.try_report_trait_placeholder_mismatch(
- Some(self.tcx().mk_region(ty::ReVar(*vid))),
+ Some(self.tcx().mk_region(ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
@@ -107,8 +108,8 @@
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
- sub_region @ ty::RePlaceholder(_),
- sup_region @ ty::RePlaceholder(_),
+ sub_region @ Region(Interned(RePlaceholder(_), _)),
+ sup_region @ Region(Interned(RePlaceholder(_), _)),
)) => self.try_report_trait_placeholder_mismatch(
None,
cause,
@@ -119,12 +120,12 @@
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
- sub_region @ ty::RePlaceholder(_),
+ sub_region @ Region(Interned(RePlaceholder(_), _)),
sup_region,
)) => self.try_report_trait_placeholder_mismatch(
- (!sup_region.has_name()).then_some(sup_region),
+ (!sup_region.has_name()).then_some(*sup_region),
cause,
- Some(sub_region),
+ Some(*sub_region),
None,
values,
),
@@ -132,12 +133,12 @@
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sub_region,
- sup_region @ ty::RePlaceholder(_),
+ sup_region @ Region(Interned(RePlaceholder(_), _)),
)) => self.try_report_trait_placeholder_mismatch(
- (!sub_region.has_name()).then_some(sub_region),
+ (!sub_region.has_name()).then_some(*sub_region),
cause,
None,
- Some(sup_region),
+ Some(*sup_region),
values,
),
@@ -147,10 +148,10 @@
fn try_report_trait_placeholder_mismatch(
&self,
- vid: Option<ty::Region<'tcx>>,
+ vid: Option<Region<'tcx>>,
cause: &ObligationCause<'tcx>,
- sub_placeholder: Option<ty::Region<'tcx>>,
- sup_placeholder: Option<ty::Region<'tcx>>,
+ sub_placeholder: Option<Region<'tcx>>,
+ sup_placeholder: Option<Region<'tcx>>,
value_pairs: &ValuePairs<'tcx>,
) -> Option<DiagnosticBuilder<'tcx>> {
let (expected_substs, found_substs, trait_def_id) = match value_pairs {
@@ -193,10 +194,10 @@
#[instrument(level = "debug", skip(self))]
fn report_trait_placeholder_mismatch(
&self,
- vid: Option<ty::Region<'tcx>>,
+ vid: Option<Region<'tcx>>,
cause: &ObligationCause<'tcx>,
- sub_placeholder: Option<ty::Region<'tcx>>,
- sup_placeholder: Option<ty::Region<'tcx>>,
+ sub_placeholder: Option<Region<'tcx>>,
+ sup_placeholder: Option<Region<'tcx>>,
trait_def_id: DefId,
expected_substs: SubstsRef<'tcx>,
actual_substs: SubstsRef<'tcx>,
@@ -306,13 +307,13 @@
fn explain_actual_impl_that_was_found(
&self,
err: &mut DiagnosticBuilder<'_>,
- sub_placeholder: Option<ty::Region<'tcx>>,
- sup_placeholder: Option<ty::Region<'tcx>>,
+ sub_placeholder: Option<Region<'tcx>>,
+ sup_placeholder: Option<Region<'tcx>>,
has_sub: Option<usize>,
has_sup: Option<usize>,
expected_trait_ref: ty::TraitRef<'tcx>,
actual_trait_ref: ty::TraitRef<'tcx>,
- vid: Option<ty::Region<'tcx>>,
+ vid: Option<Region<'tcx>>,
expected_has_vid: Option<usize>,
actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool,
@@ -322,7 +323,7 @@
#[derive(Copy, Clone)]
struct Highlighted<'tcx, T> {
tcx: TyCtxt<'tcx>,
- highlight: RegionHighlightMode,
+ highlight: RegionHighlightMode<'tcx>,
value: T,
}
@@ -366,7 +367,7 @@
let highlight_trait_ref = |trait_ref| Highlighted {
tcx: self.tcx(),
- highlight: RegionHighlightMode::default(),
+ highlight: RegionHighlightMode::new(self.tcx()),
value: trait_ref,
};
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 b6dff2e..625fd86 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
@@ -7,11 +7,10 @@
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
use rustc_middle::ty::{
- self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
- TypeVisitor,
+ self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span};
@@ -33,25 +32,23 @@
sup_origin,
sup_r,
spans,
- ) if **sub_r == RegionKind::ReStatic => {
- (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
- }
+ ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans),
RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
sub_r,
sup_r,
- ) if **sub_r == RegionKind::ReStatic => {
+ ) if sub_r.is_static() => {
// This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
// This may have a closure and it would cause ICE
// through `find_param_with_region` (#78262).
- let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+ let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
if fn_returns.is_empty() {
return None;
}
- let param = self.find_param_with_region(sup_r, sub_r)?;
+ let param = self.find_param_with_region(*sup_r, *sub_r)?;
let lifetime = if sup_r.has_name() {
format!("lifetime `{}`", sup_r)
} else {
@@ -70,7 +67,7 @@
.map(|s| format!("`{}`", s))
.unwrap_or_else(|| "`fn` parameter".to_string()),
lifetime,
- ctxt.assoc_item.ident,
+ ctxt.assoc_item.name,
);
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
err.span_label(
@@ -101,11 +98,11 @@
"try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
var_origin, sub_origin, sub_r, sup_origin, sup_r
);
- let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+ let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
let sp = var_origin.span();
let return_sp = sub_origin.span();
- let param = self.find_param_with_region(sup_r, sub_r)?;
+ let param = self.find_param_with_region(*sup_r, *sub_r)?;
let (lifetime_name, lifetime) = if sup_r.has_name() {
(sup_r.to_string(), format!("lifetime `{}`", sup_r))
} else {
@@ -187,6 +184,7 @@
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
{
let parent_id = tcx.hir().get_parent_item(*hir_id);
+ let parent_id = tcx.hir().local_def_id_to_hir_id(parent_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
let mut span: MultiSpan = fn_decl.output.span().into();
let mut add_label = true;
@@ -230,7 +228,7 @@
// Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
// `'static` lifetime when called as a method on a binding: `bar.qux()`.
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
- override_error_code = Some(ctxt.assoc_item.ident);
+ override_error_code = Some(ctxt.assoc_item.name);
}
}
}
@@ -251,7 +249,7 @@
self.get_impl_ident_and_self_ty_from_trait(*item_def_id, &v.0)
{
if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) {
- override_error_code = Some(ident);
+ override_error_code = Some(ident.name);
}
}
}
@@ -425,7 +423,7 @@
let tcx = self.tcx();
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find(tcx.hir().get_parent_item(impl_item.hir_id())) {
+ match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
Some(Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
@@ -434,13 +432,13 @@
}
}
Some(Node::TraitItem(trait_item)) => {
- let parent_id = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find(parent_id) {
+ let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
+ match tcx.hir().find_by_def_id(trait_did) {
Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
// The method being called is defined in the `trait`, but the `'static`
// obligation comes from the `impl`. Find that `impl` so that we can point
// at it in the suggestion.
- let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();
+ let trait_did = trait_did.to_def_id();
match tcx
.hir()
.trait_impls(trait_did)
@@ -557,15 +555,9 @@
pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
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) => {
+ ty::Dynamic(preds, re) if re.is_static() => {
if let Some(def_id) = preds.principal_def_id() {
self.0.insert(def_id);
}
@@ -580,12 +572,6 @@
pub(super) struct HirTraitObjectVisitor<'a>(pub(super) &'a mut Vec<Span>, pub(super) DefId);
impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
- type Map = ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
if let TyKind::TraitObject(
poly_trait_refs,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index f5fb82d..9216fa3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -2,13 +2,14 @@
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
+use crate::infer::{SubregionOrigin, Subtype};
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
@@ -33,16 +34,16 @@
{
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
if let (
- ValuePairs::Types(sub_expected_found),
- ValuePairs::Types(sup_expected_found),
+ sub_expected_found @ Some((sub_expected, sub_found)),
+ sup_expected_found @ Some(_),
CompareImplMethodObligation { trait_item_def_id, .. },
- ) = (&sub_trace.values, &sup_trace.values, sub_trace.cause.code())
+ ) = (&sub_trace.values.ty(), &sup_trace.values.ty(), sub_trace.cause.code())
{
if sup_expected_found == sub_expected_found {
self.emit_err(
var_origin.span(),
- sub_expected_found.expected,
- sub_expected_found.found,
+ *sub_expected,
+ *sub_found,
*trait_item_def_id,
);
return Some(ErrorReported);
@@ -81,25 +82,20 @@
// Mark all unnamed regions in the type with a number.
// This diagnostic is called in response to lifetime errors, so be informative.
struct HighlightBuilder<'tcx> {
- highlight: RegionHighlightMode,
- tcx: TyCtxt<'tcx>,
+ highlight: RegionHighlightMode<'tcx>,
counter: usize,
}
impl<'tcx> HighlightBuilder<'tcx> {
- fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+ fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
let mut builder =
- HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+ HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
builder.visit_ty(ty);
builder.highlight
}
}
impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
- 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> {
if !r.has_name() && self.counter <= 3 {
self.highlight.highlighting_region(r, self.counter);
@@ -187,10 +183,10 @@
}
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
- type Map = rustc_middle::hir::map::Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
@@ -207,7 +203,8 @@
.map(|res| {
matches!(
res,
- Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)
+ Res::SelfTy { trait_: _, alias_to: _ }
+ | Res::Def(hir::def::DefKind::TyParam, _)
)
})
.unwrap_or(false) =>
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 04eceec..719f6b3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -4,7 +4,7 @@
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, DefIdTree, Region, Ty};
+use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
use rustc_span::Span;
/// Information about the anonymous region we are searching for.
@@ -70,7 +70,7 @@
let ty = fn_sig.inputs()[index];
let mut found_anon_region = false;
let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
- if *r == *anon_region {
+ if r == anon_region {
found_anon_region = true;
replace_region
} else {
@@ -94,80 +94,42 @@
})
}
- pub(super) fn future_return_type(
- &self,
- local_def_id: LocalDefId,
- ) -> Option<&rustc_hir::Ty<'_>> {
- if let Some(hir::IsAsync::Async) = self.asyncness(local_def_id) {
- if let rustc_middle::ty::Opaque(def_id, _) =
- self.tcx().type_of(local_def_id).fn_sig(self.tcx()).output().skip_binder().kind()
- {
- match self.tcx().hir().get_if_local(*def_id) {
- Some(hir::Node::Item(hir::Item {
- kind:
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- bounds,
- origin: hir::OpaqueTyOrigin::AsyncFn(..),
- ..
- }),
- ..
- })) => {
- for b in bounds.iter() {
- if let hir::GenericBound::LangItemTrait(
- hir::LangItem::Future,
- _span,
- _hir_id,
- generic_args,
- ) = b
- {
- for type_binding in generic_args.bindings.iter() {
- if type_binding.ident.name == rustc_span::sym::Output {
- if let hir::TypeBindingKind::Equality { ty } =
- type_binding.kind
- {
- return Some(ty);
- }
- }
- }
- }
- }
- }
- _ => {}
- }
- }
- }
- None
- }
-
- pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option<hir::IsAsync> {
- // similar to the asyncness fn in rustc_ty_utils::ty
- let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id);
- let node = self.tcx().hir().get(hir_id);
- let fn_kind = node.fn_kind()?;
- Some(fn_kind.asyncness())
- }
-
// Here, we check for the case where the anonymous region
- // is in the return type.
+ // is in the return type as written by the user.
// FIXME(#42703) - Need to handle certain cases here.
pub(super) fn is_return_type_anon(
&self,
scope_def_id: LocalDefId,
br: ty::BoundRegionKind,
- decl: &hir::FnDecl<'_>,
+ hir_sig: &hir::FnSig<'_>,
) -> Option<Span> {
- let ret_ty = self.tcx().type_of(scope_def_id);
- if let ty::FnDef(_, _) = ret_ty.kind() {
- let sig = ret_ty.fn_sig(self.tcx());
- let late_bound_regions =
- self.tcx().collect_referenced_late_bound_regions(&sig.output());
- if late_bound_regions.iter().any(|r| *r == br) {
- return Some(decl.output.span());
- }
+ let fn_ty = self.tcx().type_of(scope_def_id);
+ if let ty::FnDef(_, _) = fn_ty.kind() {
+ let ret_ty = fn_ty.fn_sig(self.tcx()).output();
+ let span = hir_sig.decl.output.span();
+ let future_output = if hir_sig.header.is_async() {
+ ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
+ } else {
+ None
+ };
+ return match future_output {
+ Some(output) if self.includes_region(output, br) => Some(span),
+ None if self.includes_region(ret_ty, br) => Some(span),
+ _ => None,
+ };
}
None
}
+ fn includes_region(
+ &self,
+ ty: Binder<'tcx, impl TypeFoldable<'tcx>>,
+ region: ty::BoundRegionKind,
+ ) -> bool {
+ let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
+ late_bound_regions.iter().any(|r| *r == region)
+ }
+
// Here we check for the case where anonymous region
// corresponds to self and if yes, we display E0312.
// FIXME(#42700) - Need to format self properly to
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 82bd889..8671ecb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -102,6 +102,9 @@
"...so that the definition in impl matches the definition from the trait",
);
}
+ infer::CheckAssociatedTypeBounds { ref parent, .. } => {
+ self.note_region_origin(err, &parent);
+ }
}
}
@@ -115,7 +118,7 @@
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, &terr);
- match (sub, sup) {
+ match (*sub, *sup) {
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
(ty::RePlaceholder(_), _) => {
note_and_explain_region(
@@ -345,6 +348,55 @@
trait_item_def_id,
&format!("`{}: {}`", sup, sub),
),
+ infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
+ let mut err = self.report_concrete_failure(*parent, sub, sup);
+
+ let trait_item_span = self.tcx.def_span(trait_item_def_id);
+ let item_name = self.tcx.item_name(impl_item_def_id);
+ err.span_label(
+ trait_item_span,
+ format!("definition of `{}` from trait", item_name),
+ );
+
+ let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
+ let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
+
+ let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> =
+ impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
+ let clauses: Vec<_> = trait_predicates
+ .predicates
+ .into_iter()
+ .filter(|&(pred, _)| !impl_predicates.contains(pred))
+ .map(|(pred, _)| format!("{}", pred))
+ .collect();
+
+ if !clauses.is_empty() {
+ let where_clause_span = self
+ .tcx
+ .hir()
+ .get_generics(impl_item_def_id.expect_local())
+ .unwrap()
+ .where_clause
+ .tail_span_for_suggestion();
+
+ let suggestion = format!(
+ "{} {}",
+ if !impl_predicates.is_empty() { "," } else { " where" },
+ clauses.join(", "),
+ );
+ err.span_suggestion(
+ where_clause_span,
+ &format!(
+ "try copying {} from the trait",
+ if clauses.len() > 1 { "these clauses" } else { "this clause" }
+ ),
+ suggestion,
+ rustc_errors::Applicability::MaybeIncorrect,
+ );
+ }
+
+ err
+ }
}
}
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index e93cdf7..187c67d 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -41,8 +41,8 @@
}
impl<'tcx> FreeRegionMap<'tcx> {
- pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
- self.relation.elements()
+ pub fn elements(&self) -> impl Iterator<Item = Region<'tcx>> + '_ {
+ self.relation.elements().copied()
}
pub fn is_empty(&self) -> bool {
@@ -91,7 +91,7 @@
/// True for free regions other than `'static`.
pub fn is_free(&self, r: Region<'_>) -> bool {
- matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_))
+ matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_))
}
/// True if `r` is a free region or static of the sort that this
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index c40e409..e9d3b6a 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -46,7 +46,7 @@
ty_freshen_count: u32,
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
- const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>,
+ const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
keep_static: bool,
}
@@ -89,11 +89,11 @@
fn freshen_const<F>(
&mut self,
- opt_ct: Option<&'tcx ty::Const<'tcx>>,
+ opt_ct: Option<ty::Const<'tcx>>,
key: ty::InferConst<'tcx>,
freshener: F,
ty: Ty<'tcx>,
- ) -> &'tcx ty::Const<'tcx>
+ ) -> ty::Const<'tcx>
where
F: FnOnce(u32) -> ty::InferConst<'tcx>,
{
@@ -146,7 +146,7 @@
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
+ if !t.needs_infer() && !t.has_erasable_regions() {
return t;
}
@@ -221,8 +221,8 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- match ct.val {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ match ct.val() {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let opt_ct = self
.infcx
@@ -236,7 +236,7 @@
opt_ct,
ty::InferConst::Var(v),
ty::InferConst::Fresh,
- ct.ty,
+ ct.ty(),
);
}
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 773753a..c5c131a 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -230,14 +230,14 @@
r
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.val() {
if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = (vid.index - self.const_vars.0.start.index) as usize;
let origin = self.const_vars.1[idx];
- self.infcx.next_const_var(ty, origin)
+ self.infcx.next_const_var(ct.ty(), origin)
} else {
ct
}
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 862f5a5..3810973 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -78,9 +78,9 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
@@ -120,7 +120,7 @@
}
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
- fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+ fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index ae85e55..82454b8 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -94,7 +94,7 @@
};
let fld_c = |bound_var: ty::BoundVar, ty| {
- self.tcx.mk_const(ty::Const {
+ self.tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: next_universe,
name: ty::BoundConst { var: bound_var, ty },
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index a5ec84a..4e50585 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -13,6 +13,7 @@
use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
+use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -61,6 +62,7 @@
/// Contains the result of lexical region resolution. Offers methods
/// to lookup up the final value of a region variable.
+#[derive(Clone)]
pub struct LexicalRegionResolutions<'tcx> {
values: IndexVec<RegionVid, VarValue<'tcx>>,
error_region: ty::Region<'tcx>,
@@ -249,8 +251,8 @@
changes.push(b_vid);
}
if let Some(a_vid) = a_vid {
- match *b_data {
- VarValue::Value(ReStatic) | VarValue::ErrorValue => (),
+ match b_data {
+ VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (),
_ => {
constraints[a_vid].push((a_vid, b_vid));
constraints[b_vid].push((a_vid, b_vid));
@@ -269,7 +271,10 @@
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
- !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue)
+ !matches!(
+ b_data,
+ VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue
+ )
});
}
}
@@ -300,8 +305,8 @@
// check below for a common case, here purely as an
// optimization.
let b_universe = self.var_infos[b_vid].universe;
- if let ReEmpty(a_universe) = a_region {
- if *a_universe == b_universe {
+ if let ReEmpty(a_universe) = *a_region {
+ if a_universe == b_universe {
return false;
}
}
@@ -320,7 +325,7 @@
// tighter bound than `'static`.
//
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
- if let ty::RePlaceholder(p) = lub {
+ if let ty::RePlaceholder(p) = *lub {
if b_universe.cannot_name(p.universe) {
lub = self.tcx().lifetimes.re_static;
}
@@ -371,12 +376,12 @@
/// term "concrete regions").
#[instrument(level = "trace", skip(self))]
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
- let r = match (a, b) {
- (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
+ let r = match (*a, *b) {
+ (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => {
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
}
- (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
+ (ReVar(v_id), _) | (_, ReVar(v_id)) => {
span_bug!(
self.var_infos[v_id].origin.span(),
"lub_concrete_regions invoked with non-concrete \
@@ -386,27 +391,32 @@
);
}
- (&ReStatic, _) | (_, &ReStatic) => {
+ (ReStatic, _) | (_, ReStatic) => {
// nothing lives longer than `'static`
self.tcx().lifetimes.re_static
}
- (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_)))
- | (r @ (ReEarlyBound(_) | ReFree(_)), &ReEmpty(_)) => {
+ (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => {
// All empty regions are less than early-bound, free,
// and scope regions.
- r
+ b
}
- (&ReEmpty(a_ui), &ReEmpty(b_ui)) => {
+ (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => {
+ // All empty regions are less than early-bound, free,
+ // and scope regions.
+ a
+ }
+
+ (ReEmpty(a_ui), ReEmpty(b_ui)) => {
// Empty regions are ordered according to the universe
// they are associated with.
let ui = a_ui.min(b_ui);
self.tcx().mk_region(ReEmpty(ui))
}
- (&ReEmpty(empty_ui), &RePlaceholder(placeholder))
- | (&RePlaceholder(placeholder), &ReEmpty(empty_ui)) => {
+ (ReEmpty(empty_ui), RePlaceholder(placeholder))
+ | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => {
// If this empty region is from a universe that can
// name the placeholder, then the placeholder is
// larger; otherwise, the only ancestor is `'static`.
@@ -417,13 +427,13 @@
}
}
- (&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
+ (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => {
self.region_rels.lub_free_regions(a, b)
}
// For these types, we cannot define any additional
// relationship:
- (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => {
+ (RePlaceholder(..), _) | (_, RePlaceholder(..)) => {
if a == b {
a
} else {
@@ -675,7 +685,7 @@
let node_universe = self.var_infos[node_idx].universe;
for lower_bound in &lower_bounds {
- let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
+ let effective_lower_bound = if let ty::RePlaceholder(p) = *lower_bound.region {
if node_universe.cannot_name(p.universe) {
self.tcx().lifetimes.re_static
} else {
@@ -720,7 +730,7 @@
.expect("lower_vid_bounds should at least include `node_idx`");
for upper_bound in &upper_bounds {
- if let ty::RePlaceholder(p) = upper_bound.region {
+ if let ty::RePlaceholder(p) = *upper_bound.region {
if min_universe.cannot_name(p.universe) {
let origin = self.var_infos[node_idx].origin;
errors.push(RegionResolutionError::UpperBoundUniverseConflict(
@@ -854,11 +864,11 @@
}
VerifyBound::OutlivedBy(r) => {
- self.sub_concrete_regions(min, var_values.normalize(self.tcx(), r))
+ self.sub_concrete_regions(min, var_values.normalize(self.tcx(), *r))
}
VerifyBound::IsEmpty => {
- matches!(min, ty::ReEmpty(_))
+ matches!(*min, ty::ReEmpty(_))
}
VerifyBound::AnyBound(bs) => {
@@ -883,8 +893,8 @@
where
T: TypeFoldable<'tcx>,
{
- tcx.fold_regions(value, &mut false, |r, _db| match r {
- ty::ReVar(rid) => self.resolve_var(*rid),
+ tcx.fold_regions(value, &mut false, |r, _db| match *r {
+ ty::ReVar(rid) => self.resolve_var(rid),
_ => r,
})
}
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 5191d1c..57cbe2c 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -78,9 +78,9 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
@@ -103,7 +103,7 @@
}
impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
- fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+ fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 04e04e2..57ac98c 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -10,7 +10,6 @@
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;
@@ -131,6 +130,7 @@
/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot
/// operations are hot enough that we want only one call to `borrow_mut` per
/// call to `start_snapshot` and `rollback_to`.
+#[derive(Clone)]
pub struct InferCtxtInner<'tcx> {
/// Cache for projections. This cache is snapshotted along with the infcx.
///
@@ -196,7 +196,7 @@
// 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.
+ // 'de-opaque' OpaqueTypeDecl outside of type inference.
pub opaque_types: OpaqueTypeMap<'tcx>,
/// A map from inference variables created from opaque
@@ -291,7 +291,12 @@
/// 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,
+ ///
+ /// If it is `None`, we can't resolve opaque types here and need to bubble up
+ /// the obligation. This frequently happens for
+ /// short lived InferCtxt within queries. The opaque type obligations are forwarded
+ /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
+ pub defining_use_anchor: Option<LocalDefId>,
/// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are
@@ -364,13 +369,26 @@
/// See the `error_reporting` module for more details.
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
pub enum ValuePairs<'tcx> {
- Types(ExpectedFound<Ty<'tcx>>),
Regions(ExpectedFound<ty::Region<'tcx>>),
- Consts(ExpectedFound<&'tcx ty::Const<'tcx>>),
+ Terms(ExpectedFound<ty::Term<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
}
+impl<'tcx> ValuePairs<'tcx> {
+ pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
+ if let ValuePairs::Terms(ExpectedFound {
+ expected: ty::Term::Ty(expected),
+ found: ty::Term::Ty(found),
+ }) = self
+ {
+ Some((*expected, *found))
+ } else {
+ None
+ }
+ }
+}
+
/// The trace designates the path through inference that we took to
/// encounter an error or subtyping constraint.
///
@@ -420,6 +438,13 @@
/// Comparing the signature and requirements of an impl associated type
/// against the containing trait
CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
+
+ /// Checking that the bounds of a trait's associated type hold for a given impl
+ CheckAssociatedTypeBounds {
+ parent: Box<SubregionOrigin<'tcx>>,
+ impl_item_def_id: DefId,
+ trait_item_def_id: DefId,
+ },
}
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -547,7 +572,7 @@
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
- defining_use_anchor: LocalDefId,
+ defining_use_anchor: Option<LocalDefId>,
}
pub trait TyCtxtInferExt<'tcx> {
@@ -556,11 +581,7 @@
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
- InferCtxtBuilder {
- tcx: self,
- defining_use_anchor: CRATE_DEF_ID,
- fresh_typeck_results: None,
- }
+ InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
}
}
@@ -580,7 +601,7 @@
/// (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.defining_use_anchor = Some(defining_use_anchor);
self
}
@@ -1065,11 +1086,7 @@
self.tcx.mk_ty_var(vid)
}
- pub fn next_const_var(
- &self,
- ty: Ty<'tcx>,
- origin: ConstVariableOrigin,
- ) -> &'tcx ty::Const<'tcx> {
+ pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> {
self.tcx.mk_const_var(self.next_const_var_id(origin), ty)
}
@@ -1078,7 +1095,7 @@
ty: Ty<'tcx>,
origin: ConstVariableOrigin,
universe: ty::UniverseIndex,
- ) -> &'tcx ty::Const<'tcx> {
+ ) -> ty::Const<'tcx> {
let vid = self
.inner
.borrow_mut()
@@ -1421,7 +1438,7 @@
pub fn probe_const_var(
&self,
vid: ty::ConstVid<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
+ ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
ConstVariableValue::Known { value } => Ok(value),
ConstVariableValue::Unknown { universe } => Err(universe),
@@ -1487,8 +1504,8 @@
pub fn report_mismatched_consts(
&self,
cause: &ObligationCause<'tcx>,
- expected: &'tcx ty::Const<'tcx>,
- actual: &'tcx ty::Const<'tcx>,
+ expected: ty::Const<'tcx>,
+ actual: ty::Const<'tcx>,
err: TypeError<'tcx>,
) -> DiagnosticBuilder<'tcx> {
let trace = TypeTrace::consts(cause, true, expected, actual);
@@ -1585,8 +1602,7 @@
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
- let mut substs = unevaluated.substs(self.tcx);
- substs = self.resolve_vars_if_possible(substs);
+ let substs = self.resolve_vars_if_possible(unevaluated.substs);
// Postpone the evaluation of constants whose substs depend on inference
// variables
@@ -1599,7 +1615,7 @@
let unevaluated = ty::Unevaluated {
def: unevaluated.def,
- substs_: Some(substs_erased),
+ substs: substs_erased,
promoted: unevaluated.promoted,
};
@@ -1743,8 +1759,8 @@
/// Tries to extract an inference variable from a constant, returns `None`
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
- pub fn maybe_from_const(ct: &'tcx ty::Const<'tcx>) -> Option<Self> {
- match ct.val {
+ pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
+ match ct.val() {
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
_ => None,
}
@@ -1764,13 +1780,13 @@
self.infcx.shallow_resolve_ty(ty)
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() {
self.infcx
.inner
.borrow_mut()
.const_unification_table()
- .probe_value(*vid)
+ .probe_value(vid)
.val
.known()
.unwrap_or(ct)
@@ -1791,16 +1807,22 @@
a: Ty<'tcx>,
b: Ty<'tcx>,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
pub fn consts(
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
}
@@ -1817,6 +1839,7 @@
ReferenceOutlivesReferent(_, a) => a,
CompareImplMethodObligation { span, .. } => span,
CompareImplTypeObligation { span, .. } => span,
+ CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
}
}
@@ -1847,6 +1870,15 @@
trait_item_def_id,
},
+ traits::ObligationCauseCode::CheckAssociatedTypeBounds {
+ impl_item_def_id,
+ trait_item_def_id,
+ } => SubregionOrigin::CheckAssociatedTypeBounds {
+ impl_item_def_id,
+ trait_item_def_id,
+ parent: Box::new(default()),
+ },
+
_ => default(),
}
}
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index ebc0e80..60f776d 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -87,7 +87,7 @@
info: ty::VarianceDiagInfo<'tcx>,
);
- fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
+ fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
/// Creates a new universe index. Used when instantiating placeholders.
fn create_next_universe(&mut self) -> ty::UniverseIndex;
@@ -201,7 +201,6 @@
};
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,
@@ -245,8 +244,8 @@
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
debug!("replace_bound_regions(scopes={:?})", scopes);
- if let ty::ReLateBound(debruijn, br) = r {
- Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
+ if let ty::ReLateBound(debruijn, br) = *r {
+ Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
} else {
r
}
@@ -451,7 +450,7 @@
where
D: TypeRelatingDelegate<'tcx>,
{
- relate.relate(&generalized_ty, &self.value_ty())
+ relate.relate(generalized_ty, self.value_ty())
}
}
@@ -483,7 +482,7 @@
where
D: TypeRelatingDelegate<'tcx>,
{
- relate.relate(&self.value_ty(), &generalized_ty)
+ relate.relate(self.value_ty(), generalized_ty)
}
}
@@ -610,16 +609,16 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- mut b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ mut b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
let a = self.infcx.shallow_resolve(a);
if !D::forbid_inference_vars() {
b = self.infcx.shallow_resolve(b);
}
- match b.val {
+ match b.val() {
ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
// Forbid inference variables in the RHS.
bug!("unexpected inference var {:?}", b)
@@ -746,7 +745,7 @@
where
D: TypeRelatingDelegate<'tcx>,
{
- fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+ fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
self.delegate.const_equate(a, b);
}
}
@@ -759,7 +758,6 @@
/// `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,
@@ -767,10 +765,6 @@
}
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>,
@@ -785,9 +779,9 @@
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
let ScopeInstantiator { bound_region_scope, next_region, .. } = self;
- match r {
- ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
- bound_region_scope.map.entry(*br).or_insert_with(|| next_region(*br));
+ match *r {
+ ty::ReLateBound(debruijn, br) if debruijn == self.target_index => {
+ bound_region_scope.map.entry(br).or_insert_with(|| next_region(br));
}
_ => {}
@@ -969,8 +963,8 @@
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("TypeGeneralizer::regions(a={:?})", a);
- if let ty::ReLateBound(debruijn, _) = a {
- if *debruijn < self.first_free_index {
+ if let ty::ReLateBound(debruijn, _) = *a {
+ if debruijn < self.first_free_index {
return Ok(a);
}
}
@@ -998,10 +992,10 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- _: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
- match a.val {
+ a: ty::Const<'tcx>,
+ _: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+ match a.val() {
ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
}
@@ -1016,7 +1010,7 @@
origin: var_value.origin,
val: ConstVariableValue::Unknown { universe: self.universe },
});
- Ok(self.tcx().mk_const_var(new_var_id, a.ty))
+ Ok(self.tcx().mk_const_var(new_var_id, a.ty()))
}
}
}
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index c2ef0b4..e7dca94 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -316,7 +316,6 @@
);
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx: self.tcx,
op: |r| {
self.member_constraint(
opaque_type_key.def_id,
@@ -328,6 +327,31 @@
},
});
}
+
+ fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
+ let tcx = self.tcx;
+ let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let parent_def_id = self.defining_use_anchor?;
+ let item_kind = &tcx.hir().expect_item(def_id).kind;
+ let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
+ span_bug!(
+ tcx.def_span(def_id),
+ "weird opaque type: {:#?}",
+ item_kind
+ )
+ };
+ let in_definition_scope = match *origin {
+ // Async `impl Trait`
+ hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
+ // Anonymous `impl Trait`
+ hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
+ // Named `type Foo = impl Bar;`
+ hir::OpaqueTyOrigin::TyAlias => {
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
+ }
+ };
+ in_definition_scope.then_some(*origin)
+ }
}
// Visitor that requires that (almost) all regions in the type visited outlive
@@ -343,19 +367,14 @@
//
// We ignore any type parameters because impl trait values are assumed to
// capture all the in-scope type parameters.
-struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
- tcx: TyCtxt<'tcx>,
+struct ConstrainOpaqueTypeRegionVisitor<OP> {
op: OP,
}
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<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>,
@@ -377,7 +396,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_POTENTIAL_FREE_REGIONS) {
+ if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
return ControlFlow::CONTINUE;
}
@@ -459,31 +478,10 @@
// }
// ```
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.infcx.defining_use_anchor;
- let item_kind = &tcx.hir().expect_item(def_id).kind;
- let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
- span_bug!(
- self.value_span,
- "weird opaque type: {:#?}, {:#?}",
- ty.kind(),
- item_kind
- )
- };
- let in_definition_scope = match *origin {
- // Async `impl Trait`
- hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
- // Anonymous `impl Trait`
- hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
- // Named `type Foo = impl Bar;`
- hir::OpaqueTyOrigin::TyAlias => {
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
- }
- };
- if in_definition_scope {
+ if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
let opaque_type_key =
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, *origin);
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
}
debug!(
@@ -551,17 +549,35 @@
let predicate = predicate.subst(tcx, substs);
debug!(?predicate);
+ let predicate = predicate.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| match *ty.kind() {
+ // Replace all other mentions of the same opaque type with the hidden type,
+ // as the bounds must hold on the hidden type after all.
+ ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
+ ty_var
+ }
+ // Instantiate nested instances of `impl Trait`.
+ ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
+ _ => ty,
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ });
+
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match ty.kind() {
- ty::Projection(projection_ty) => infcx.infer_projection(
- self.param_env,
- *projection_ty,
- traits::ObligationCause::misc(self.value_span, self.body_id),
- 0,
- &mut self.obligations,
- ),
+ ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+ infcx.infer_projection(
+ self.param_env,
+ *projection_ty,
+ traits::ObligationCause::misc(self.value_span, self.body_id),
+ 0,
+ &mut self.obligations,
+ )
+ }
_ => ty,
},
lt_op: |lt| lt,
@@ -570,15 +586,10 @@
debug!(?predicate);
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.
+ if projection.term.references_error() {
return tcx.ty_error();
}
}
- // Change the predicate to refer to the type variable,
- // which will be the concrete type instead of the opaque type.
- // This also instantiates nested instances of `impl Trait`.
- let predicate = self.instantiate_opaque_types_in_map(predicate);
let cause =
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
@@ -619,7 +630,7 @@
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
- hir_id = tcx.hir().get_parent_item(hir_id);
+ hir_id = tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(hir_id));
}
// Syntactically, we are allowed to define the concrete type if:
let res = hir_id == scope;
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index 22e18de..fbf149a 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -196,7 +196,7 @@
out: &mut SmallVec<[Component<'tcx>; 4]>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) {
- for child in parent.walk_shallow(tcx, visited) {
+ for child in parent.walk_shallow(visited) {
match child.unpack() {
GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited);
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 3947282..bd8bb9e 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -2,8 +2,9 @@
use crate::infer::{GenericKind, InferCtxt};
use crate::traits::query::OutlivesBound;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
use super::explicit_outlives_bounds;
@@ -66,7 +67,7 @@
/// "Region-bound pairs" tracks outlives relations that are known to
/// be true, either because of explicit where-clauses like `T: 'a` or
/// because of implied bounds.
-pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
+pub type RegionBoundPairs<'tcx> = Vec<(Region<'tcx>, GenericKind<'tcx>)>;
impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
@@ -164,10 +165,10 @@
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
match outlives_bound {
OutlivesBound::RegionSubRegion(
- r_a @ (&ty::ReEarlyBound(_) | &ty::ReFree(_)),
- &ty::ReVar(vid_b),
+ r_a @ (Region(Interned(ReEarlyBound(_), _)) | Region(Interned(ReFree(_), _))),
+ Region(Interned(ReVar(vid_b), _)),
) => {
- infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
+ infcx.expect("no infcx provided but region vars found").add_given(r_a, *vid_b);
}
OutlivesBound::RegionSubParam(r_a, param_b) => {
self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b)));
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 74eb263..0224aba 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -164,7 +164,7 @@
"cannot process registered region obligations in a snapshot"
);
- debug!("process_registered_region_obligations()");
+ debug!(?param_env, "process_registered_region_obligations()");
let my_region_obligations = self.take_registered_region_obligations();
@@ -285,7 +285,7 @@
let origin = origin.clone();
match component {
Component::Region(region1) => {
- self.delegate.push_sub_region_constraint(origin, region, region1);
+ self.delegate.push_sub_region_constraint(origin, region, *region1);
}
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
@@ -356,6 +356,8 @@
let trait_bounds: Vec<_> =
self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+ debug!(?trait_bounds);
+
// Compute the bounds we can derive from the environment. This
// is an "approximate" match -- in some cases, these bounds
// may not apply.
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index dba7325..f69212c 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(self.tcx, visited)
+ .walk_shallow(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/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index 9b53ab7..b45a651 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -26,7 +26,8 @@
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id),
});
- let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
+ let projection =
+ ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
let obligation = Obligation::with_depth(
cause,
recursion_depth,
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 2d4c1e5..36d18ae 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -154,17 +154,17 @@
let scc = self.mini_graph.sccs.scc(*leak_check_node);
// Set the universe of each SCC to be the minimum of its constituent universes
- let universe = self.rcc.universe(region);
+ let universe = self.rcc.universe(*region);
debug!(
"assign_placeholder_values: scc={:?} universe={:?} region={:?}",
scc, universe, region
);
- self.scc_universes[scc].take_min(universe, region);
+ self.scc_universes[scc].take_min(universe, *region);
// Detect those SCCs that directly contain a placeholder
- if let ty::RePlaceholder(placeholder) = region {
+ if let ty::RePlaceholder(placeholder) = **region {
if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
- self.assign_scc_value(scc, *placeholder)?;
+ self.assign_scc_value(scc, placeholder)?;
}
}
}
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 29775a9..a5bd3b1 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -8,6 +8,7 @@
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
@@ -28,7 +29,7 @@
pub use rustc_middle::infer::MemberConstraint;
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct RegionConstraintStorage<'tcx> {
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
var_infos: IndexVec<RegionVid, RegionVariableInfo>,
@@ -502,14 +503,15 @@
self.make_subregion(origin, sup, sub);
match (sub, sup) {
- (&ty::ReVar(sub), &ty::ReVar(sup)) => {
+ (Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => {
debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
- self.unification_table().union(sub, sup);
+ self.unification_table().union(*sub, *sup);
self.any_unifications = true;
}
- (&ty::ReVar(vid), value) | (value, &ty::ReVar(vid)) => {
+ (Region(Interned(ReVar(vid), _)), value)
+ | (value, Region(Interned(ReVar(vid), _))) => {
debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
- self.unification_table().union_value(vid, UnifiedRegion(Some(value)));
+ self.unification_table().union_value(*vid, UnifiedRegion(Some(value)));
self.any_unifications = true;
}
(_, _) => {}
@@ -550,20 +552,20 @@
// cannot add constraints once regions are resolved
debug!("origin = {:#?}", origin);
- match (sub, sup) {
- (&ReLateBound(..), _) | (_, &ReLateBound(..)) => {
+ match (*sub, *sup) {
+ (ReLateBound(..), _) | (_, ReLateBound(..)) => {
span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup);
}
- (_, &ReStatic) => {
+ (_, ReStatic) => {
// all regions are subregions of static, so we can ignore this
}
- (&ReVar(sub_id), &ReVar(sup_id)) => {
+ (ReVar(sub_id), ReVar(sup_id)) => {
self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin);
}
- (_, &ReVar(sup_id)) => {
+ (_, ReVar(sup_id)) => {
self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin);
}
- (&ReVar(sub_id), _) => {
+ (ReVar(sub_id), _) => {
self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin);
}
_ => {
@@ -591,16 +593,12 @@
) -> Region<'tcx> {
// cannot add constraints once regions are resolved
debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b);
- match (a, b) {
- (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
- r // nothing lives longer than static
- }
-
- _ if a == b => {
- a // LUB(a,a) = a
- }
-
- _ => self.combine_vars(tcx, Lub, a, b, origin),
+ if a.is_static() || b.is_static() {
+ a // nothing lives longer than static
+ } else if a == b {
+ a // LUB(a,a) = a
+ } else {
+ self.combine_vars(tcx, Lub, a, b, origin)
}
}
@@ -613,16 +611,14 @@
) -> Region<'tcx> {
// cannot add constraints once regions are resolved
debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b);
- match (a, b) {
- (&ReStatic, r) | (r, &ReStatic) => {
- r // static lives longer than everything else
- }
-
- _ if a == b => {
- a // GLB(a,a) = a
- }
-
- _ => self.combine_vars(tcx, Glb, a, b, origin),
+ if a.is_static() {
+ b // static lives longer than everything else
+ } else if b.is_static() {
+ a // static lives longer than everything else
+ } else if a == b {
+ a // GLB(a,a) = a
+ } else {
+ self.combine_vars(tcx, Glb, a, b, origin)
}
}
@@ -639,11 +635,11 @@
tcx: TyCtxt<'tcx>,
region: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
- match region {
+ match *region {
ty::ReVar(rid) => {
- let unified_region = self.unification_table().probe_value(*rid);
+ let unified_region = self.unification_table().probe_value(rid);
unified_region.0.unwrap_or_else(|| {
- let root = self.unification_table().find(*rid).vid;
+ let root = self.unification_table().find(rid).vid;
tcx.reuse_or_mk_region(region, ty::ReVar(root))
})
}
@@ -767,8 +763,7 @@
pub fn must_hold(&self) -> bool {
match self {
VerifyBound::IfEq(..) => false,
- VerifyBound::OutlivedBy(ty::ReStatic) => true,
- VerifyBound::OutlivedBy(_) => false,
+ VerifyBound::OutlivedBy(re) => re.is_static(),
VerifyBound::IsEmpty => false,
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index f036e12..08358bf 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -39,7 +39,7 @@
}
}
- fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
+ fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
if !ct.has_infer_types_or_consts() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
@@ -98,7 +98,7 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
if !ct.has_infer_regions() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
@@ -126,11 +126,6 @@
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() {
@@ -223,15 +218,12 @@
}
}
- fn try_fold_const(
- &mut self,
- c: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
if !c.needs_infer() {
Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
- match c.val {
+ match c.val() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
return Err(FixupError::UnresolvedConst(vid));
}
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index ccac0ef..9ec1b33 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -151,9 +151,9 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.fields.infcx.super_combine_consts(self, a, b)
}
@@ -170,7 +170,7 @@
}
impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
- fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+ fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 82970f2..74c4408 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -14,6 +14,7 @@
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
/// Represents a single undo-able action that affects a type inference variable.
+#[derive(Clone)]
pub(crate) enum UndoLog<'tcx> {
EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>),
SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>),
@@ -58,6 +59,7 @@
}
}
+#[derive(Clone)]
pub struct TypeVariableStorage<'tcx> {
values: sv::SnapshotVecStorage<Delegate>,
@@ -137,6 +139,7 @@
LatticeVariable,
}
+#[derive(Clone)]
pub(crate) struct TypeVariableData {
origin: TypeVariableOrigin,
}
@@ -165,6 +168,7 @@
}
}
+#[derive(Clone)]
pub(crate) struct Instantiate;
pub(crate) struct Delegate;
@@ -259,7 +263,7 @@
let index = self.values().push(TypeVariableData { origin });
assert_eq!(eq_key.vid.as_u32(), index as u32);
- debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,);
+ debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin);
eq_key.vid
}
@@ -412,6 +416,7 @@
fn index(&self) -> u32 {
self.vid.as_u32()
}
+ #[inline]
fn from_index(i: u32) -> Self {
TyVidEqKey::from(ty::TyVid::from_u32(i))
}
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 89db8f4..ecd886b 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -17,6 +17,7 @@
}
/// Records the "undo" data for a single operation that affects some form of inference variable.
+#[derive(Clone)]
pub(crate) enum UndoLog<'tcx> {
TypeVariables(type_variable::UndoLog<'tcx>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
@@ -84,6 +85,7 @@
/// The combined undo log for all the various unification tables. For each change to the storage
/// for any kind of inference variable, we record an UndoLog entry in the vector here.
+#[derive(Clone)]
pub(crate) struct InferCtxtUndoLogs<'tcx> {
logs: Vec<UndoLog<'tcx>>,
num_open_snapshots: usize,
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 5f228d1..ae79e14 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -23,6 +23,7 @@
#![feature(min_specialization)]
#![feature(label_break_value)]
#![recursion_limit = "512"] // For rustdoc
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index e1f3b54..85bb727 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -101,7 +101,7 @@
CodeSelectionError(SelectionError<'tcx>),
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
- CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>),
+ CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
CodeAmbiguity,
}
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index 96af16c..b84ed3d 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -70,7 +70,7 @@
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
}
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct ProjectionCacheStorage<'tcx> {
map: SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
}
@@ -93,7 +93,7 @@
Recur,
Error,
NormalizedTy {
- ty: NormalizedTy<'tcx>,
+ ty: Normalized<'tcx, ty::Term<'tcx>>,
/// If we were able to successfully evaluate the
/// corresponding cache entry key during predicate
/// evaluation, then this field stores the final
@@ -174,7 +174,11 @@
}
/// Indicates that `key` was normalized to `value`.
- pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) {
+ pub fn insert_term(
+ &mut self,
+ key: ProjectionCacheKey<'tcx>,
+ value: Normalized<'tcx, ty::Term<'tcx>>,
+ ) {
debug!(
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
key, value
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 8f5d6c8..674c75f 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -152,7 +152,7 @@
obligation.cause.clone(),
)
});
- debug!("super_predicates: data={:?}", data);
+ debug!(?data, ?obligations, "super_predicates");
// Only keep those bounds that we haven't already seen.
// This is necessary to prevent infinite recursion in some
@@ -241,10 +241,19 @@
Component::UnresolvedInferenceVariable(_) => None,
- Component::Projection(_) | Component::EscapingProjection(_) => {
- // We can probably do more here. This
- // corresponds to a case like `<T as
- // Foo<'a>>::U: 'b`.
+ Component::Projection(projection) => {
+ // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
+ // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
+ let ty =
+ tcx.mk_projection(projection.item_def_id, projection.substs);
+ Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+ ty, r_min,
+ )))
+ }
+
+ Component::EscapingProjection(_) => {
+ // We might be able to do more here, but we don't
+ // want to deal with escaping vars right now.
None
}
})
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index f5823e5..e31119c 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -10,8 +10,8 @@
libc = "0.2"
libloading = "0.7.1"
tracing = "0.1"
-rustc-rayon-core = "0.3.1"
-rayon = { version = "0.3.1", package = "rustc-rayon" }
+rustc-rayon-core = "0.3.2"
+rayon = { version = "0.3.2", package = "rustc-rayon" }
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index 3c7908f..a18e2d1 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -4,7 +4,7 @@
//! `rustc_data_structures::AtomicRef` type, which allows us to setup a global
//! static which can then be set in this file at program startup.
//!
-//! See `SPAN_DEBUG` for an example of how to set things up.
+//! See `SPAN_TRACK` for an example of how to set things up.
//!
//! The functions in this file should fall back to the default set in their
//! origin crate when the `TyCtxt` is not present in TLS.
@@ -13,18 +13,6 @@
use rustc_middle::ty::tls;
use std::fmt;
-/// This is a callback from `rustc_ast` as it cannot access the implicit state
-/// in `rustc_middle` otherwise.
-fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- tls::with_opt(|tcx| {
- if let Some(tcx) = tcx {
- rustc_span::debug_with_source_map(span, f, tcx.sess.source_map())
- } else {
- rustc_span::default_span_debug(span, f)
- }
- })
-}
-
fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
tls::with_opt(|tcx| {
if let Some(tcx) = tcx {
@@ -65,7 +53,6 @@
/// Sets up the callbacks in prior crates which we want to refer to the
/// TyCtxt in.
pub fn setup_callbacks() {
- rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 3804e10..609fc4b 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -2,7 +2,7 @@
use crate::util;
use rustc_ast::token;
-use rustc_ast::{self as ast, MetaItemKind};
+use rustc_ast::{self as ast, LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
@@ -13,15 +13,15 @@
use rustc_middle::ty;
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
-use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
use rustc_session::early_error;
use rustc_session::lint;
use rustc_session::parse::{CrateConfig, ParseSess};
use rustc_session::{DiagnosticOutput, Session};
use rustc_span::source_map::{FileLoader, FileName};
+use rustc_span::symbol::sym;
use std::path::PathBuf;
use std::result;
-use std::sync::{Arc, Mutex};
pub type Result<T> = result::Result<T, ErrorReported>;
@@ -124,13 +124,106 @@
Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
}
- error!(r#"expected `key` or `key="value"`"#);
+ // If the user tried to use a key="value" flag, but is missing the quotes, provide
+ // a hint about how to resolve this.
+ if s.contains('=') && !s.contains("=\"") && !s.ends_with('"') {
+ error!(concat!(
+ r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
+ r#" for your shell, try 'key="value"' or key=\"value\""#
+ ));
+ } else {
+ error!(r#"expected `key` or `key="value"`"#);
+ }
})
.collect::<CrateConfig>();
cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
})
}
+/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
+pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
+ rustc_span::create_default_session_if_not_set_then(move |_| {
+ let mut cfg = CheckCfg::default();
+
+ 'specs: for s in specs {
+ let sess = ParseSess::with_silent_emitter(Some(format!(
+ "this error occurred on the command line: `--check-cfg={}`",
+ s
+ )));
+ let filename = FileName::cfg_spec_source_code(&s);
+
+ macro_rules! error {
+ ($reason: expr) => {
+ early_error(
+ ErrorOutputType::default(),
+ &format!(
+ concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+ s
+ ),
+ );
+ };
+ }
+
+ match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
+ Ok(mut parser) => match &mut parser.parse_meta_item() {
+ Ok(meta_item) if parser.token == token::Eof => {
+ if let Some(args) = meta_item.meta_item_list() {
+ if meta_item.has_name(sym::names) {
+ cfg.names_checked = true;
+ for arg in args {
+ if arg.is_word() && arg.ident().is_some() {
+ let ident = arg.ident().expect("multi-segment cfg key");
+ cfg.names_valid.insert(ident.name.to_string());
+ } else {
+ error!("`names()` arguments must be simple identifers");
+ }
+ }
+ continue 'specs;
+ } else if meta_item.has_name(sym::values) {
+ if let Some((name, values)) = args.split_first() {
+ if name.is_word() && name.ident().is_some() {
+ let ident = name.ident().expect("multi-segment cfg key");
+ cfg.values_checked.insert(ident.to_string());
+ for val in values {
+ if let Some(LitKind::Str(s, _)) =
+ val.literal().map(|lit| &lit.kind)
+ {
+ cfg.values_valid
+ .insert((ident.to_string(), s.to_string()));
+ } else {
+ error!(
+ "`values()` arguments must be string literals"
+ );
+ }
+ }
+
+ continue 'specs;
+ } else {
+ error!(
+ "`values()` first argument must be a simple identifer"
+ );
+ }
+ }
+ }
+ }
+ }
+ Ok(..) => {}
+ Err(err) => err.cancel(),
+ },
+ Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
+ }
+
+ error!(
+ "expected `names(name1, name2, ... nameN)` or \
+ `values(name, \"value1\", \"value2\", ... \"valueN\")`"
+ );
+ }
+
+ cfg.names_valid.extend(cfg.values_checked.iter().cloned());
+ cfg
+ })
+}
+
/// The compiler configuration
pub struct Config {
/// Command line options
@@ -138,6 +231,7 @@
/// cfg! configuration in addition to the default ones
pub crate_cfg: FxHashSet<(String, Option<String>)>,
+ pub crate_check_cfg: CheckCfg,
pub input: Input,
pub input_path: Option<PathBuf>,
@@ -146,9 +240,6 @@
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
pub diagnostic_output: DiagnosticOutput,
- /// Set to capture stderr output during compiler execution
- pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
-
pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
/// This is a callback from the driver that is called when [`ParseSess`] is created.
@@ -177,10 +268,13 @@
}
pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
+ crate::callbacks::setup_callbacks();
+
let registry = &config.registry;
let (mut sess, codegen_backend) = util::create_session(
config.opts,
config.crate_cfg,
+ config.crate_check_cfg,
config.diagnostic_output,
config.file_loader,
config.input_path.clone(),
@@ -226,13 +320,11 @@
})
}
-pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
+pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
tracing::trace!("run_compiler");
- let stderr = config.stderr.take();
- util::setup_callbacks_and_run_in_thread_pool_with_globals(
+ util::run_in_thread_pool_with_globals(
config.opts.edition,
config.opts.debugging_opts.threads,
- &stderr,
|| create_compiler_and_run(config, f),
)
}
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 2fc3759..dcad303 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,10 +1,12 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
+#![feature(let_else)]
#![feature(internal_output_capture)]
#![feature(thread_spawn_unchecked)]
#![feature(nll)]
#![feature(once_cell)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
mod callbacks;
pub mod interface;
@@ -13,6 +15,7 @@
mod queries;
pub mod util;
+pub use callbacks::setup_callbacks;
pub use interface::{run_compiler, Config};
pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS};
pub use queries::Queries;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 33bf670..c0552fd 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -3,7 +3,7 @@
use crate::util;
use rustc_ast::mut_visit::MutVisitor;
-use rustc_ast::{self as ast, visit, DUMMY_NODE_ID};
+use rustc_ast::{self as ast, visit};
use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend;
@@ -11,16 +11,16 @@
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{Applicability, ErrorReported, PResult};
-use rustc_expand::base::ExtCtxt;
+use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate;
-use rustc_lint::LintStore;
+use rustc_lint::{EarlyCheckNode, LintStore};
use rustc_metadata::creader::CStore;
use rustc_metadata::{encode_metadata, EncodedMetadata};
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::query::{ExternProviders, Providers};
-use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
+use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test};
@@ -34,7 +34,7 @@
use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Symbol};
use rustc_span::{FileName, MultiSpan};
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
@@ -233,26 +233,43 @@
Ok((krate, lint_store))
}
-fn pre_expansion_lint(
+fn pre_expansion_lint<'a>(
sess: &Session,
lint_store: &LintStore,
- krate: &ast::Crate,
- crate_attrs: &[ast::Attribute],
- crate_name: &str,
+ registered_tools: &RegisteredTools,
+ check_node: impl EarlyCheckNode<'a>,
+ node_name: &str,
) {
- sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
- rustc_lint::check_ast_crate(
+ sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| {
+ rustc_lint::check_ast_node(
sess,
- lint_store,
- krate,
- crate_attrs,
true,
+ lint_store,
+ registered_tools,
None,
rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
+ check_node,
);
});
}
+// Cannot implement directly for `LintStore` due to trait coherence.
+struct LintStoreExpandImpl<'a>(&'a LintStore);
+
+impl LintStoreExpand for LintStoreExpandImpl<'_> {
+ fn pre_expansion_lint(
+ &self,
+ sess: &Session,
+ registered_tools: &RegisteredTools,
+ node_id: ast::NodeId,
+ attrs: &[ast::Attribute],
+ items: &[rustc_ast::ptr::P<ast::Item>],
+ name: &str,
+ ) {
+ pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name);
+ }
+}
+
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
/// harness if one is to be provided, injection of a dependency on the
@@ -265,12 +282,11 @@
resolver: &mut Resolver<'_>,
) -> Result<ast::Crate> {
tracing::trace!("configure_and_expand");
- pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name);
+ pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name);
rustc_builtin_macros::register_builtin_macros(resolver);
krate = sess.time("crate_injection", || {
- let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
- rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name)
+ rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess)
});
util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
@@ -321,13 +337,8 @@
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
};
- let crate_attrs = krate.attrs.clone();
- let extern_mod_loaded = |ident: Ident, attrs, items, span| {
- let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
- pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
- (krate.attrs, krate.items)
- };
- let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded));
+ let lint_store = LintStoreExpandImpl(lint_store);
+ let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
@@ -382,8 +393,18 @@
});
let crate_types = sess.crate_types();
+ let is_executable_crate = crate_types.contains(&CrateType::Executable);
let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
+ if crate_types.len() > 1 {
+ if is_executable_crate {
+ sess.err("cannot mix `bin` crate type with others");
+ }
+ if is_proc_macro_crate {
+ sess.err("cannot mix `proc-macro` crate type with others");
+ }
+ }
+
// For backwards compatibility, we don't try to run proc macro injection
// if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
// specified. This should only affect users who manually invoke 'rustdoc', as
@@ -400,7 +421,6 @@
msg.emit()
} else {
krate = sess.time("maybe_create_a_macro_crate", || {
- let num_crate_types = crate_types.len();
let is_test_crate = sess.opts.test;
rustc_builtin_macros::proc_macro_harness::inject(
sess,
@@ -409,7 +429,6 @@
is_proc_macro_crate,
has_proc_macro_decls,
is_test_crate,
- num_crate_types,
sess.diagnostic(),
)
});
@@ -499,14 +518,15 @@
);
sess.time("early_lint_checks", || {
- rustc_lint::check_ast_crate(
+ let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
+ rustc_lint::check_ast_node(
sess,
- lint_store,
- &krate,
- &krate.attrs,
false,
- Some(std::mem::take(resolver.lint_buffer())),
+ lint_store,
+ resolver.registered_tools(),
+ lint_buffer,
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
+ &*krate,
)
});
@@ -645,13 +665,13 @@
boxed_resolver.borrow_mut().access(|resolver| {
for cnum in resolver.cstore().crates_untracked() {
let source = resolver.cstore().crate_source_untracked(cnum);
- if let Some((path, _)) = source.dylib {
+ if let Some((path, _)) = &source.dylib {
files.push(escape_dep_filename(&path.display().to_string()));
}
- if let Some((path, _)) = source.rlib {
+ if let Some((path, _)) = &source.rlib {
files.push(escape_dep_filename(&path.display().to_string()));
}
- if let Some((path, _)) = source.rmeta {
+ if let Some((path, _)) = &source.rmeta {
files.push(escape_dep_filename(&path.display().to_string()));
}
}
@@ -986,7 +1006,8 @@
tcx.ensure().check_private_in_public(());
},
{
- sess.time("death_checking", || rustc_passes::dead::check_crate(tcx));
+ tcx.hir()
+ .par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
},
{
sess.time("unused_lib_feature_checking", || {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index e635ee1..89390ee 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -13,7 +13,6 @@
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::{GlobalCtxt, TyCtxt};
use rustc_query_impl::Queries as TcxQueries;
-use rustc_serialize::json;
use rustc_session::config::{self, OutputFilenames, OutputType};
use rustc_session::{output::find_crate_name, Session};
use rustc_span::symbol::sym;
@@ -367,12 +366,10 @@
}
if sess.opts.debugging_opts.no_link {
- // FIXME: use a binary format to encode the `.rlink` file
- let rlink_data = json::encode(&codegen_results).map_err(|err| {
- sess.fatal(&format!("failed to encode rlink: {}", err));
- })?;
+ let mut encoder = rustc_serialize::opaque::Encoder::new(Vec::new());
+ rustc_serialize::Encodable::encode(&codegen_results, &mut encoder).unwrap();
let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
- std::fs::write(&rlink_file, rlink_data).map_err(|err| {
+ std::fs::write(&rlink_file, encoder.into_inner()).map_err(|err| {
sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
})?;
return Ok(());
@@ -403,10 +400,6 @@
gcx.enter(rustc_query_impl::alloc_self_profile_query_strings);
}
- if self.session().opts.debugging_opts.query_stats {
- gcx.enter(rustc_query_impl::print_stats);
- }
-
self.session()
.time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph));
}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 30e319c..f9c39f7 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -8,10 +8,11 @@
use rustc_session::config::{
rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
};
-use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
use rustc_session::config::{
- Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel,
+ BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion,
+ WasiExecModel,
};
+use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
@@ -574,6 +575,7 @@
tracked!(force_frame_pointers, Some(false));
tracked!(force_unwind_tables, Some(true));
tracked!(inline_threshold, Some(0xf007ba11));
+ tracked!(instrument_coverage, Some(InstrumentCoverage::All));
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
tracked!(link_dead_code, Some(true));
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
@@ -645,6 +647,7 @@
untracked!(borrowck, String::from("other"));
untracked!(deduplicate_diagnostics, false);
untracked!(dep_tasks, true);
+ untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
untracked!(dont_buffer_diagnostics, true);
untracked!(dump_dep_graph, true);
untracked!(dump_mir, Some(String::from("abc")));
@@ -676,13 +679,11 @@
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
untracked!(profile_closures, true);
- untracked!(print_link_args, true);
untracked!(print_llvm_passes, true);
untracked!(print_mono_items, Some(String::from("abc")));
untracked!(print_type_sizes, true);
untracked!(proc_macro_backtrace, true);
untracked!(query_dep_graph, true);
- untracked!(query_stats, true);
untracked!(save_analysis, true);
untracked!(self_profile, SwitchWithOptPath::Enabled(None));
untracked!(self_profile_events, Some(vec![String::new()]));
@@ -718,12 +719,20 @@
tracked!(asm_comments, true);
tracked!(assume_incomplete_release, true);
tracked!(binary_dep_depinfo, true);
+ tracked!(
+ branch_protection,
+ Some(BranchProtection {
+ bti: true,
+ pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B })
+ })
+ );
tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(debug_info_for_profiling, true);
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
+ tracked!(drop_tracking, true);
tracked!(dual_proc_macros, true);
tracked!(fewer_names, Some(true));
tracked!(force_unstable_if_unmarked, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index cb51555..46964f5 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -1,7 +1,7 @@
use libloading::Library;
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
+use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
@@ -15,6 +15,7 @@
use rustc_query_impl::QueryCtxt;
use rustc_resolve::{self, Resolver};
use rustc_session as session;
+use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
@@ -27,7 +28,6 @@
use smallvec::SmallVec;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
-use std::io;
use std::lazy::SyncOnceCell;
use std::mem;
use std::ops::DerefMut;
@@ -35,7 +35,6 @@
use std::panic;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex};
use std::thread;
use tracing::info;
@@ -67,6 +66,7 @@
pub fn create_session(
sopts: config::Options,
cfg: FxHashSet<(String, Option<String>)>,
+ check_cfg: CheckCfg,
diagnostic_output: DiagnosticOutput,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
input_path: Option<PathBuf>,
@@ -102,7 +102,13 @@
let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
add_configuration(&mut cfg, &mut sess, &*codegen_backend);
+
+ let mut check_cfg = config::to_crate_check_config(check_cfg);
+ check_cfg.fill_well_known();
+ check_cfg.fill_actual(&cfg);
+
sess.parse_sess.config = cfg;
+ sess.parse_sess.check_config = check_cfg;
(Lrc::new(sess), Lrc::new(codegen_backend))
}
@@ -118,7 +124,7 @@
/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
/// for `'static` bounds.
#[cfg(not(parallel_compiler))]
-pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
+fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
// SAFETY: join() is called immediately, so any closure captures are still
// alive.
match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
@@ -128,10 +134,9 @@
}
#[cfg(not(parallel_compiler))]
-pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
edition: Edition,
_threads: usize,
- stderr: &Option<Arc<Mutex<Vec<u8>>>>,
f: F,
) -> R {
let mut cfg = thread::Builder::new().name("rustc".to_string());
@@ -140,14 +145,7 @@
cfg = cfg.stack_size(size);
}
- crate::callbacks::setup_callbacks();
-
- let main_handler = move || {
- rustc_span::create_session_globals_then(edition, || {
- io::set_output_capture(stderr.clone());
- f()
- })
- };
+ let main_handler = move || rustc_span::create_session_globals_then(edition, f);
scoped_thread(cfg, main_handler)
}
@@ -176,14 +174,11 @@
}
#[cfg(parallel_compiler)]
-pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
edition: Edition,
threads: usize,
- stderr: &Option<Arc<Mutex<Vec<u8>>>>,
f: F,
) -> R {
- crate::callbacks::setup_callbacks();
-
let mut config = rayon::ThreadPoolBuilder::new()
.thread_name(|_| "rustc".to_string())
.acquire_thread_handler(jobserver::acquire_thread)
@@ -203,10 +198,7 @@
// the thread local rustc uses. `session_globals` is captured and set
// on the new threads.
let main_handler = move |thread: rayon::ThreadBuilder| {
- rustc_span::set_session_globals_then(session_globals, || {
- io::set_output_capture(stderr.clone());
- thread.run()
- })
+ rustc_span::set_session_globals_then(session_globals, || thread.run())
};
config.build_scoped(main_handler, with_pool).unwrap()
@@ -343,6 +335,7 @@
#[cfg(windows)]
fn current_dll_path() -> Option<PathBuf> {
use std::ffi::OsString;
+ use std::io;
use std::os::windows::prelude::*;
use std::ptr;
@@ -379,7 +372,7 @@
}
}
-pub fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
+fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
@@ -717,52 +710,57 @@
}
fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool {
- if let ast::FnRetTy::Ty(ref ty) = ret_ty {
- fn involves_impl_trait(ty: &ast::Ty) -> bool {
- match ty.kind {
- ast::TyKind::ImplTrait(..) => true,
- ast::TyKind::Slice(ref subty)
- | ast::TyKind::Array(ref subty, _)
- | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. })
- | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. })
- | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
- ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
- ast::TyKind::Path(_, ref path) => {
- path.segments.iter().any(|seg| match seg.args.as_deref() {
- None => false,
- Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
- data.args.iter().any(|arg| match arg {
- ast::AngleBracketedArg::Arg(arg) => match arg {
- ast::GenericArg::Type(ty) => involves_impl_trait(ty),
- ast::GenericArg::Lifetime(_)
- | ast::GenericArg::Const(_) => false,
- },
- ast::AngleBracketedArg::Constraint(c) => match c.kind {
- ast::AssocTyConstraintKind::Bound { .. } => true,
- ast::AssocTyConstraintKind::Equality { ref ty } => {
- involves_impl_trait(ty)
+ let ast::FnRetTy::Ty(ref ty) = ret_ty else {
+ return false;
+ };
+ fn involves_impl_trait(ty: &ast::Ty) -> bool {
+ match ty.kind {
+ ast::TyKind::ImplTrait(..) => true,
+ ast::TyKind::Slice(ref subty)
+ | ast::TyKind::Array(ref subty, _)
+ | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. })
+ | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. })
+ | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
+ ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
+ ast::TyKind::Path(_, ref path) => {
+ path.segments.iter().any(|seg| match seg.args.as_deref() {
+ None => false,
+ Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
+ data.args.iter().any(|arg| match arg {
+ ast::AngleBracketedArg::Arg(arg) => match arg {
+ ast::GenericArg::Type(ty) => involves_impl_trait(ty),
+ ast::GenericArg::Lifetime(_) | ast::GenericArg::Const(_) => {
+ false
+ }
+ },
+ ast::AngleBracketedArg::Constraint(c) => match c.kind {
+ ast::AssocConstraintKind::Bound { .. } => true,
+ ast::AssocConstraintKind::Equality { ref term } => {
+ match term {
+ Term::Ty(ty) => involves_impl_trait(ty),
+ // FIXME(...): This should check if the constant
+ // involves a trait impl, but for now ignore.
+ Term::Const(_) => false,
}
- },
- })
- }
- Some(&ast::GenericArgs::Parenthesized(ref data)) => {
- any_involves_impl_trait(data.inputs.iter())
- || ReplaceBodyWithLoop::should_ignore_fn(&data.output)
- }
- })
- }
- _ => false,
+ }
+ },
+ })
+ }
+ Some(&ast::GenericArgs::Parenthesized(ref data)) => {
+ any_involves_impl_trait(data.inputs.iter())
+ || ReplaceBodyWithLoop::should_ignore_fn(&data.output)
+ }
+ })
}
+ _ => false,
}
-
- fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool {
- it.any(|subty| involves_impl_trait(subty))
- }
-
- involves_impl_trait(ty)
- } else {
- false
}
+
+ fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool {
+ it.any(|subty| involves_impl_trait(subty))
+ }
+
+ involves_impl_trait(ty)
}
fn is_sig_const(sig: &ast::FnSig) -> bool {
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index b615175..a14d602 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -61,7 +61,7 @@
}
// We only care about method call expressions.
- if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
+ if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind {
if call.ident.name != sym::into_iter {
return;
}
@@ -119,7 +119,7 @@
// to an array or to a slice.
_ => bug!("array type coerced to something other than array or slice"),
};
- cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
+ cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| {
let mut diag = lint.build(&format!(
"this method call resolves to `<&{} as IntoIterator>::into_iter` \
(due to backwards compatibility), \
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 1fd6379..a397db7 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -152,8 +152,8 @@
declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers {
- fn check_heap_type<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
- for leaf in ty.walk(cx.tcx) {
+ fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
+ for leaf in ty.walk() {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if leaf_ty.is_box() {
cx.struct_span_lint(BOX_POINTERS, span, |lint| {
@@ -610,8 +610,7 @@
// reported for missing docs.
let real_trait = trait_ref.path.res.def_id();
let Some(def_id) = real_trait.as_local() else { return };
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) else { return };
+ let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(def_id) else { return };
if let hir::VisibilityKind::Inherited = item.vis.node {
for impl_item_ref in items {
self.private_traits.insert(impl_item_ref.id.hir_id());
@@ -656,7 +655,7 @@
// If the method is an impl for an item with docs_hidden, don't doc.
if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
- let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
let impl_ty = cx.tcx.type_of(parent);
let outerdef = match impl_ty.kind() {
ty::Adt(def, _) => Some(def.did),
@@ -913,7 +912,7 @@
impl EarlyLintPass for AnonymousParameters {
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
- if cx.sess.edition() != Edition::Edition2015 {
+ if cx.sess().edition() != Edition::Edition2015 {
// This is a hard error in future editions; avoid linting and erroring
return;
}
@@ -922,7 +921,7 @@
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
- let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
+ let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
(snip.as_str(), Applicability::MachineApplicable)
@@ -1212,7 +1211,7 @@
check_no_mangle_on_generic_fn(
no_mangle_attr,
Some(generics),
- cx.tcx.hir().get_generics(it.id.def_id.to_def_id()).unwrap(),
+ cx.tcx.hir().get_generics(it.id.def_id).unwrap(),
it.span,
);
}
@@ -1248,7 +1247,7 @@
/// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
MUTABLE_TRANSMUTES,
Deny,
- "mutating transmuted &mut T from &T may cause undefined behavior"
+ "transmuting &T to &mut T is undefined behavior, even if the reference is unused"
}
declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
@@ -1260,8 +1259,8 @@
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
{
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
- let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
- consider instead using an UnsafeCell";
+ let msg = "transmuting &T to &mut T is undefined behavior, \
+ even if the reference is unused, consider instead using an UnsafeCell";
cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| lint.build(msg).emit());
}
}
@@ -1480,12 +1479,6 @@
err: &'a mut DiagnosticBuilder<'db>,
}
impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
-
fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) {
if TypeAliasBounds::is_type_variable_assoc(qpath) {
self.err.span_help(
@@ -1663,7 +1656,7 @@
ConstEquate(..) |
TypeWellFormedFromEnv(..) => continue,
};
- if predicate.is_global(cx.tcx) {
+ if predicate.is_global() {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
lint.build(&format!(
"{} bound {} does not depend on any type \
@@ -1782,7 +1775,7 @@
};
if join.edition() >= Edition::Edition2021 {
let mut err =
- rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+ rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
err.span_suggestion(
pat.span,
suggestion,
@@ -1806,7 +1799,7 @@
let replace = "..=".to_owned();
if join.edition() >= Edition::Edition2021 {
let mut err =
- rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+ rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
err.span_suggestion_short(
join,
suggestion,
@@ -1990,7 +1983,7 @@
UnderMacro(under_macro): UnderMacro,
ident: Ident,
) {
- let next_edition = match cx.sess.edition() {
+ let next_edition = match cx.sess().edition() {
Edition::Edition2015 => {
match ident.name {
kw::Async | kw::Await | kw::Try => Edition::Edition2018,
@@ -2018,7 +2011,7 @@
};
// Don't lint `r#foo`.
- if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
+ if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
return;
}
@@ -2057,7 +2050,7 @@
inferred_outlives
.iter()
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
_ => None,
},
@@ -2118,10 +2111,10 @@
if let hir::GenericBound::Outlives(lifetime) = bound {
let is_inferred = match tcx.named_region(lifetime.hir_id) {
Some(Region::Static) if infer_static => {
- inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic))
+ inferred_outlives.iter().any(|r| matches!(**r, ty::ReStatic))
}
Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
- if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false }
+ if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
}),
_ => false,
};
@@ -2386,7 +2379,7 @@
impl EarlyLintPass for IncompleteFeatures {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
- let features = cx.sess.features_untracked();
+ let features = cx.sess().features_untracked();
features
.declared_lang_features
.iter()
@@ -2501,7 +2494,7 @@
_ => {}
}
}
- } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
+ } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
@@ -2840,7 +2833,7 @@
return true;
}
let tcx = cx.tcx;
- if a == b || rustc_middle::ty::TyS::same_type(a, b) {
+ if a == b {
// All nominally-same types are structurally same, too.
true
} else {
@@ -2902,26 +2895,22 @@
}
(Array(a_ty, a_const), Array(b_ty, b_const)) => {
// For arrays, we also check the constness of the type.
- a_const.val == b_const.val
- && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ a_const.val() == b_const.val()
+ && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
}
(Slice(a_ty), Slice(b_ty)) => {
- structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
}
(RawPtr(a_tymut), RawPtr(b_tymut)) => {
a_tymut.mutbl == b_tymut.mutbl
&& structurally_same_type_impl(
- seen_types,
- cx,
- &a_tymut.ty,
- &b_tymut.ty,
- ckind,
+ seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
)
}
(Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
// For structural sameness, we don't need the region to be same.
a_mut == b_mut
- && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
}
(FnDef(..), FnDef(..)) => {
let a_poly_sig = a.fn_sig(tcx);
@@ -2934,7 +2923,7 @@
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
&& a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
- structurally_same_type_impl(seen_types, cx, a, b, ckind)
+ structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
})
&& structurally_same_type_impl(
seen_types,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index d938664..d2d853e 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -16,10 +16,9 @@
use self::TargetLint::*;
-use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
+use crate::levels::LintLevelsBuilder;
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
-use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
-use rustc_ast as ast;
+use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
use rustc_errors::{struct_span_err, Applicability, SuggestionStyle};
@@ -32,13 +31,14 @@
use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
+use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
use rustc_serialize::json::Json;
use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi;
use tracing::debug;
@@ -143,7 +143,11 @@
&self.lints
}
- pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
+ pub fn get_lint_groups<'t>(
+ &'t self,
+ ) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> + 't {
+ // This function is not used in a way which observes the order of lints.
+ #[cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
self.lint_groups
.iter()
.filter(|(_, LintGroup { depr, .. })| {
@@ -153,7 +157,6 @@
.map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
(*k, lint_ids.clone(), *from_plugin)
})
- .collect()
}
pub fn register_early_pass(
@@ -313,7 +316,7 @@
sess: &Session,
lint_name: &str,
level: Level,
- crate_attrs: &[ast::Attribute],
+ registered_tools: &RegisteredTools,
) {
let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
@@ -326,7 +329,7 @@
)
.emit();
}
- let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) {
+ let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
CheckLintNameResult::NoLint(suggestion) => {
@@ -397,13 +400,16 @@
/// printing duplicate warnings.
pub fn check_lint_name(
&self,
- sess: &Session,
lint_name: &str,
tool_name: Option<Symbol>,
- crate_attrs: &[ast::Attribute],
+ registered_tools: &RegisteredTools,
) -> CheckLintNameResult<'_> {
if let Some(tool_name) = tool_name {
- if !is_known_lint_tool(tool_name, sess, crate_attrs) {
+ // FIXME: rustc and rustdoc are considered tools for lints, but not for attributes.
+ if tool_name != sym::rustc
+ && tool_name != sym::rustdoc
+ && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
+ {
return CheckLintNameResult::NoTool;
}
}
@@ -521,7 +527,7 @@
}
}
-/// Context for lint checking after type checking.
+/// Context for lint checking outside of type inference.
pub struct LateContext<'tcx> {
/// Type context we're checking in.
pub tcx: TyCtxt<'tcx>,
@@ -553,20 +559,9 @@
pub only_module: bool,
}
-/// Context for lint checking of the AST, after expansion, before lowering to
-/// HIR.
+/// Context for lint checking of the AST, after expansion, before lowering to HIR.
pub struct EarlyContext<'a> {
- /// Type context we're checking in.
- pub sess: &'a Session,
-
- /// The crate being checked.
- pub krate: &'a ast::Crate,
-
pub builder: LintLevelsBuilder<'a>,
-
- /// The store of registered lints and the lint levels.
- pub lint_store: &'a LintStore,
-
pub buffered: LintBuffer,
}
@@ -802,19 +797,20 @@
}
impl<'a> EarlyContext<'a> {
- pub fn new(
+ pub(crate) fn new(
sess: &'a Session,
- lint_store: &'a LintStore,
- krate: &'a ast::Crate,
- crate_attrs: &'a [ast::Attribute],
- buffered: LintBuffer,
warn_about_weird_lints: bool,
+ lint_store: &'a LintStore,
+ registered_tools: &'a RegisteredTools,
+ buffered: LintBuffer,
) -> EarlyContext<'a> {
EarlyContext {
- sess,
- krate,
- lint_store,
- builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs),
+ builder: LintLevelsBuilder::new(
+ sess,
+ warn_about_weird_lints,
+ lint_store,
+ registered_tools,
+ ),
buffered,
}
}
@@ -852,11 +848,11 @@
/// Gets the overall compiler `Session` object.
fn sess(&self) -> &Session {
- &self.sess
+ &self.builder.sess()
}
fn lints(&self) -> &LintStore {
- &*self.lint_store
+ self.builder.lint_store()
}
fn lookup<S: Into<MultiSpan>>(
@@ -978,7 +974,7 @@
Ok(())
}
- fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
Ok(())
}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 0bba66d..1b2c888 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -16,9 +16,11 @@
use crate::context::{EarlyContext, LintContext, LintStore};
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
-use rustc_ast as ast;
-use rustc_ast::visit as ast_visit;
+use rustc_ast::ptr::P;
+use rustc_ast::visit::{self as ast_visit, Visitor};
use rustc_ast::AstLike;
+use rustc_ast::{self as ast, walk_list};
+use rustc_middle::ty::RegisteredTools;
use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass};
use rustc_session::Session;
use rustc_span::symbol::Ident;
@@ -31,7 +33,7 @@
$cx.pass.$f(&$cx.context, $($args),*);
}) }
-struct EarlyContextAndPass<'a, T: EarlyLintPass> {
+pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
context: EarlyContext<'a>,
pass: T,
}
@@ -57,7 +59,7 @@
F: FnOnce(&mut Self),
{
let is_crate_node = id == ast::CRATE_NODE_ID;
- let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node);
+ let push = self.context.builder.push(attrs, is_crate_node);
self.check_id(id);
self.enter_attrs(attrs);
f(self);
@@ -325,48 +327,89 @@
crate::early_lint_methods!(early_lint_pass_impl, []);
-fn early_lint_crate<T: EarlyLintPass>(
+/// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
+/// This trait generalizes over those nodes.
+pub trait EarlyCheckNode<'a>: Copy {
+ fn id(self) -> ast::NodeId;
+ fn attrs<'b>(self) -> &'b [ast::Attribute]
+ where
+ 'a: 'b;
+ fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+ where
+ 'a: 'b;
+}
+
+impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
+ fn id(self) -> ast::NodeId {
+ ast::CRATE_NODE_ID
+ }
+ fn attrs<'b>(self) -> &'b [ast::Attribute]
+ where
+ 'a: 'b,
+ {
+ &self.attrs
+ }
+ fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+ where
+ 'a: 'b,
+ {
+ run_early_pass!(cx, check_crate, self);
+ ast_visit::walk_crate(cx, self);
+ run_early_pass!(cx, check_crate_post, self);
+ }
+}
+
+impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::Item>]) {
+ fn id(self) -> ast::NodeId {
+ self.0
+ }
+ fn attrs<'b>(self) -> &'b [ast::Attribute]
+ where
+ 'a: 'b,
+ {
+ self.1
+ }
+ fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+ where
+ 'a: 'b,
+ {
+ walk_list!(cx, visit_attribute, self.1);
+ walk_list!(cx, visit_item, self.2);
+ }
+}
+
+fn early_lint_node<'a>(
sess: &Session,
- lint_store: &LintStore,
- krate: &ast::Crate,
- crate_attrs: &[ast::Attribute],
- pass: T,
- buffered: LintBuffer,
warn_about_weird_lints: bool,
+ lint_store: &LintStore,
+ registered_tools: &RegisteredTools,
+ buffered: LintBuffer,
+ pass: impl EarlyLintPass,
+ check_node: impl EarlyCheckNode<'a>,
) -> LintBuffer {
let mut cx = EarlyContextAndPass {
context: EarlyContext::new(
sess,
- lint_store,
- krate,
- crate_attrs,
- buffered,
warn_about_weird_lints,
+ lint_store,
+ registered_tools,
+ buffered,
),
pass,
};
- // Visit the whole crate.
- cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
- // since the root module isn't visited as an item (because it isn't an
- // item), warn for it here.
- run_early_pass!(cx, check_crate, krate);
-
- ast_visit::walk_crate(cx, krate);
-
- run_early_pass!(cx, check_crate_post, krate);
- });
+ cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
cx.context.buffered
}
-pub fn check_ast_crate<T: EarlyLintPass>(
+pub fn check_ast_node<'a>(
sess: &Session,
- lint_store: &LintStore,
- krate: &ast::Crate,
- crate_attrs: &[ast::Attribute],
pre_expansion: bool,
+ lint_store: &LintStore,
+ registered_tools: &RegisteredTools,
lint_buffer: Option<LintBuffer>,
- builtin_lints: T,
+ builtin_lints: impl EarlyLintPass,
+ check_node: impl EarlyCheckNode<'a>,
) {
let passes =
if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
@@ -374,39 +417,39 @@
let mut buffered = lint_buffer.unwrap_or_default();
if !sess.opts.debugging_opts.no_interleave_lints {
- buffered = early_lint_crate(
+ buffered = early_lint_node(
sess,
- lint_store,
- krate,
- crate_attrs,
- builtin_lints,
- buffered,
pre_expansion,
+ lint_store,
+ registered_tools,
+ buffered,
+ builtin_lints,
+ check_node,
);
if !passes.is_empty() {
- buffered = early_lint_crate(
+ buffered = early_lint_node(
sess,
- lint_store,
- krate,
- crate_attrs,
- EarlyLintPassObjects { lints: &mut passes[..] },
- buffered,
false,
+ lint_store,
+ registered_tools,
+ buffered,
+ EarlyLintPassObjects { lints: &mut passes[..] },
+ check_node,
);
}
} else {
for (i, pass) in passes.iter_mut().enumerate() {
buffered =
sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| {
- early_lint_crate(
+ early_lint_node(
sess,
- lint_store,
- krate,
- crate_attrs,
- EarlyLintPassObjects { lints: slice::from_mut(pass) },
- buffered,
pre_expansion && i == 0,
+ lint_store,
+ registered_tools,
+ buffered,
+ EarlyLintPassObjects { lints: slice::from_mut(pass) },
+ check_node,
)
});
}
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index 65772d0..c5e15a8 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -38,7 +38,7 @@
/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
fn is_non_enum(t: Ty<'_>) -> bool {
- !t.is_enum() && !t.potentially_needs_subst()
+ !t.is_enum() && !t.needs_subst()
}
fn enforce_mem_discriminant(
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index c64a67b..944a099 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -5,10 +5,8 @@
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
-use rustc_hir::{
- GenericArg, HirId, Item, ItemKind, MutTy, Mutability, Node, Path, PathSegment, QPath, Ty,
- TyKind,
-};
+use rustc_hir::{Expr, ExprKind, GenericArg, Path, PathSegment, QPath};
+use rustc_hir::{HirId, Item, ItemKind, Node, Ty, TyKind};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -52,16 +50,66 @@
}
declare_tool_lint! {
- pub rustc::USAGE_OF_TY_TYKIND,
+ pub rustc::POTENTIAL_QUERY_INSTABILITY,
Allow,
- "usage of `ty::TyKind` outside of the `ty::sty` module",
+ "require explicit opt-in when using potentially unstable methods or functions",
report_in_external_macro: true
}
+declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);
+
+impl LateLintPass<'_> for QueryStability {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ // FIXME(rustdoc): This lint uses typecheck results, causing rustdoc to
+ // error if there are resolution failures.
+ //
+ // As internal lints are currently always run if there are `unstable_options`,
+ // they are added to the lint store of rustdoc. Internal lints are also
+ // not used via the `lint_mod` query. Crate lints run outside of a query
+ // so rustdoc currently doesn't disable them.
+ //
+ // Instead of relying on this, either change crate lints to a query disabled by
+ // rustdoc, only run internal lints if the user is explicitly opting in
+ // or figure out a different way to avoid running lints for rustdoc.
+ if cx.tcx.sess.opts.actually_rustdoc {
+ return;
+ }
+
+ let (span, def_id, substs) = match expr.kind {
+ ExprKind::MethodCall(segment, _, _)
+ if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
+ {
+ (segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id))
+ },
+ _ => {
+ let &ty::FnDef(def_id, substs) =
+ cx.typeck_results()
+ .node_type(expr.hir_id)
+ .kind() else { return };
+ (expr.span, def_id, substs)
+ }
+ };
+ if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
+ let def_id = instance.def_id();
+ if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
+ cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
+ let msg = format!(
+ "using `{}` can result in unstable query results",
+ cx.tcx.item_name(def_id)
+ );
+ lint.build(&msg)
+ .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
+ .emit();
+ })
+ }
+ }
+ }
+}
+
declare_tool_lint! {
- pub rustc::TY_PASS_BY_REFERENCE,
+ pub rustc::USAGE_OF_TY_TYKIND,
Allow,
- "passing `Ty` or `TyCtxt` by reference",
+ "usage of `ty::TyKind` outside of the `ty::sty` module",
report_in_external_macro: true
}
@@ -74,7 +122,6 @@
declare_lint_pass!(TyTyKind => [
USAGE_OF_TY_TYKIND,
- TY_PASS_BY_REFERENCE,
USAGE_OF_QUALIFIED_TY,
]);
@@ -119,7 +166,7 @@
lint.build(&format!("usage of qualified `ty::{}`", t))
.span_suggestion(
path.span,
- "try using it unqualified",
+ "try importing it and using it unqualified",
t,
// The import probably needs to be changed
Applicability::MaybeIncorrect,
@@ -131,26 +178,6 @@
}
}
}
- TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
- if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
- if cx.tcx.impl_trait_ref(impl_did).is_some() {
- return;
- }
- }
- if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
- cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| {
- lint.build(&format!("passing `{}` by reference", t))
- .span_suggestion(
- ty.span,
- "try passing by value",
- t,
- // Changing type of function argument
- Applicability::MaybeIncorrect,
- )
- .emit();
- })
- }
- }
_ => {}
}
}
@@ -175,7 +202,7 @@
}
}
// Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
- Res::SelfTy(None, Some((did, _))) => {
+ Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
if let Some(name @ (sym::Ty | sym::TyCtxt)) =
cx.tcx.get_diagnostic_name(adt.did)
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 773e575..0ce760b 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -21,7 +21,7 @@
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit as hir_visit;
use rustc_hir::intravisit::Visitor;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::LintPass;
use rustc_span::symbol::Symbol;
@@ -94,13 +94,13 @@
}
impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPass<'tcx, T> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
/// Because lints are scoped lexically, we want to walk nested
/// items in the context of the outer item, so enable
/// deep-walking.
- fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
- hir_visit::NestedVisitorMap::All(self.context.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.context.tcx.hir()
}
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index d3fa086..8afbd46 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -5,8 +5,8 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
-use rustc_hir::{intravisit, HirId, CRATE_HIR_ID};
-use rustc_middle::hir::map::Map;
+use rustc_hir::{intravisit, HirId};
+use rustc_middle::hir::nested_filter;
use rustc_middle::lint::LevelAndSource;
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::lint::{
@@ -14,7 +14,7 @@
COMMAND_LINE,
};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS},
Level, Lint, LintId,
@@ -27,14 +27,14 @@
fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
let store = unerased_lint_store(tcx);
- let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
- let levels = LintLevelsBuilder::new(tcx.sess, false, &store, crate_attrs);
- let mut builder = LintLevelMapBuilder { levels, tcx, store };
+ let levels =
+ LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools);
+ let mut builder = LintLevelMapBuilder { levels, tcx };
let krate = tcx.hir().krate();
builder.levels.id_to_set.reserve(krate.owners.len() + 1);
- let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true);
+ let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true);
builder.levels.register_id(hir::CRATE_HIR_ID);
tcx.hir().walk_toplevel_module(&mut builder);
builder.levels.pop(push);
@@ -49,7 +49,7 @@
cur: LintStackIndex,
warn_about_weird_lints: bool,
store: &'s LintStore,
- crate_attrs: &'s [ast::Attribute],
+ registered_tools: &'s RegisteredTools,
}
pub struct BuilderPush {
@@ -62,7 +62,7 @@
sess: &'s Session,
warn_about_weird_lints: bool,
store: &'s LintStore,
- crate_attrs: &'s [ast::Attribute],
+ registered_tools: &'s RegisteredTools,
) -> Self {
let mut builder = LintLevelsBuilder {
sess,
@@ -71,19 +71,27 @@
id_to_set: Default::default(),
warn_about_weird_lints,
store,
- crate_attrs,
+ registered_tools,
};
builder.process_command_line(sess, store);
assert_eq!(builder.sets.list.len(), 1);
builder
}
+ pub(crate) fn sess(&self) -> &Session {
+ self.sess
+ }
+
+ pub(crate) fn lint_store(&self) -> &LintStore {
+ self.store
+ }
+
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
let mut specs = FxHashMap::default();
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
for &(ref lint_name, level) in &sess.opts.lint_opts {
- store.check_lint_name_cmdline(sess, &lint_name, level, self.crate_attrs);
+ store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
let orig_level = level;
let lint_flag_val = Symbol::intern(lint_name);
@@ -217,12 +225,7 @@
/// `#[allow]`
///
/// Don't forget to call `pop`!
- pub(crate) fn push(
- &mut self,
- attrs: &[ast::Attribute],
- store: &LintStore,
- is_crate_node: bool,
- ) -> BuilderPush {
+ pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
let mut specs = FxHashMap::default();
let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
@@ -310,7 +313,8 @@
};
let tool_name = tool_ident.map(|ident| ident.name);
let name = pprust::path_to_string(&meta_item.path);
- let lint_result = store.check_lint_name(sess, &name, tool_name, self.crate_attrs);
+ let lint_result =
+ self.store.check_lint_name(&name, tool_name, self.registered_tools);
match &lint_result {
CheckLintNameResult::Ok(ids) => {
let src = LintLevelSource::Node(
@@ -459,7 +463,7 @@
// Ignore any errors or warnings that happen because the new name is inaccurate
// NOTE: `new_name` already includes the tool name, so we don't have to add it again.
if let CheckLintNameResult::Ok(ids) =
- store.check_lint_name(sess, &new_name, None, self.crate_attrs)
+ self.store.check_lint_name(&new_name, None, self.registered_tools)
{
let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
for &id in ids {
@@ -562,34 +566,19 @@
}
}
-pub fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool {
- if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) {
- return true;
- }
- // Look for registered tools
- // 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())
- .flatten()
- .filter_map(|nested_meta| nested_meta.ident())
- .map(|ident| ident.name)
- .any(|name| name == m_item)
-}
-
-struct LintLevelMapBuilder<'a, 'tcx> {
+struct LintLevelMapBuilder<'tcx> {
levels: LintLevelsBuilder<'tcx>,
tcx: TyCtxt<'tcx>,
- store: &'a LintStore,
}
-impl LintLevelMapBuilder<'_, '_> {
+impl LintLevelMapBuilder<'_> {
fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
where
F: FnOnce(&mut Self),
{
let is_crate_hir = id == hir::CRATE_HIR_ID;
let attrs = self.tcx.hir().attrs(id);
- let push = self.levels.push(attrs, self.store, is_crate_hir);
+ let push = self.levels.push(attrs, is_crate_hir);
if push.changed {
self.levels.register_id(id);
}
@@ -598,11 +587,11 @@
}
}
-impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
- type Map = Map<'tcx>;
+impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c782303..69863b5 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -30,12 +30,14 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
#![feature(iter_order_by)]
#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
@@ -56,6 +58,7 @@
mod non_fmt_panic;
mod nonstandard_style;
mod noop_method_call;
+mod pass_by_value;
mod passes;
mod redundant_semicolon;
mod traits;
@@ -85,6 +88,7 @@
use non_fmt_panic::NonPanicFmt;
use nonstandard_style::*;
use noop_method_call::*;
+use pass_by_value::*;
use redundant_semicolon::*;
use traits::*;
use types::*;
@@ -92,8 +96,9 @@
/// Useful for other parts of the compiler / Clippy.
pub use builtin::SoftLints;
-pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
-pub use early::check_ast_crate;
+pub use context::{CheckLintNameResult, FindLintError, LintStore};
+pub use context::{EarlyContext, LateContext, LintContext};
+pub use early::{check_ast_node, EarlyCheckNode};
pub use late::check_crate;
pub use passes::{EarlyLintPass, LateLintPass};
pub use rustc_session::lint::Level::{self, *};
@@ -478,6 +483,11 @@
<https://github.com/rust-lang/rust/issues/59014> for more information",
);
store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
+ store.register_removed(
+ "unsupported_naked_functions",
+ "converted into hard error, see RFC 2972 \
+ <https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md> for more information",
+ );
}
fn register_internals(store: &mut LintStore) {
@@ -485,19 +495,24 @@
store.register_early_pass(|| Box::new(LintPassImpl));
store.register_lints(&DefaultHashTypes::get_lints());
store.register_late_pass(|| Box::new(DefaultHashTypes));
+ store.register_lints(&QueryStability::get_lints());
+ store.register_late_pass(|| Box::new(QueryStability));
store.register_lints(&ExistingDocKeyword::get_lints());
store.register_late_pass(|| Box::new(ExistingDocKeyword));
store.register_lints(&TyTyKind::get_lints());
store.register_late_pass(|| Box::new(TyTyKind));
+ store.register_lints(&PassByValue::get_lints());
+ store.register_late_pass(|| Box::new(PassByValue));
store.register_group(
false,
"rustc::internal",
None,
vec![
LintId::of(DEFAULT_HASH_TYPES),
+ LintId::of(POTENTIAL_QUERY_INSTABILITY),
LintId::of(USAGE_OF_TY_TYKIND),
+ LintId::of(PASS_BY_VALUE),
LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
- LintId::of(TY_PASS_BY_REFERENCE),
LintId::of(USAGE_OF_QUALIFIED_TY),
LintId::of(EXISTING_DOC_KEYWORD),
],
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index 5558947..ae93683 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -44,7 +44,7 @@
fn first_method_call<'tcx>(
expr: &'tcx Expr<'tcx>,
) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> {
- if let ExprKind::MethodCall(path, _, args, _) = &expr.kind {
+ if let ExprKind::MethodCall(path, args, _) = &expr.kind {
if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) }
} else {
None
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index a570206..2dd6dbd 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -166,7 +166,7 @@
}
let mut has_non_ascii_idents = false;
- let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
+ let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock();
// Sort by `Span` so that error messages make sense with respect to the
// order of identifier locations in the code.
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index f2fee67..3130d57 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -355,5 +355,5 @@
// 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)
+ 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 be7756b..f73388c 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -164,7 +164,7 @@
let has_repr_c = it
.attrs
.iter()
- .any(|attr| attr::find_repr_attrs(&cx.sess, attr).contains(&attr::ReprC));
+ .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC));
if has_repr_c {
return;
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 600504f..39b5b7a 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -40,7 +40,7 @@
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
- let ExprKind::MethodCall(call, _, elements, _) = &expr.kind else {
+ let ExprKind::MethodCall(call, elements, _) = &expr.kind else {
return
};
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
@@ -62,7 +62,7 @@
_ => return,
};
let substs = cx.typeck_results().node_substs(expr.hir_id);
- if substs.definitely_needs_subst(cx.tcx) {
+ if substs.needs_subst() {
// 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/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
new file mode 100644
index 0000000..c47fdc0
--- /dev/null
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -0,0 +1,95 @@
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
+use rustc_middle::ty;
+use rustc_span::symbol::sym;
+
+declare_tool_lint! {
+ /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to
+ /// always be passed by value. This is usually used for types that are thin wrappers around
+ /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which
+ /// is a reference to an `Interned<TyS>`)
+ pub rustc::PASS_BY_VALUE,
+ Warn,
+ "pass by reference of a type flagged as `#[rustc_pass_by_value]`",
+ report_in_external_macro: true
+}
+
+declare_lint_pass!(PassByValue => [PASS_BY_VALUE]);
+
+impl<'tcx> LateLintPass<'tcx> for PassByValue {
+ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
+ match &ty.kind {
+ TyKind::Rptr(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
+ if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
+ if cx.tcx.impl_trait_ref(impl_did).is_some() {
+ return;
+ }
+ }
+ if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
+ cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
+ lint.build(&format!("passing `{}` by reference", t))
+ .span_suggestion(
+ ty.span,
+ "try passing by value",
+ t,
+ // Changing type of function argument
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ })
+ }
+ }
+ _ => {}
+ }
+ }
+}
+
+fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> {
+ if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
+ match path.res {
+ Res::Def(_, def_id) if cx.tcx.has_attr(def_id, sym::rustc_pass_by_value) => {
+ let name = cx.tcx.item_name(def_id).to_ident_string();
+ let path_segment = path.segments.last().unwrap();
+ return Some(format!("{}{}", name, gen_args(cx, path_segment)));
+ }
+ Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+ if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+ if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) {
+ return Some(cx.tcx.def_path_str_with_substs(adt.did, substs));
+ }
+ }
+ }
+ _ => (),
+ }
+ }
+
+ None
+}
+
+fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
+ if let Some(args) = &segment.args {
+ let params = args
+ .args
+ .iter()
+ .map(|arg| match arg {
+ GenericArg::Lifetime(lt) => lt.name.ident().to_string(),
+ GenericArg::Type(ty) => {
+ cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
+ }
+ GenericArg::Const(c) => {
+ cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into())
+ }
+ GenericArg::Infer(_) => String::from("_"),
+ })
+ .collect::<Vec<_>>();
+
+ if !params.is_empty() {
+ return format!("<{}>", params.join(", "));
+ }
+ }
+
+ String::new()
+}
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index dafff64..4c7f348 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -86,7 +86,6 @@
impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
- use rustc_middle::ty;
use rustc_middle::ty::PredicateKind::*;
let predicates = cx.tcx.explicit_predicates_of(item.def_id);
@@ -94,7 +93,7 @@
let Trait(trait_predicate) = predicate.kind().skip_binder() else {
continue
};
- if trait_predicate.constness == ty::BoundConstness::ConstIfConst {
+ if trait_predicate.is_const_if_const() {
// `~const Drop` definitely have meanings so avoid linting here.
continue;
}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 32ed6da..fc88e8c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -249,7 +249,7 @@
));
}
if let Some(sugg_ty) =
- get_type_suggestion(&cx.typeck_results().node_type(expr.hir_id), val, negative)
+ get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
{
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
@@ -367,7 +367,7 @@
max,
));
if let Some(sugg_ty) =
- get_type_suggestion(&cx.typeck_results().node_type(e.hir_id), v, negative)
+ get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
{
err.help(&format!("consider using the type `{}` instead", sugg_ty));
}
@@ -1095,7 +1095,7 @@
}
}
for arg in sig.inputs() {
- let r = self.check_type_for_ffi(cache, arg);
+ let r = self.check_type_for_ffi(cache, *arg);
match r {
FfiSafe => {}
_ => {
@@ -1175,9 +1175,6 @@
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() {
@@ -1260,7 +1257,7 @@
let sig = self.cx.tcx.erase_late_bound_regions(sig);
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
- self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false);
+ self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false);
}
if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
@@ -1467,7 +1464,7 @@
sym::AtomicI128,
];
if_chain! {
- if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
+ 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);
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 6b89fd6..adec1a3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1793,6 +1793,10 @@
Warn,
"detects name collision with an existing but unstable method",
@future_incompatible = FutureIncompatibleInfo {
+ reason: FutureIncompatibilityReason::Custom(
+ "once this associated item is added to the standard library, \
+ the ambiguity may cause an error or change in behavior!"
+ ),
reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>",
// Note: this item represents future incompatibility of all unstable functions in the
// standard library, and thus should never be removed or changed to an error.
@@ -1805,7 +1809,7 @@
///
/// ### Example
///
- /// ```
+ /// ```rust
/// if let _ = 123 {
/// println!("always runs!");
/// }
@@ -2335,6 +2339,10 @@
Warn,
"reservation of a two-phased borrow conflicts with other shared borrows",
@future_incompatible = FutureIncompatibleInfo {
+ reason: FutureIncompatibilityReason::Custom(
+ "this borrowing pattern was not meant to be accepted, \
+ and may become a hard error in the future"
+ ),
reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>",
};
}
@@ -2431,7 +2439,19 @@
/// }
/// ```
///
- /// {{produces}}
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: formatting may not be suitable for sub-register argument
+ /// --> src/main.rs:7:19
+ /// |
+ /// 7 | asm!("mov {0}, {0}", in(reg) 0i16);
+ /// | ^^^ ^^^ ---- for this argument
+ /// |
+ /// = note: `#[warn(asm_sub_register)]` on by default
+ /// = help: use the `x` modifier to have the register formatted as `ax`
+ /// = help: or use the `r` modifier to keep the default formatting of `rax`
+ /// ```
///
/// ### Explanation
///
@@ -2474,7 +2494,17 @@
/// }
/// ```
///
- /// {{produces}}
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
+ /// --> src/main.rs:8:14
+ /// |
+ /// 8 | ".att_syntax",
+ /// | ^^^^^^^^^^^
+ /// |
+ /// = note: `#[warn(bad_asm_style)]` on by default
+ /// ```
///
/// ### Explanation
///
@@ -2742,57 +2772,11 @@
}
declare_lint! {
- /// The `unsupported_naked_functions` lint detects naked function
- /// definitions that are unsupported but were previously accepted.
- ///
- /// ### Example
- ///
- /// ```rust
- /// #![feature(naked_functions)]
- ///
- /// #[naked]
- /// pub extern "C" fn f() -> u32 {
- /// 42
- /// }
- /// ```
- ///
- /// {{produces}}
- ///
- /// ### Explanation
- ///
- /// The naked functions must be defined using a single inline assembly
- /// block.
- ///
- /// The execution must never fall through past the end of the assembly
- /// code so the block must use `noreturn` option. The asm block can also
- /// use `att_syntax` option, but other options are not allowed.
- ///
- /// 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
- /// the future.
- ///
- /// [future-incompatible]: ../index.md#future-incompatible-lints
- pub UNSUPPORTED_NAKED_FUNCTIONS,
- Warn,
- "unsupported naked function definitions",
- @future_incompatible = FutureIncompatibleInfo {
- reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
- };
-}
-
-declare_lint! {
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
///
/// ### Example
///
- /// ```compile_fail
+ /// ```rust,compile_fail
/// #![feature(staged_api)]
///
/// #[derive(Clone)]
@@ -2973,6 +2957,43 @@
};
}
+declare_lint! {
+ /// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions.
+ ///
+ /// ### Example
+ ///
+ /// ```text
+ /// rustc --check-cfg 'names()'
+ /// ```
+ ///
+ /// ```rust,ignore (needs command line option)
+ /// #[cfg(widnows)]
+ /// fn foo() {}
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: unknown condition name used
+ /// --> lint_example.rs:1:7
+ /// |
+ /// 1 | #[cfg(widnows)]
+ /// | ^^^^^^^
+ /// |
+ /// = note: `#[warn(unexpected_cfgs)]` on by default
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// This lint is only active when a `--check-cfg='names(...)'` option has been passed
+ /// to the compiler and triggers whenever an unknown condition name or value is used.
+ /// The known condition include names or values passed in `--check-cfg`, `--cfg`, and some
+ /// well-knows names and values built into the compiler.
+ pub UNEXPECTED_CFGS,
+ Warn,
+ "detects unexpected names and values in `#[cfg]` conditions",
+}
+
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@@ -3052,7 +3073,6 @@
UNINHABITED_STATIC,
FUNCTION_ITEM_REFERENCES,
USELESS_DEPRECATED,
- UNSUPPORTED_NAKED_FUNCTIONS,
MISSING_ABI,
INVALID_DOC_ATTRIBUTES,
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -3071,6 +3091,8 @@
DEREF_INTO_DYN_SUPERTRAIT,
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
DUPLICATE_MACRO_ATTRIBUTES,
+ SUSPICIOUS_AUTO_TRAIT_IMPLS,
+ UNEXPECTED_CFGS,
]
}
@@ -3622,7 +3644,17 @@
/// fn foo() {}
/// ```
///
- /// {{produces}}
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: duplicated attribute
+ /// --> src/lib.rs:2:1
+ /// |
+ /// 2 | #[test]
+ /// | ^^^^^^^
+ /// |
+ /// = note: `#[warn(duplicate_macro_attributes)]` on by default
+ /// ```
///
/// ### Explanation
///
@@ -3637,3 +3669,37 @@
Warn,
"duplicated attribute"
}
+
+declare_lint! {
+ /// The `suspicious_auto_trait_impls` lint checks for potentially incorrect
+ /// implementations of auto traits.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// struct Foo<T>(T);
+ ///
+ /// unsafe impl<T> Send for Foo<*const T> {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A type can implement auto traits, e.g. `Send`, `Sync` and `Unpin`,
+ /// in two different ways: either by writing an explicit impl or if
+ /// all fields of the type implement that auto trait.
+ ///
+ /// The compiler disables the automatic implementation if an explicit one
+ /// exists for given type constructor. The exact rules governing this
+ /// are currently unsound and quite subtle and and will be modified in the future.
+ /// This change will cause the automatic implementation to be disabled in more
+ /// cases, potentially breaking some code.
+ pub SUSPICIOUS_AUTO_TRAIT_IMPLS,
+ Warn,
+ "the rules governing auto traits will change in the future",
+ @future_incompatible = FutureIncompatibleInfo {
+ reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
+ reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>",
+ };
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 97f6df5..1f834b7 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -163,12 +163,17 @@
/// This will be an error in a future release, and
/// Cargo should create a report even for dependencies
FutureReleaseErrorReportNow,
+ /// Code that changes meaning in some way in a
+ /// future release.
+ FutureReleaseSemanticsChange,
/// Previously accepted code that will become an
/// error in the provided edition
EditionError(Edition),
/// Code that changes meaning in some way in
/// the provided edition
EditionSemanticsChange(Edition),
+ /// A custom reason.
+ Custom(&'static str),
}
impl FutureIncompatibilityReason {
@@ -282,7 +287,7 @@
// This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated).
-#[derive(PartialEq, Debug)]
+#[derive(Debug)]
pub enum BuiltinLintDiagnostics {
Normal,
AbsPathWithModule(Span),
@@ -309,7 +314,6 @@
/// Lints that are buffered up early on in the `Session` before the
/// `LintLevels` is calculated.
-#[derive(PartialEq)]
pub struct BufferedEarlyLint {
/// The span of code that we are linting on.
pub span: MultiSpan,
@@ -336,9 +340,7 @@
impl LintBuffer {
pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
let arr = self.map.entry(early_lint.node_id).or_default();
- if !arr.contains(&early_lint) {
- arr.push(early_lint);
- }
+ arr.push(early_lint);
}
pub fn add_lint(
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index e2ce7da..a2b0e9b 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -82,6 +82,8 @@
StackProtectReq = 30,
StackProtectStrong = 31,
StackProtect = 32,
+ NoUndef = 33,
+ SanitizeMemTag = 34,
};
typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index f06fc3e..7030fd5 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1168,25 +1168,6 @@
passes.run(*unwrap(M));
}
-extern "C" void LLVMRustMarkAllFunctionsNounwind(LLVMModuleRef M) {
- for (Module::iterator GV = unwrap(M)->begin(), E = unwrap(M)->end(); GV != E;
- ++GV) {
- GV->setDoesNotThrow();
- Function *F = dyn_cast<Function>(GV);
- if (F == nullptr)
- continue;
-
- for (Function::iterator B = F->begin(), BE = F->end(); B != BE; ++B) {
- for (BasicBlock::iterator I = B->begin(), IE = B->end(); I != IE; ++I) {
- if (isa<InvokeInst>(I)) {
- InvokeInst *CI = cast<InvokeInst>(I);
- CI->setDoesNotThrow();
- }
- }
- }
- }
-}
-
extern "C" void
LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
LLVMTargetMachineRef TMR) {
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index c21e4ac..c8f31ad 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -76,6 +76,10 @@
install_fatal_error_handler(FatalErrorHandler);
}
+extern "C" void LLVMRustDisableSystemDialogsOnCrash() {
+ sys::DisableSystemDialogsOnCrash();
+}
+
extern "C" char *LLVMRustGetLastError(void) {
char *Ret = LastError;
LastError = nullptr;
@@ -220,6 +224,10 @@
return Attribute::StackProtectStrong;
case StackProtect:
return Attribute::StackProtect;
+ case NoUndef:
+ return Attribute::NoUndef;
+ case SanitizeMemTag:
+ return Attribute::SanitizeMemTag;
}
report_fatal_error("bad AttributeKind");
}
@@ -328,6 +336,17 @@
AddAttribute(F, Index, Attr);
}
+extern "C" void LLVMRustEmitUWTableAttr(LLVMValueRef Fn, bool Async) {
+ Function *F = unwrap<Function>(Fn);
+#if LLVM_VERSION_LT(15, 0)
+ Attribute Attr = Attribute::get(F->getContext(), Attribute::UWTable);
+#else
+ Attribute Attr = Attribute::getWithUWTableKind(
+ F->getContext(), Async ? UWTableKind::Async : UWTableKind::Sync);
+#endif
+ AddAttribute(F, AttributeList::AttrIndex::FunctionIndex, Attr);
+}
+
extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
unsigned Index,
const char *Name,
@@ -722,9 +741,12 @@
#endif
}
-extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name,
- uint32_t Value) {
- unwrap(M)->addModuleFlag(Module::Warning, Name, Value);
+extern "C" void LLVMRustAddModuleFlag(
+ LLVMModuleRef M,
+ Module::ModFlagBehavior MergeBehavior,
+ const char *Name,
+ uint32_t Value) {
+ unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
}
extern "C" LLVMValueRef LLVMRustMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD) {
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 3351564..6c54615 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -47,7 +47,7 @@
quote! {
::rustc_serialize::Decoder::read_struct(
__decoder,
- |__decoder| { ::std::result::Result::Ok(#construct) },
+ |__decoder| { #construct },
)
}
}
@@ -57,7 +57,7 @@
.enumerate()
.map(|(idx, vi)| {
let construct = vi.construct(|field, index| decode_field(field, index, false));
- quote! { #idx => { ::std::result::Result::Ok(#construct) } }
+ quote! { #idx => { #construct } }
})
.collect();
let names: TokenStream = variants
@@ -82,8 +82,7 @@
|__decoder, __variant_idx| {
match __variant_idx {
#match_inner
- _ => return ::std::result::Result::Err(
- ::rustc_serialize::Decoder::error(__decoder, #message)),
+ _ => panic!(#message),
}
})
}
@@ -95,9 +94,7 @@
s.bound_impl(
quote!(::rustc_serialize::Decodable<#decoder_ty>),
quote! {
- fn decode(
- __decoder: &mut #decoder_ty,
- ) -> ::std::result::Result<Self, <#decoder_ty as ::rustc_serialize::Decoder>::Error> {
+ fn decode(__decoder: &mut #decoder_ty) -> Self {
#decode_body
}
},
@@ -127,12 +124,7 @@
#__decoder, #opt_field_name #decode_inner_method)
};
- quote! {
- match #decode_call {
- ::std::result::Result::Ok(__res) => __res,
- ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
- }
- }
+ quote! { #decode_call }
}
pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 918c3b9..0462450 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -9,6 +9,7 @@
#![feature(try_blocks)]
#![feature(never_type)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
extern crate proc_macro;
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 13ea089..550b22a 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -223,7 +223,7 @@
use rustc_errors::{struct_span_err, FatalError};
use rustc_session::config::{self, CrateType};
use rustc_session::cstore::{CrateSource, MetadataLoader};
-use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
+use rustc_session::filesearch::FileSearch;
use rustc_session::search_paths::PathKind;
use rustc_session::utils::CanonicalizedPath;
use rustc_session::Session;
@@ -371,15 +371,20 @@
extra_prefix: &str,
seen_paths: &mut FxHashSet<PathBuf>,
) -> Result<Option<Library>, CrateError> {
- // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
- let dylib_prefix = format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
- let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
+ let rmeta_prefix = &format!("lib{}{}", self.crate_name, extra_prefix);
+ let rlib_prefix = rmeta_prefix;
+ let dylib_prefix =
+ &format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
let staticlib_prefix =
- format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
+ &format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
+
+ let rmeta_suffix = ".rmeta";
+ let rlib_suffix = ".rlib";
+ let dylib_suffix = &self.target.dll_suffix;
+ let staticlib_suffix = &self.target.staticlib_suffix;
let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
Default::default();
- let mut staticlibs = vec![];
// First, find all possible candidate rlibs and dylibs purely based on
// the name of the files themselves. We're trying to match against an
@@ -394,46 +399,50 @@
// of the crate id (path/name/id).
//
// The goal of this step is to look at as little metadata as possible.
- self.filesearch.search(|spf, kind| {
- let file = match &spf.file_name_str {
- None => return FileDoesntMatch,
- Some(file) => file,
- };
- let (hash, found_kind) = if file.starts_with(&rlib_prefix) && file.ends_with(".rlib") {
- (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
- } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
- (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
- } else if file.starts_with(&dylib_prefix) && file.ends_with(&self.target.dll_suffix) {
- (
- &file[(dylib_prefix.len())..(file.len() - self.target.dll_suffix.len())],
- CrateFlavor::Dylib,
- )
- } else {
- if file.starts_with(&staticlib_prefix)
- && file.ends_with(&self.target.staticlib_suffix)
- {
- staticlibs
- .push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() });
- }
- return FileDoesntMatch;
- };
+ // Unfortunately, the prefix-based matching sometimes is over-eager.
+ // E.g. if `rlib_suffix` is `libstd` it'll match the file
+ // `libstd_detect-8d6701fb958915ad.rlib` (incorrect) as well as
+ // `libstd-f3ab5b1dea981f17.rlib` (correct). But this is hard to avoid
+ // given that `extra_filename` comes from the `-C extra-filename`
+ // option and thus can be anything, and the incorrect match will be
+ // handled safely in `extract_one`.
+ for search_path in self.filesearch.search_paths() {
+ debug!("searching {}", search_path.dir.display());
+ for spf in search_path.files.iter() {
+ debug!("testing {}", spf.path.display());
- info!("lib candidate: {}", spf.path.display());
+ let f = &spf.file_name_str;
+ let (hash, kind) = if f.starts_with(rlib_prefix) && f.ends_with(rlib_suffix) {
+ (&f[rlib_prefix.len()..(f.len() - rlib_suffix.len())], CrateFlavor::Rlib)
+ } else if f.starts_with(rmeta_prefix) && f.ends_with(rmeta_suffix) {
+ (&f[rmeta_prefix.len()..(f.len() - rmeta_suffix.len())], CrateFlavor::Rmeta)
+ } else if f.starts_with(dylib_prefix) && f.ends_with(dylib_suffix) {
+ (&f[dylib_prefix.len()..(f.len() - dylib_suffix.len())], CrateFlavor::Dylib)
+ } else {
+ if f.starts_with(staticlib_prefix) && f.ends_with(staticlib_suffix) {
+ self.crate_rejections.via_kind.push(CrateMismatch {
+ path: spf.path.clone(),
+ got: "static".to_string(),
+ });
+ }
+ continue;
+ };
- let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
- let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
- if seen_paths.contains(&path) {
- return FileDoesntMatch;
- };
- seen_paths.insert(path.clone());
- match found_kind {
- CrateFlavor::Rlib => rlibs.insert(path, kind),
- CrateFlavor::Rmeta => rmetas.insert(path, kind),
- CrateFlavor::Dylib => dylibs.insert(path, kind),
- };
- FileMatches
- });
- self.crate_rejections.via_kind.extend(staticlibs);
+ info!("lib candidate: {}", spf.path.display());
+
+ let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
+ let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
+ if seen_paths.contains(&path) {
+ continue;
+ };
+ seen_paths.insert(path.clone());
+ match kind {
+ CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
+ CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
+ CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
+ };
+ }
+ }
// We have now collected all known libraries into a set of candidates
// keyed of the filename hash listed. For each filename, we also have a
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 639d2e6..88292a4 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -274,11 +274,6 @@
span,
"`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
);
- } else if !self.tcx.sess.target.options.is_like_msvc {
- self.tcx.sess.span_warn(
- span,
- "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu",
- );
}
if lib_name.as_str().contains('\0') {
@@ -409,11 +404,13 @@
fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
let calling_convention = if self.tcx.sess.target.arch == "x86" {
match abi {
- Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C,
+ Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
Abi::Stdcall { .. } | Abi::System { .. } => {
DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
}
- Abi::Fastcall => DllCallingConvention::Fastcall(self.i686_arg_list_size(item)),
+ Abi::Fastcall { .. } => {
+ DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
+ }
// Vectorcall is intentionally not supported at this time.
_ => {
self.tcx.sess.span_fatal(
@@ -424,7 +421,7 @@
}
} else {
match abi {
- Abi::C { .. } | Abi::Win64 | Abi::System { .. } => DllCallingConvention::C,
+ Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
_ => {
self.tcx.sess.span_fatal(
item.span,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index bb9a58a..66968c9 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -21,7 +21,7 @@
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::lang_items;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::mir::{self, Body, Promoted};
@@ -120,7 +120,7 @@
/// How to link (or not link) this crate to the currently compiled crate.
dep_kind: Lock<CrateDepKind>,
/// Filesystem location of this crate.
- source: CrateSource,
+ source: Lrc<CrateSource>,
/// Whether or not this crate should be consider a private dependency
/// for purposes of the 'exported_private_dependencies' lint
private_dep: bool,
@@ -218,40 +218,40 @@
}
}
-impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> {
+impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> {
#[inline]
fn blob(self) -> &'a MetadataBlob {
- &self.blob
+ &self.cdata.blob
}
#[inline]
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
- Some(*self)
+ Some(self)
}
}
-impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) {
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) {
#[inline]
fn blob(self) -> &'a MetadataBlob {
- &self.0.blob
+ &self.0.cdata.blob
}
#[inline]
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
- Some(*self.0)
+ Some(self.0)
}
#[inline]
fn sess(self) -> Option<&'tcx Session> {
- Some(&self.1)
+ Some(self.1)
}
}
-impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) {
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) {
#[inline]
fn blob(self) -> &'a MetadataBlob {
- &self.0.blob
+ &self.0.cdata.blob
}
#[inline]
fn cdata(self) -> Option<CrateMetadataRef<'a>> {
- Some(*self.0)
+ Some(self.0)
}
#[inline]
fn tcx(self) -> Option<TyCtxt<'tcx>> {
@@ -263,7 +263,7 @@
fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
let mut dcx = metadata.decoder(self.position.get());
dcx.lazy_state = LazyState::NodeStart(self.position);
- T::decode(&mut dcx).unwrap()
+ T::decode(&mut dcx)
}
}
@@ -274,7 +274,7 @@
) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
let mut dcx = metadata.decoder(self.position.get());
dcx.lazy_state = LazyState::NodeStart(self.position);
- (0..self.meta).map(move |_| T::decode(&mut dcx).unwrap())
+ (0..self.meta).map(move |_| T::decode(&mut dcx))
}
}
@@ -300,23 +300,19 @@
if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
}
- fn read_lazy_with_meta<T: ?Sized + LazyMeta>(
- &mut self,
- meta: T::Meta,
- ) -> Result<Lazy<T>, <Self as Decoder>::Error> {
- let min_size = T::min_size(meta);
- let distance = self.read_usize()?;
+ fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> {
+ let distance = self.read_usize();
let position = match self.lazy_state {
LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
LazyState::NodeStart(start) => {
let start = start.get();
- assert!(distance + min_size <= start);
- start - distance - min_size
+ assert!(distance <= start);
+ start - distance
}
- LazyState::Previous(last_min_end) => last_min_end.get() + distance,
+ LazyState::Previous(last_pos) => last_pos.get() + distance,
};
- self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
- Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
+ self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap());
+ Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta)
}
#[inline]
@@ -343,25 +339,21 @@
self.opaque.position()
}
- fn cached_ty_for_shorthand<F>(
- &mut self,
- shorthand: usize,
- or_insert_with: F,
- ) -> Result<Ty<'tcx>, Self::Error>
+ fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
where
- F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>,
+ F: FnOnce(&mut Self) -> Ty<'tcx>,
{
let tcx = self.tcx();
let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
- return Ok(ty);
+ return ty;
}
- let ty = or_insert_with(self)?;
+ let ty = or_insert_with(self);
tcx.ty_rcache.borrow_mut().insert(key, ty);
- Ok(ty)
+ ty
}
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
@@ -377,7 +369,7 @@
r
}
- fn decode_alloc_id(&mut self) -> Result<rustc_middle::mir::interpret::AllocId, Self::Error> {
+ fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId {
if let Some(alloc_decoding_session) = self.alloc_decoding_session {
alloc_decoding_session.decode_alloc_id(self)
} else {
@@ -387,48 +379,48 @@
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for CrateNum {
- fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<CrateNum, String> {
- let cnum = CrateNum::from_u32(d.read_u32()?);
- Ok(d.map_encoded_cnum_to_current(cnum))
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> CrateNum {
+ let cnum = CrateNum::from_u32(d.read_u32());
+ d.map_encoded_cnum_to_current(cnum)
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex {
- fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefIndex, String> {
- Ok(DefIndex::from_u32(d.read_u32()?))
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefIndex {
+ DefIndex::from_u32(d.read_u32())
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex {
- fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnIndex, String> {
- Ok(ExpnIndex::from_u32(d.read_u32()?))
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex {
+ ExpnIndex::from_u32(d.read_u32())
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
- fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String> {
+ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext {
let cdata = decoder.cdata();
let sess = decoder.sess.unwrap();
let cname = cdata.root.name;
rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| {
debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
- Ok(cdata
+ cdata
.root
.syntax_contexts
- .get(&cdata, id)
+ .get(cdata, id)
.unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
- .decode((&cdata, sess)))
+ .decode((cdata, sess))
})
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
- fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnId, String> {
+ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId {
let local_cdata = decoder.cdata();
let sess = decoder.sess.unwrap();
- let cnum = CrateNum::decode(decoder)?;
- let index = u32::decode(decoder)?;
+ let cnum = CrateNum::decode(decoder);
+ let index = u32::decode(decoder);
let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| {
let ExpnId { krate: cnum, local_id: index } = expn_id;
@@ -443,34 +435,34 @@
let expn_data = crate_data
.root
.expn_data
- .get(&crate_data, index)
+ .get(crate_data, index)
.unwrap()
- .decode((&crate_data, sess));
+ .decode((crate_data, sess));
let expn_hash = crate_data
.root
.expn_hashes
- .get(&crate_data, index)
+ .get(crate_data, index)
.unwrap()
- .decode((&crate_data, sess));
+ .decode((crate_data, sess));
(expn_data, expn_hash)
});
- Ok(expn_id)
+ expn_id
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
- fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Span, String> {
- let ctxt = SyntaxContext::decode(decoder)?;
- let tag = u8::decode(decoder)?;
+ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span {
+ let ctxt = SyntaxContext::decode(decoder);
+ let tag = u8::decode(decoder);
if tag == TAG_PARTIAL_SPAN {
- return Ok(DUMMY_SP.with_ctxt(ctxt));
+ return DUMMY_SP.with_ctxt(ctxt);
}
debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN);
- let lo = BytePos::decode(decoder)?;
- let len = BytePos::decode(decoder)?;
+ let lo = BytePos::decode(decoder);
+ let len = BytePos::decode(decoder);
let hi = lo + len;
let Some(sess) = decoder.sess else {
@@ -513,7 +505,7 @@
if decoder.cdata().root.is_proc_macro_crate() {
// Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE
// since we don't have `cnum_map` populated.
- let cnum = u32::decode(decoder)?;
+ let cnum = u32::decode(decoder);
panic!(
"Decoding of crate {:?} tried to access proc-macro dep {:?}",
decoder.cdata().root.name,
@@ -521,7 +513,7 @@
);
}
// tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above
- let cnum = CrateNum::decode(decoder)?;
+ let cnum = CrateNum::decode(decoder);
debug!(
"SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}",
cnum
@@ -583,18 +575,18 @@
(hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos;
// Do not try to decode parent for foreign spans.
- Ok(Span::new(lo, hi, ctxt, None))
+ Span::new(lo, hi, ctxt, None)
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
- fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
ty::codec::RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
- fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
ty::codec::RefDecodable::decode(d)
}
}
@@ -602,7 +594,7 @@
impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
for Lazy<T>
{
- fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
decoder.read_lazy_with_meta(())
}
}
@@ -610,9 +602,9 @@
impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
for Lazy<[T]>
{
- fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
- let len = decoder.read_usize()?;
- if len == 0 { Ok(Lazy::empty()) } else { decoder.read_lazy_with_meta(len) }
+ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
+ let len = decoder.read_usize();
+ if len == 0 { Lazy::empty() } else { decoder.read_lazy_with_meta(len) }
}
}
@@ -621,8 +613,8 @@
where
Option<T>: FixedSizeEncoding,
{
- fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
- let len = decoder.read_usize()?;
+ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
+ let len = decoder.read_usize();
decoder.read_lazy_with_meta(len)
}
}
@@ -707,7 +699,7 @@
}
impl<'a, 'tcx> CrateMetadataRef<'a> {
- fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
+ fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
// with items in 'raw_proc_macros'.
let pos = self
@@ -722,7 +714,7 @@
&self.raw_proc_macros.unwrap()[pos]
}
- fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
+ fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?;
let span = match self.root.tables.ident_span.get(self, item_index) {
Some(lazy_span) => lazy_span.decode((self, sess)),
@@ -738,15 +730,15 @@
Some(Ident::new(name, span))
}
- fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
+ fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident {
self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
}
- fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
+ fn maybe_kind(self, item_id: DefIndex) -> Option<EntryKind> {
self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
}
- fn kind(&self, item_id: DefIndex) -> EntryKind {
+ fn kind(self, item_id: DefIndex) -> EntryKind {
self.maybe_kind(item_id).unwrap_or_else(|| {
bug!(
"CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
@@ -757,7 +749,7 @@
})
}
- fn def_kind(&self, item_id: DefIndex) -> DefKind {
+ fn def_kind(self, item_id: DefIndex) -> DefKind {
self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| {
bug!(
"CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
@@ -768,7 +760,7 @@
})
}
- fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
+ fn get_span(self, index: DefIndex, sess: &Session) -> Span {
self.root
.tables
.span
@@ -777,7 +769,7 @@
.decode((self, sess))
}
- fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
+ fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension {
let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let helper_attrs =
@@ -808,7 +800,7 @@
)
}
- fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
+ fn get_trait_def(self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
match self.kind(item_id) {
EntryKind::Trait(data) => {
let data = data.decode((self, sess));
@@ -821,6 +813,7 @@
data.skip_array_during_method_dispatch,
data.specialization_kind,
self.def_path_hash(item_id),
+ data.must_implement_one_of,
)
}
EntryKind::TraitAlias => ty::TraitDef::new(
@@ -832,13 +825,14 @@
false,
ty::trait_def::TraitSpecializationKind::None,
self.def_path_hash(item_id),
+ None,
),
_ => bug!("def-index does not refer to trait or trait alias"),
}
}
fn get_variant(
- &self,
+ self,
kind: &EntryKind,
index: DefIndex,
parent_did: DefId,
@@ -863,7 +857,7 @@
let ctor_did = data.ctor.map(|index| self.local_def_id(index));
ty::VariantDef::new(
- self.item_ident(index, sess),
+ self.item_ident(index, sess).name,
variant_did,
ctor_did,
data.discr,
@@ -875,7 +869,7 @@
.decode(self)
.map(|index| ty::FieldDef {
did: self.local_def_id(index),
- ident: self.item_ident(index, sess),
+ name: self.item_ident(index, sess).name,
vis: self.get_visibility(index),
})
.collect(),
@@ -887,7 +881,7 @@
)
}
- fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
+ fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
let kind = self.kind(item_id);
let did = self.local_def_id(item_id);
@@ -915,7 +909,7 @@
}
fn get_explicit_predicates(
- &self,
+ self,
item_id: DefIndex,
tcx: TyCtxt<'tcx>,
) -> ty::GenericPredicates<'tcx> {
@@ -923,7 +917,7 @@
}
fn get_inferred_outlives(
- &self,
+ self,
item_id: DefIndex,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
@@ -936,7 +930,7 @@
}
fn get_super_predicates(
- &self,
+ self,
item_id: DefIndex,
tcx: TyCtxt<'tcx>,
) -> ty::GenericPredicates<'tcx> {
@@ -944,7 +938,7 @@
}
fn get_explicit_item_bounds(
- &self,
+ self,
item_id: DefIndex,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
@@ -956,11 +950,11 @@
.unwrap_or_default()
}
- fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
+ fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
}
- fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ fn get_type(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
self.root
.tables
.ty
@@ -969,59 +963,63 @@
.decode((self, tcx))
}
- fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
+ fn get_stability(self, id: DefIndex) -> Option<attr::Stability> {
self.root.tables.stability.get(self, id).map(|stab| stab.decode(self))
}
- fn get_const_stability(&self, id: DefIndex) -> Option<attr::ConstStability> {
+ fn get_const_stability(self, id: DefIndex) -> Option<attr::ConstStability> {
self.root.tables.const_stability.get(self, id).map(|stab| stab.decode(self))
}
- fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
+ fn get_deprecation(self, id: DefIndex) -> Option<attr::Deprecation> {
self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self))
}
- fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
+ fn get_visibility(self, id: DefIndex) -> ty::Visibility {
self.root.tables.visibility.get(self, id).unwrap().decode(self)
}
- fn get_impl_data(&self, id: DefIndex) -> ImplData {
+ fn get_impl_data(self, id: DefIndex) -> ImplData {
match self.kind(id) {
EntryKind::Impl(data) => data.decode(self),
_ => bug!(),
}
}
- fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
+ fn get_parent_impl(self, id: DefIndex) -> Option<DefId> {
self.get_impl_data(id).parent_impl
}
- fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
+ fn get_impl_polarity(self, id: DefIndex) -> ty::ImplPolarity {
self.get_impl_data(id).polarity
}
- fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
+ fn get_impl_defaultness(self, id: DefIndex) -> hir::Defaultness {
self.get_impl_data(id).defaultness
}
- fn get_impl_constness(&self, id: DefIndex) -> hir::Constness {
+ fn get_impl_constness(self, id: DefIndex) -> hir::Constness {
self.get_impl_data(id).constness
}
- fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
+ fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
+ self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
+ }
+
+ fn get_coerce_unsized_info(self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
self.get_impl_data(id).coerce_unsized_info
}
- fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
+ fn get_impl_trait(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
}
- fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId {
+ fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
}
fn get_const_param_default(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> rustc_middle::ty::Const<'tcx> {
@@ -1029,75 +1027,66 @@
}
/// Iterates over all the stability attributes in the given crate.
- fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
- // FIXME: For a proc macro crate, not sure whether we should return the "host"
- // features or an empty Vec. Both don't cause ICEs.
+ fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
tcx.arena.alloc_from_iter(self.root.lib_features.decode(self))
}
/// Iterates over the language items in the given crate.
- fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
- if self.root.is_proc_macro_crate() {
- // Proc macro crates do not export any lang-items to the target.
- &[]
- } else {
- tcx.arena.alloc_from_iter(
- self.root
- .lang_items
- .decode(self)
- .map(|(def_index, index)| (self.local_def_id(def_index), index)),
- )
- }
+ fn get_lang_items(self) -> impl Iterator<Item = (DefId, usize)> + 'a {
+ self.root
+ .lang_items
+ .decode(self)
+ .map(move |(def_index, index)| (self.local_def_id(def_index), index))
}
/// Iterates over the diagnostic items in the given crate.
- fn get_diagnostic_items(&self) -> DiagnosticItems {
- if self.root.is_proc_macro_crate() {
- // Proc macro crates do not export any diagnostic-items to the target.
- Default::default()
- } else {
- let mut id_to_name = FxHashMap::default();
- let name_to_id = self
- .root
- .diagnostic_items
- .decode(self)
- .map(|(name, def_index)| {
- let id = self.local_def_id(def_index);
- id_to_name.insert(id, name);
- (name, id)
- })
- .collect();
- DiagnosticItems { id_to_name, name_to_id }
- }
+ fn get_diagnostic_items(self) -> DiagnosticItems {
+ let mut id_to_name = FxHashMap::default();
+ let name_to_id = self
+ .root
+ .diagnostic_items
+ .decode(self)
+ .map(|(name, def_index)| {
+ let id = self.local_def_id(def_index);
+ id_to_name.insert(id, name);
+ (name, id)
+ })
+ .collect();
+ DiagnosticItems { id_to_name, name_to_id }
}
- /// Iterates over each child of the given item.
- fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) {
+ /// Iterates over all named children of the given module,
+ /// including both proper items and reexports.
+ /// Module here is understood in name resolution sense - it can be a `mod` item,
+ /// or a crate root, or an enum, or a trait.
+ fn for_each_module_child(
+ self,
+ id: DefIndex,
+ mut callback: impl FnMut(ModChild),
+ sess: &Session,
+ ) {
if let Some(data) = &self.root.proc_macro_data {
- /* If we are loading as a proc macro, we want to return the view of this crate
- * as a proc macro crate.
- */
+ // If we are loading as a proc macro, we want to return
+ // the view of this crate as a proc macro crate.
if id == CRATE_DEF_INDEX {
- let macros = data.macros.decode(self);
- for def_index in macros {
+ for def_index in data.macros.decode(self) {
let raw_macro = self.raw_proc_macro(def_index);
let res = Res::Def(
DefKind::Macro(macro_kind(raw_macro)),
self.local_def_id(def_index),
);
let ident = self.item_ident(def_index, sess);
- callback(Export { ident, res, vis: ty::Visibility::Public, span: ident.span });
+ callback(ModChild {
+ ident,
+ res,
+ vis: ty::Visibility::Public,
+ span: ident.span,
+ });
}
}
return;
}
- // Find the item.
- let kind = match self.maybe_kind(id) {
- None => return,
- Some(kind) => kind,
- };
-
// Iterate over all children.
if let Some(children) = self.root.tables.children.get(self, id) {
for child_index in children.decode((self, sess)) {
@@ -1113,7 +1102,7 @@
let vis = self.get_visibility(child_index);
let span = self.get_span(child_index, sess);
- callback(Export { ident, res, vis, span });
+ callback(ModChild { ident, res, vis, span });
// For non-re-export structs and variants add their constructors to children.
// Re-export lists automatically contain constructors when necessary.
@@ -1125,7 +1114,7 @@
let ctor_res =
Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let vis = self.get_visibility(ctor_def_id.index);
- callback(Export { res: ctor_res, vis, ident, span });
+ callback(ModChild { ident, res: ctor_res, vis, span });
}
}
DefKind::Variant => {
@@ -1150,7 +1139,7 @@
vis = ty::Visibility::Restricted(crate_def_id);
}
}
- callback(Export { res: ctor_res, ident, vis, span });
+ callback(ModChild { ident, res: ctor_res, vis, span });
}
_ => {}
}
@@ -1158,22 +1147,26 @@
}
}
- if let EntryKind::Mod(exports) = kind {
- for exp in exports.decode((self, sess)) {
- callback(exp);
+ match self.kind(id) {
+ EntryKind::Mod(exports) => {
+ for exp in exports.decode((self, sess)) {
+ callback(exp);
+ }
}
+ EntryKind::Enum(..) | EntryKind::Trait(..) => {}
+ _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)),
}
}
- fn is_ctfe_mir_available(&self, id: DefIndex) -> bool {
+ fn is_ctfe_mir_available(self, id: DefIndex) -> bool {
self.root.tables.mir_for_ctfe.get(self, id).is_some()
}
- fn is_item_mir_available(&self, id: DefIndex) -> bool {
+ fn is_item_mir_available(self, id: DefIndex) -> bool {
self.root.tables.mir.get(self, id).is_some()
}
- fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
+ fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
match self.kind(id) {
EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
self.get_expn_that_defined(id, sess)
@@ -1182,7 +1175,7 @@
}
}
- fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+ fn get_optimized_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
self.root
.tables
.mir
@@ -1193,7 +1186,7 @@
.decode((self, tcx))
}
- fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+ fn get_mir_for_ctfe(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
self.root
.tables
.mir_for_ctfe
@@ -1205,7 +1198,7 @@
}
fn get_thir_abstract_const(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
@@ -1216,7 +1209,7 @@
.map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
}
- fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
+ fn get_unused_generic_params(self, id: DefIndex) -> FiniteBitSet<u32> {
self.root
.tables
.unused_generic_params
@@ -1225,7 +1218,7 @@
.unwrap_or_default()
}
- fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
+ fn get_promoted_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
self.root
.tables
.promoted_mir
@@ -1236,7 +1229,7 @@
.decode((self, tcx))
}
- fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
+ fn mir_const_qualif(self, id: DefIndex) -> mir::ConstQualifs {
match self.kind(id) {
EntryKind::AnonConst(qualif, _)
| EntryKind::Const(qualif, _)
@@ -1251,14 +1244,24 @@
}
}
- fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool {
+ fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
match self.kind(id) {
EntryKind::AssocFn(data) => data.decode(self).has_self,
_ => false,
}
}
- fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
+ fn get_associated_item_def_ids(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
+ if let Some(children) = self.root.tables.children.get(self, id) {
+ tcx.arena.alloc_from_iter(
+ children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)),
+ )
+ } else {
+ &[]
+ }
+ }
+
+ fn get_associated_item(self, id: DefIndex, sess: &Session) -> ty::AssocItem {
let def_key = self.def_key(id);
let parent = self.local_def_id(def_key.parent.unwrap());
let ident = self.item_ident(id, sess);
@@ -1274,21 +1277,22 @@
};
ty::AssocItem {
- ident,
+ name: ident.name,
kind,
vis: self.get_visibility(id),
defaultness: container.defaultness(),
def_id: self.local_def_id(id),
+ trait_item_def_id: self.get_trait_item_def_id(id),
container: container.with_def_id(parent),
fn_has_self_parameter: has_self,
}
}
- fn get_item_variances(&'a self, id: DefIndex) -> impl Iterator<Item = ty::Variance> + 'a {
+ fn get_item_variances(self, id: DefIndex) -> impl Iterator<Item = ty::Variance> + 'a {
self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self)
}
- fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
+ fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
match self.kind(node_id) {
EntryKind::Struct(data, _) | EntryKind::Variant(data) => {
let vdata = data.decode(self);
@@ -1299,7 +1303,7 @@
}
fn get_item_attrs(
- &'a self,
+ self,
id: DefIndex,
sess: &'a Session,
) -> impl Iterator<Item = ast::Attribute> + 'a {
@@ -1323,30 +1327,32 @@
.decode((self, sess))
}
- fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec<Spanned<Symbol>> {
+ fn get_struct_field_names(
+ self,
+ id: DefIndex,
+ sess: &'a Session,
+ ) -> impl Iterator<Item = Spanned<Symbol>> + 'a {
self.root
.tables
.children
.get(self, id)
.unwrap_or_else(Lazy::empty)
.decode(self)
- .map(|index| respan(self.get_span(index, sess), self.item_ident(index, sess).name))
- .collect()
+ .map(move |index| respan(self.get_span(index, sess), self.item_ident(index, sess).name))
}
- fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec<Visibility> {
+ fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator<Item = Visibility> + 'a {
self.root
.tables
.children
.get(self, id)
.unwrap_or_else(Lazy::empty)
.decode(self)
- .map(|field_index| self.get_visibility(field_index))
- .collect()
+ .map(move |field_index| self.get_visibility(field_index))
}
fn get_inherent_implementations_for_type(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> &'tcx [DefId] {
@@ -1361,25 +1367,45 @@
)
}
- fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a {
- self.root.traits.decode(self).map(|index| self.local_def_id(index))
+ /// Decodes all inherent impls in the crate (for rustdoc).
+ fn get_inherent_impls(self) -> impl Iterator<Item = (DefId, DefId)> + 'a {
+ (0..self.root.tables.inherent_impls.size()).flat_map(move |i| {
+ let ty_index = DefIndex::from_usize(i);
+ let ty_def_id = self.local_def_id(ty_index);
+ self.root
+ .tables
+ .inherent_impls
+ .get(self, ty_index)
+ .unwrap_or_else(Lazy::empty)
+ .decode(self)
+ .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
+ })
}
- fn get_trait_impls(&'a self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
- self.trait_impls.values().flat_map(move |impls| {
- impls
- .decode(self)
- .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
+ /// Decodes all traits in the crate (for rustdoc and rustc diagnostics).
+ fn get_traits(self) -> impl Iterator<Item = DefId> + 'a {
+ self.root.traits.decode(self).map(move |index| self.local_def_id(index))
+ }
+
+ /// Decodes all trait impls in the crate (for rustdoc).
+ fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a {
+ self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| {
+ let trait_def_id = DefId {
+ krate: self.cnum_map[CrateNum::from_u32(*trait_cnum_raw)],
+ index: *trait_index,
+ };
+ impls.decode(self).map(move |(impl_index, simplified_self_ty)| {
+ (trait_def_id, self.local_def_id(impl_index), simplified_self_ty)
+ })
})
}
fn get_implementations_of_trait(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
) -> &'tcx [(DefId, Option<SimplifiedType>)] {
- if self.root.is_proc_macro_crate() {
- // proc-macro crates export no trait impls.
+ if self.trait_impls.is_empty() {
return &[];
}
@@ -1401,7 +1427,7 @@
}
}
- fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
+ fn get_trait_of_item(self, id: DefIndex) -> Option<DefId> {
let def_key = self.def_key(id);
match def_key.disambiguated_data.data {
DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
@@ -1414,16 +1440,11 @@
})
}
- fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLib> {
- if self.root.is_proc_macro_crate() {
- // Proc macro crates do not have any *target* native libraries.
- vec![]
- } else {
- self.root.native_libraries.decode((self, sess)).collect()
- }
+ fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> + 'a {
+ self.root.native_libraries.decode((self, sess))
}
- fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span {
+ fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span {
self.root
.tables
.proc_macro_quoted_spans
@@ -1432,19 +1453,12 @@
.decode((self, sess))
}
- fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
- if self.root.is_proc_macro_crate() {
- // Proc macro crates do not have any *target* foreign modules.
- Lrc::new(FxHashMap::default())
- } else {
- let modules: FxHashMap<DefId, ForeignModule> =
- self.root.foreign_modules.decode((self, tcx.sess)).map(|m| (m.def_id, m)).collect();
- Lrc::new(modules)
- }
+ fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> + '_ {
+ self.root.foreign_modules.decode((self, sess))
}
fn get_dylib_dependency_formats(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(CrateNum, LinkagePreference)] {
tcx.arena.alloc_from_iter(
@@ -1455,16 +1469,11 @@
)
}
- fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
- if self.root.is_proc_macro_crate() {
- // Proc macro crates do not depend on any target weak lang-items.
- &[]
- } else {
- tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
- }
+ fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
+ tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
}
- fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
+ fn get_fn_param_names(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
let param_names = match self.kind(id) {
EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names,
EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names,
@@ -1474,19 +1483,13 @@
}
fn exported_symbols(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
- if self.root.is_proc_macro_crate() {
- // If this crate is a custom derive crate, then we're not even going to
- // link those in so we skip those crates.
- &[]
- } else {
- tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
- }
+ tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
}
- fn get_rendered_const(&self, id: DefIndex) -> String {
+ fn get_rendered_const(self, id: DefIndex) -> String {
match self.kind(id) {
EntryKind::AnonConst(_, data)
| EntryKind::Const(_, data)
@@ -1495,7 +1498,7 @@
}
}
- fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef {
+ fn get_macro(self, id: DefIndex, sess: &Session) -> MacroDef {
match self.kind(id) {
EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)),
_ => bug!(),
@@ -1504,7 +1507,7 @@
// This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we
// don't serialize constness for tuple variant and tuple struct constructors.
- fn is_const_fn_raw(&self, id: DefIndex) -> bool {
+ fn is_const_fn_raw(self, id: DefIndex) -> bool {
let constness = match self.kind(id) {
EntryKind::AssocFn(data) => data.decode(self).fn_data.constness,
EntryKind::Fn(data) => data.decode(self).constness,
@@ -1515,7 +1518,7 @@
constness == hir::Constness::Const
}
- fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
+ fn asyncness(self, id: DefIndex) -> hir::IsAsync {
match self.kind(id) {
EntryKind::Fn(data) => data.decode(self).asyncness,
EntryKind::AssocFn(data) => data.decode(self).fn_data.asyncness,
@@ -1524,7 +1527,7 @@
}
}
- fn is_foreign_item(&self, id: DefIndex) -> bool {
+ fn is_foreign_item(self, id: DefIndex) -> bool {
match self.kind(id) {
EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => {
true
@@ -1533,7 +1536,7 @@
}
}
- fn static_mutability(&self, id: DefIndex) -> Option<hir::Mutability> {
+ fn static_mutability(self, id: DefIndex) -> Option<hir::Mutability> {
match self.kind(id) {
EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not),
EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut),
@@ -1541,19 +1544,19 @@
}
}
- fn generator_kind(&self, id: DefIndex) -> Option<hir::GeneratorKind> {
+ fn generator_kind(self, id: DefIndex) -> Option<hir::GeneratorKind> {
match self.kind(id) {
EntryKind::Generator(data) => Some(data),
_ => None,
}
}
- fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
+ fn fn_sig(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
self.root.tables.fn_sig.get(self, id).unwrap().decode((self, tcx))
}
#[inline]
- fn def_key(&self, index: DefIndex) -> DefKey {
+ fn def_key(self, index: DefIndex) -> DefKey {
*self
.def_key_cache
.lock()
@@ -1562,13 +1565,13 @@
}
// Returns the path leading to the thing with this `id`.
- fn def_path(&self, id: DefIndex) -> DefPath {
+ fn def_path(self, id: DefIndex) -> DefPath {
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
}
fn def_path_hash_unlocked(
- &self,
+ self,
index: DefIndex,
def_path_hashes: &mut FxHashMap<DefIndex, DefPathHash>,
) -> DefPathHash {
@@ -1578,17 +1581,17 @@
}
#[inline]
- fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
+ fn def_path_hash(self, index: DefIndex) -> DefPathHash {
let mut def_path_hashes = self.def_path_hash_cache.lock();
self.def_path_hash_unlocked(index, &mut def_path_hashes)
}
#[inline]
- fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex {
+ fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex {
self.def_path_hash_map.def_path_hash_to_def_index(&hash)
}
- fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
+ fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
debug_assert_eq!(ExpnId::from_hash(hash), None);
let index_guess = ExpnIndex::from_u32(index_guess);
let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self));
@@ -1646,7 +1649,7 @@
///
/// Proc macro crates don't currently export spans, so this function does not have
/// to work for them.
- fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
+ fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
// Translate the virtual `/rustc/$hash` prefix back to a real directory
// that should hold actual sources, where possible.
//
@@ -1870,7 +1873,7 @@
cnum_map,
dependencies,
dep_kind: Lock::new(dep_kind),
- source,
+ source: Lrc::new(source),
private_dep,
host_hash,
extern_crate: Lock::new(None),
@@ -1898,7 +1901,7 @@
}
crate fn source(&self) -> &CrateSource {
- &self.source
+ &*self.source
}
crate fn dep_kind(&self) -> CrateDepKind {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index aac0aa6..7708b51 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -3,16 +3,16 @@
use crate::native_libs;
use rustc_ast as ast;
-use rustc_data_structures::stable_map::FxHashMap;
-use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
+use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
-use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
+use rustc_session::cstore::{CrateSource, CrateStore};
use rustc_session::utils::NativeLibKind;
use rustc_session::{Session, StableCrateId};
use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -103,12 +103,7 @@
tcx.calculate_dtor(def_id, |_,_| Ok(()))
}
variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
- associated_item_def_ids => {
- let mut result = SmallVec::<[_; 8]>::new();
- cdata.each_child_of_item(def_id.index,
- |child| result.push(child.res.def_id()), tcx.sess);
- tcx.arena.alloc_slice(&result)
- }
+ associated_item_def_ids => { cdata.get_associated_item_def_ids(tcx, def_id.index) }
associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
impl_polarity => { cdata.get_impl_polarity(def_id.index) }
@@ -122,7 +117,7 @@
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
- const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
+ const_param_default => { cdata.get_const_param_default(tcx, def_id.index) }
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
@@ -183,8 +178,8 @@
reachable_non_generics
}
- native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
- foreign_modules => { cdata.get_foreign_modules(tcx) }
+ native_libraries => { cdata.get_native_libraries(tcx.sess).collect() }
+ foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() }
crate_hash => { cdata.root.hash }
crate_host_hash => { cdata.host_hash }
crate_name => { cdata.root.name }
@@ -192,8 +187,6 @@
extra_filename => { cdata.root.extra_filename.clone() }
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
- all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }
-
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
visibility => { cdata.get_visibility(def_id.index) }
@@ -201,13 +194,13 @@
let r = *cdata.dep_kind.lock();
r
}
- item_children => {
+ module_children => {
let mut result = SmallVec::<[_; 8]>::new();
- cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
+ cdata.for_each_module_child(def_id.index, |child| result.push(child), tcx.sess);
tcx.arena.alloc_slice(&result)
}
defined_lib_features => { cdata.get_lib_features(tcx) }
- defined_lang_items => { cdata.get_lang_items(tcx) }
+ defined_lang_items => { tcx.arena.alloc_from_iter(cdata.get_lang_items()) }
diagnostic_items => { cdata.get_diagnostic_items() }
missing_lang_items => { cdata.get_missing_lang_items(tcx) }
@@ -216,7 +209,7 @@
r
}
- used_crate_source => { Lrc::new(cdata.source.clone()) }
+ used_crate_source => { Lrc::clone(&cdata.source) }
exported_symbols => {
let syms = cdata.exported_symbols(tcx);
@@ -270,13 +263,11 @@
},
native_libraries: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
- Lrc::new(native_libs::collect(tcx))
+ native_libs::collect(tcx)
},
foreign_modules: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
- let modules: FxHashMap<DefId, ForeignModule> =
- foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect();
- Lrc::new(modules)
+ foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
},
// Returns a map from a sufficiently visible external item (i.e., an
@@ -314,35 +305,40 @@
bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
}
- let mut add_child = |bfs_queue: &mut VecDeque<_>, export: &Export, parent: DefId| {
- if !export.vis.is_public() {
+ let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
+ if !child.vis.is_public() {
return;
}
- if let Some(child) = export.res.opt_def_id() {
- if export.ident.name == kw::Underscore {
- fallback_map.insert(child, parent);
+ if let Some(def_id) = child.res.opt_def_id() {
+ if child.ident.name == kw::Underscore {
+ fallback_map.insert(def_id, parent);
return;
}
- match visible_parent_map.entry(child) {
+ match visible_parent_map.entry(def_id) {
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
// that it is mapped to a parent in `cnum`.
- if child.is_local() && entry.get().is_local() {
+ if def_id.is_local() && entry.get().is_local() {
entry.insert(parent);
}
}
Entry::Vacant(entry) => {
entry.insert(parent);
- bfs_queue.push_back(child);
+ if matches!(
+ child.res,
+ Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _)
+ ) {
+ bfs_queue.push_back(def_id);
+ }
}
}
}
};
while let Some(def) = bfs_queue.pop_front() {
- for child in tcx.item_children(def).iter() {
+ for child in tcx.module_children(def).iter() {
add_child(bfs_queue, child, def);
}
}
@@ -372,11 +368,18 @@
}
impl CStore {
- pub fn struct_field_names_untracked(&self, def: DefId, sess: &Session) -> Vec<Spanned<Symbol>> {
+ pub fn struct_field_names_untracked<'a>(
+ &'a self,
+ def: DefId,
+ sess: &'a Session,
+ ) -> impl Iterator<Item = Spanned<Symbol>> + 'a {
self.get_crate_data(def.krate).get_struct_field_names(def.index, sess)
}
- pub fn struct_field_visibilities_untracked(&self, def: DefId) -> Vec<Visibility> {
+ pub fn struct_field_visibilities_untracked(
+ &self,
+ def: DefId,
+ ) -> impl Iterator<Item = Visibility> + '_ {
self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
}
@@ -388,9 +391,9 @@
self.get_crate_data(def.krate).get_visibility(def.index)
}
- pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<Export> {
+ pub fn module_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ModChild> {
let mut result = vec![];
- self.get_crate_data(def_id.krate).each_child_of_item(
+ self.get_crate_data(def_id.krate).for_each_module_child(
def_id.index,
|child| result.push(child),
sess,
@@ -430,7 +433,7 @@
self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index)
}
- pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
+ pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc<CrateSource> {
self.get_crate_data(cnum).source.clone()
}
@@ -461,8 +464,12 @@
self.get_crate_data(cnum).num_def_ids()
}
- pub fn item_attrs_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
- self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
+ pub fn item_attrs_untracked<'a>(
+ &'a self,
+ def_id: DefId,
+ sess: &'a Session,
+ ) -> impl Iterator<Item = ast::Attribute> + 'a {
+ self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess)
}
pub fn get_proc_macro_quoted_span_untracked(
@@ -473,6 +480,32 @@
) -> Span {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}
+
+ /// Decodes all traits in the crate (for rustdoc).
+ pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
+ self.get_crate_data(cnum).get_traits()
+ }
+
+ /// Decodes all trait impls in the crate (for rustdoc).
+ pub fn trait_impls_in_crate_untracked(
+ &self,
+ cnum: CrateNum,
+ ) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ {
+ self.get_crate_data(cnum).get_trait_impls()
+ }
+
+ /// Decodes all inherent impls in the crate (for rustdoc).
+ pub fn inherent_impls_in_crate_untracked(
+ &self,
+ cnum: CrateNum,
+ ) -> impl Iterator<Item = (DefId, DefId)> + '_ {
+ self.get_crate_data(cnum).get_inherent_impls()
+ }
+
+ /// Decodes all lang items in the crate (for rustdoc).
+ pub fn lang_items_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
+ self.get_crate_data(cnum).get_lang_items().map(|(def_id, _)| def_id)
+ }
}
impl CrateStore for CStore {
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 0544311..d66f2b0 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -39,11 +39,11 @@
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> {
- fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefPathHashMapRef<'static>, String> {
+ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
// Import TyDecoder so we can access the DecodeContext::position() method
use crate::rustc_middle::ty::codec::TyDecoder;
- let len = d.read_usize()?;
+ let len = d.read_usize();
let pos = d.position();
let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]);
@@ -52,7 +52,9 @@
// the method. We use read_raw_bytes() for that.
let _ = d.read_raw_bytes(len);
- let inner = odht::HashTable::from_raw_bytes(o).map_err(|e| format!("{}", e))?;
- Ok(DefPathHashMapRef::OwnedFromMetadata(inner))
+ let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| {
+ panic!("decode error: {}", e);
+ });
+ DefPathHashMapRef::OwnedFromMetadata(inner)
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 12d66f4..4dea04e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -11,13 +11,13 @@
CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
};
use rustc_hir::definitions::DefPathData;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items;
use rustc_hir::{AnonConst, GenericParamKind};
use rustc_index::bit_set::GrowableBitSet;
use rustc_index::vec::Idx;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
@@ -26,7 +26,7 @@
use rustc_middle::thir;
use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder};
@@ -404,24 +404,24 @@
&mut self,
lazy: Lazy<T>,
) -> Result<(), <Self as Encoder>::Error> {
- let min_end = lazy.position.get() + T::min_size(lazy.meta);
+ let pos = lazy.position.get();
let distance = match self.lazy_state {
LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
LazyState::NodeStart(start) => {
let start = start.get();
- assert!(min_end <= start);
- start - min_end
+ assert!(pos <= start);
+ start - pos
}
- LazyState::Previous(last_min_end) => {
+ LazyState::Previous(last_pos) => {
assert!(
- last_min_end <= lazy.position,
+ last_pos <= lazy.position,
"make sure that the calls to `lazy*` \
are in the same order as the metadata fields",
);
- lazy.position.get() - last_min_end.get()
+ lazy.position.get() - last_pos.get()
}
};
- self.lazy_state = LazyState::Previous(NonZeroUsize::new(min_end).unwrap());
+ self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
self.emit_usize(distance)
}
@@ -436,7 +436,7 @@
let meta = value.encode_contents_for_lazy(self);
self.lazy_state = LazyState::NoNode;
- assert!(pos.get() + <T>::min_size(meta) <= self.position());
+ assert!(pos.get() <= self.position());
Lazy::from_position_and_meta(pos, meta)
}
@@ -982,7 +982,7 @@
for local_id in hir.iter_local_def_id() {
let def_id = local_id.to_def_id();
let def_kind = tcx.opt_def_kind(local_id);
- let def_kind = if let Some(def_kind) = def_kind { def_kind } else { continue };
+ let Some(def_kind) = def_kind else { continue };
record!(self.tables.def_kind[def_id] <- match def_kind {
// Replace Ctor by the enclosing object to avoid leaking details in children crates.
DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct,
@@ -1052,7 +1052,7 @@
assert!(f.did.is_local());
f.did.index
}));
- self.encode_ident_span(def_id, variant.ident);
+ self.encode_ident_span(def_id, variant.ident(tcx));
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
// FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
@@ -1094,7 +1094,7 @@
// code uses it). However, we skip encoding anything relating to child
// items - we encode information about proc-macros later on.
let reexports = if !self.is_proc_macro {
- match tcx.module_exports(local_def_id) {
+ match tcx.module_reexports(local_def_id) {
Some(exports) => self.lazy(exports),
_ => Lazy::empty(),
}
@@ -1104,7 +1104,6 @@
record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
if self.is_proc_macro {
- record!(self.tables.children[def_id] <- &[]);
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
@@ -1139,7 +1138,7 @@
debug!("EncodeContext::encode_field({:?})", def_id);
record!(self.tables.kind[def_id] <- EntryKind::Field);
- self.encode_ident_span(def_id, field.ident);
+ self.encode_ident_span(def_id, field.ident(self.tcx));
self.encode_item_type(def_id);
}
@@ -1292,8 +1291,11 @@
record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
}
}
- self.encode_ident_span(def_id, impl_item.ident);
+ self.encode_ident_span(def_id, impl_item.ident(self.tcx));
self.encode_item_type(def_id);
+ if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
+ record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
+ }
if impl_item.kind == ty::AssocKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
}
@@ -1312,7 +1314,7 @@
return;
}
- let mut keys_and_jobs = self
+ let keys_and_jobs = self
.tcx
.mir_keys(())
.iter()
@@ -1325,8 +1327,6 @@
}
})
.collect::<Vec<_>>();
- // Sort everything to ensure a stable order for diagnotics.
- keys_and_jobs.sort_by_key(|&(def_id, _, _)| def_id.index());
for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() {
debug_assert!(encode_const || encode_opt);
@@ -1511,6 +1511,7 @@
is_marker: trait_def.is_marker,
skip_array_during_method_dispatch: trait_def.skip_array_during_method_dispatch,
specialization_kind: trait_def.specialization_kind,
+ must_implement_one_of: trait_def.must_implement_one_of.clone(),
};
EntryKind::Trait(self.lazy(data))
@@ -1577,12 +1578,12 @@
}
}
- fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
+ fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
+ let def_id = self.tcx.hir().local_def_id(hir_id);
debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
// NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
// including on the signature, which is inferred in `typeck.
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let ty = self.tcx.typeck(def_id).node_type(hir_id);
match ty.kind() {
@@ -1603,9 +1604,9 @@
}
}
- fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
+ fn encode_info_for_anon_const(&mut self, id: hir::HirId) {
+ let def_id = self.tcx.hir().local_def_id(id);
debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id);
- let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = self.tcx.hir().body_owned_by(id);
let const_data = self.encode_rendered_const_for_body(body_id);
let qualifs = self.tcx.mir_const_qualif(def_id);
@@ -1741,7 +1742,7 @@
hash: self.tcx.crate_hash(cnum),
host_hash: self.tcx.crate_host_hash(cnum),
kind: self.tcx.dep_kind(cnum),
- extra_filename: self.tcx.extra_filename(cnum),
+ extra_filename: self.tcx.extra_filename(cnum).clone(),
};
(cnum, dep)
})
@@ -1915,10 +1916,10 @@
// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
@@ -1926,8 +1927,7 @@
}
fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
intravisit::walk_anon_const(self, c);
- let def_id = self.tcx.hir().local_def_id(c.hir_id);
- self.encode_info_for_anon_const(def_id);
+ self.encode_info_for_anon_const(c.hir_id);
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
intravisit::walk_item(self, item);
@@ -1981,8 +1981,7 @@
fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) {
if let hir::ExprKind::Closure(..) = expr.kind {
- let def_id = self.tcx.hir().local_def_id(expr.hir_id);
- self.encode_info_for_closure(def_id);
+ self.encode_info_for_closure(expr.hir_id);
}
}
@@ -2067,7 +2066,6 @@
self.tcx,
trait_ref.self_ty(),
SimplifyParams::No,
- StripReferences::No,
);
self.impls
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 4076e0b..8424a31 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -12,7 +12,7 @@
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc_middle::mir;
use rustc_middle::thir;
@@ -63,27 +63,14 @@
/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
trait LazyMeta {
type Meta: Copy + 'static;
-
- /// Returns the minimum encoded size.
- // FIXME(eddyb) Give better estimates for certain types.
- fn min_size(meta: Self::Meta) -> usize;
}
impl<T> LazyMeta for T {
type Meta = ();
-
- fn min_size(_: ()) -> usize {
- assert_ne!(std::mem::size_of::<T>(), 0);
- 1
- }
}
impl<T> LazyMeta for [T] {
type Meta = usize;
-
- fn min_size(len: usize) -> usize {
- len * T::min_size(())
- }
}
/// A value of type T referred to by its absolute position
@@ -161,8 +148,7 @@
NodeStart(NonZeroUsize),
/// Inside a metadata node, with a previous `Lazy`.
- /// The position is a conservative estimate of where that
- /// previous `Lazy` would end (see their comments).
+ /// The position is where that previous `Lazy` would start.
Previous(NonZeroUsize),
}
@@ -302,6 +288,7 @@
ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
+ trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
variances: Table<DefIndex, Lazy<[ty::Variance]>>,
generics: Table<DefIndex, Lazy<ty::Generics>>,
@@ -349,7 +336,7 @@
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
- Mod(Lazy<[Export]>),
+ Mod(Lazy<[ModChild]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
@@ -391,6 +378,7 @@
is_marker: bool,
skip_array_during_method_dispatch: bool,
specialization_kind: ty::trait_def::TraitSpecializationKind,
+ must_implement_one_of: Option<Box<[Ident]>>,
}
#[derive(TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 4dfefda..265ca5a 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -183,10 +183,6 @@
Option<T>: FixedSizeEncoding,
{
type Meta = usize;
-
- fn min_size(len: usize) -> usize {
- len
- }
}
impl<I: Idx, T> Lazy<Table<I, T>>
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index a9db846..b133441 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -12,8 +12,8 @@
either = "1.5.0"
gsgdt = "0.1.2"
tracing = "0.1"
-rustc-rayon = "0.3.1"
-rustc-rayon-core = "0.3.1"
+rustc-rayon = "0.3.2"
+rustc-rayon-core = "0.3.2"
polonius-engine = "0.13.0"
rustc_apfloat = { path = "../rustc_apfloat" }
rustc_attr = { path = "../rustc_attr" }
@@ -29,7 +29,7 @@
rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.75.0"
+chalk-ir = "0.76.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_session = { path = "../rustc_session" }
rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index a936852..c4e6734 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -52,6 +52,9 @@
Vec<rustc_middle::traits::query::OutlivesBound<'tcx>>
>
>,
+ [] dtorck_constraint: rustc_middle::traits::query::DtorckConstraint<'tcx>,
+ [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>,
+ [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>,
[] type_op_subtype:
rustc_middle::infer::canonical::Canonical<'tcx,
rustc_middle::infer::canonical::QueryResponse<'tcx, ()>
@@ -85,7 +88,8 @@
// Interned types
[] tys: rustc_middle::ty::TyS<'tcx>,
- [] predicates: rustc_middle::ty::PredicateInner<'tcx>,
+ [] predicates: rustc_middle::ty::PredicateS<'tcx>,
+ [] consts: rustc_middle::ty::ConstS<'tcx>,
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
// since we need to allocate this type on both the `rustc_hir` arena
@@ -95,6 +99,7 @@
// This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
[decode] span: rustc_span::Span,
[decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+ [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
[] dep_kind: rustc_middle::dep_graph::DepKindStruct,
]);
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 5c7cdbe..d20be0a 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -266,7 +266,9 @@
/// has been removed.
fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
- Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())))
+ Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
+ panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
+ }))
} else {
None
}
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 79d7ca3..6bfd1b7 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -1,6 +1,5 @@
use crate::ty::{self, TyCtxt};
use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_data_structures::sync::Lock;
use rustc_query_system::ich::StableHashingContext;
use rustc_session::Session;
@@ -17,6 +16,7 @@
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
+pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
@@ -45,7 +45,7 @@
write!(f, ")")
}
- fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, op: OP) -> R
+ fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
where
OP: FnOnce() -> R,
{
@@ -58,10 +58,10 @@
fn read_deps<OP>(op: OP)
where
- OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>),
+ OP: for<'a> FnOnce(TaskDepsRef<'a>),
{
ty::tls::with_context_opt(|icx| {
- let icx = if let Some(icx) = icx { icx } else { return };
+ let Some(icx) = icx else { return };
op(icx.task_deps)
})
}
diff --git a/compiler/rustc_middle/src/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs
deleted file mode 100644
index f37b976..0000000
--- a/compiler/rustc_middle/src/hir/exports.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use crate::ty;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::Res;
-use rustc_hir::def_id::LocalDefId;
-use rustc_macros::HashStable;
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-use std::fmt::Debug;
-
-/// This is the replacement export map. It maps a module to all of the exports
-/// within.
-pub type ExportMap = FxHashMap<LocalDefId, Vec<Export>>;
-
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct Export {
- /// The name of the target.
- pub ident: Ident,
- /// The resolution of the target.
- /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
- pub res: Res<!>,
- /// The span of the target.
- pub span: Span,
- /// The visibility of the export.
- /// We include non-`pub` exports for hygienic macros that get used from extern crates.
- pub vis: ty::Visibility,
-}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 394a1fc..f36847c 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -12,6 +12,7 @@
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*;
use rustc_index::vec::Idx;
+use rustc_middle::hir::nested_filter;
use rustc_span::def_id::StableCrateId;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
@@ -117,13 +118,13 @@
}
impl<'hir> Iterator for ParentOwnerIterator<'hir> {
- type Item = (HirId, OwnerNode<'hir>);
+ type Item = (LocalDefId, 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.tcx.hir_owner(self.current_id.owner) {
- return Some((self.current_id, node.node));
+ return Some((self.current_id.owner, node.node));
}
}
if self.current_id == CRATE_HIR_ID {
@@ -141,42 +142,42 @@
// If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
- return Some((self.current_id, node.node));
+ return Some((self.current_id.owner, node.node));
}
}
}
}
impl<'hir> Map<'hir> {
- pub fn krate(&self) -> &'hir Crate<'hir> {
+ pub fn krate(self) -> &'hir Crate<'hir> {
self.tcx.hir_crate(())
}
- pub fn root_module(&self) -> &'hir Mod<'hir> {
+ pub fn root_module(self) -> &'hir Mod<'hir> {
match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) {
Some(OwnerNode::Crate(item)) => item,
_ => bug!(),
}
}
- pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
+ pub fn items(self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
let krate = self.krate();
- krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() {
+ krate.owners.iter().filter_map(|owner| match owner.as_owner()?.node() {
OwnerNode::Item(item) => Some(item),
_ => None,
})
}
- pub fn def_key(&self, def_id: LocalDefId) -> DefKey {
+ pub fn def_key(self, def_id: LocalDefId) -> DefKey {
// Accessing the DefKey is ok, since it is part of DefPathHash.
self.tcx.untracked_resolutions.definitions.def_key(def_id)
}
- pub fn def_path_from_hir_id(&self, id: HirId) -> Option<DefPath> {
+ pub fn def_path_from_hir_id(self, id: HirId) -> Option<DefPath> {
self.opt_local_def_id(id).map(|def_id| self.def_path(def_id))
}
- pub fn def_path(&self, def_id: LocalDefId) -> DefPath {
+ pub fn def_path(self, def_id: LocalDefId) -> DefPath {
// Accessing the DefPath is ok, since it is part of DefPathHash.
self.tcx.untracked_resolutions.definitions.def_path(def_id)
}
@@ -188,7 +189,7 @@
}
#[inline]
- pub fn local_def_id(&self, hir_id: HirId) -> LocalDefId {
+ pub fn local_def_id(self, hir_id: HirId) -> LocalDefId {
self.opt_local_def_id(hir_id).unwrap_or_else(|| {
bug!(
"local_def_id: no entry for `{:?}`, which has a map of `{:?}`",
@@ -199,25 +200,32 @@
}
#[inline]
- pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<LocalDefId> {
- // FIXME(#85914) is this access safe for incr. comp.?
- self.tcx.untracked_resolutions.definitions.opt_hir_id_to_local_def_id(hir_id)
+ pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> {
+ if hir_id.local_id == ItemLocalId::new(0) {
+ Some(hir_id.owner)
+ } else {
+ self.tcx
+ .hir_owner_nodes(hir_id.owner)
+ .as_owner()?
+ .local_id_to_def_id
+ .get(&hir_id.local_id)
+ .copied()
+ }
}
#[inline]
- pub fn local_def_id_to_hir_id(&self, def_id: LocalDefId) -> HirId {
- // FIXME(#85914) is this access safe for incr. comp.?
- self.tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id)
+ pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId {
+ self.tcx.local_def_id_to_hir_id(def_id)
}
- pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+ pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'hir {
// Create a dependency to the crate to be sure we reexcute this when the amount of
// definitions change.
self.tcx.ensure().hir_crate(());
self.tcx.untracked_resolutions.definitions.iter_local_def_id()
}
- pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
+ pub fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
let hir_id = self.local_def_id_to_hir_id(local_def_id);
let def_kind = match self.find(hir_id)? {
Node::Item(item) => match item.kind {
@@ -304,49 +312,60 @@
Some(def_kind)
}
- pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
+ pub fn def_kind(self, local_def_id: LocalDefId) -> DefKind {
self.opt_def_kind(local_def_id)
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
}
- pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
+ pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
if id.local_id == ItemLocalId::from_u32(0) {
Some(self.tcx.hir_owner_parent(id.owner))
} else {
- let owner = self.tcx.hir_owner_nodes(id.owner)?;
+ let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
let node = owner.nodes[id.local_id].as_ref()?;
let hir_id = HirId { owner: id.owner, local_id: node.parent };
Some(hir_id)
}
}
- pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
+ pub fn get_parent_node(self, hir_id: HirId) -> HirId {
self.find_parent_node(hir_id).unwrap()
}
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
- pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
+ 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.into())
} else {
- let owner = self.tcx.hir_owner_nodes(id.owner)?;
+ let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
let node = owner.nodes[id.local_id].as_ref()?;
Some(node.node)
}
}
+ /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
+ #[inline]
+ pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> {
+ self.find(self.local_def_id_to_hir_id(id))
+ }
+
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
- pub fn get(&self, id: HirId) -> Node<'hir> {
+ pub fn get(self, id: HirId) -> Node<'hir> {
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
}
- pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
+ /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
+ #[inline]
+ pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> {
+ self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id))
+ }
+
+ pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
}
- pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
- let id = id.as_local()?;
+ pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
let node = self.tcx.hir_owner(id)?;
match node.node {
OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
@@ -367,27 +386,27 @@
}
}
- pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
+ pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
}
- pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
+ pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
}
- pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
+ pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
}
- pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
}
- pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
+ pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
}
- pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
+ pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
if let Some(node) = self.find(hir_id) {
fn_decl(node)
} else {
@@ -395,7 +414,7 @@
}
}
- pub fn fn_sig_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
+ pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
if let Some(node) = self.find(hir_id) {
fn_sig(node)
} else {
@@ -403,7 +422,7 @@
}
}
- pub fn enclosing_body_owner(&self, hir_id: HirId) -> HirId {
+ pub fn enclosing_body_owner(self, hir_id: HirId) -> HirId {
for (parent, _) in self.parent_iter(hir_id) {
if let Some(body) = self.maybe_body_owned_by(parent) {
return self.body_owner(body);
@@ -416,24 +435,24 @@
/// Returns the `HirId` that corresponds to the definition of
/// which this is the body of, i.e., a `fn`, `const` or `static`
/// item (possibly associated), a closure, or a `hir::AnonConst`.
- pub fn body_owner(&self, BodyId { hir_id }: BodyId) -> HirId {
+ pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
let parent = self.get_parent_node(hir_id);
assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)));
parent
}
- pub fn body_owner_def_id(&self, id: BodyId) -> LocalDefId {
+ pub fn body_owner_def_id(self, id: BodyId) -> LocalDefId {
self.local_def_id(self.body_owner(id))
}
/// Given a `HirId`, returns the `BodyId` associated with it,
/// if the node is a body owner, otherwise returns `None`.
- pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option<BodyId> {
+ pub fn maybe_body_owned_by(self, hir_id: HirId) -> Option<BodyId> {
self.find(hir_id).map(associated_body).flatten()
}
/// Given a body owner's id, returns the `BodyId` associated with it.
- pub fn body_owned_by(&self, id: HirId) -> BodyId {
+ pub fn body_owned_by(self, id: HirId) -> BodyId {
self.maybe_body_owned_by(id).unwrap_or_else(|| {
span_bug!(
self.span(id),
@@ -443,7 +462,7 @@
})
}
- pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
+ pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
_ => Ident::empty(),
@@ -453,7 +472,7 @@
/// Returns the `BodyOwnerKind` of this `LocalDefId`.
///
/// Panics if `LocalDefId` does not have an associated body.
- pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind {
+ pub fn body_owner_kind(self, id: HirId) -> BodyOwnerKind {
match self.get(id) {
Node::Item(&Item { kind: ItemKind::Const(..), .. })
| Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. })
@@ -476,7 +495,7 @@
/// This should only be used for determining the context of a body, a return
/// value of `Some` does not always suggest that the owner of the body is `const`,
/// just that it has to be checked as if it were.
- pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
+ pub fn body_const_context(self, did: LocalDefId) -> Option<ConstContext> {
let hir_id = self.local_def_id_to_hir_id(did);
let ccx = match self.body_owner_kind(hir_id) {
BodyOwnerKind::Const => ConstContext::Const,
@@ -503,7 +522,7 @@
.owners
.iter_enumerated()
.flat_map(move |(owner, owner_info)| {
- let bodies = &owner_info.as_ref()?.nodes.bodies;
+ let bodies = &owner_info.as_owner()?.nodes.bodies;
Some(bodies.iter().map(move |&(local_id, _)| {
let hir_id = HirId { owner, local_id };
let body_id = BodyId { hir_id };
@@ -520,7 +539,7 @@
par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| {
let owner = LocalDefId::new(owner);
- if let Some(owner_info) = owner_info {
+ if let MaybeOwner::Owner(owner_info) = owner_info {
par_iter(owner_info.nodes.bodies.range(..)).for_each(|(local_id, _)| {
let hir_id = HirId { owner, local_id: *local_id };
let body_id = BodyId { hir_id };
@@ -530,15 +549,17 @@
});
}
- pub fn ty_param_owner(&self, id: HirId) -> HirId {
+ pub fn ty_param_owner(self, id: HirId) -> LocalDefId {
match self.get(id) {
- Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id,
- Node::GenericParam(_) => self.get_parent_node(id),
+ Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
+ id.expect_owner()
+ }
+ Node::GenericParam(_) => self.get_parent_item(id),
_ => bug!("ty_param_owner: {} not a type parameter", self.node_to_string(id)),
}
}
- pub fn ty_param_name(&self, id: HirId) -> Symbol {
+ pub fn ty_param_name(self, id: HirId) -> Symbol {
match self.get(id) {
Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
kw::SelfUpper
@@ -548,18 +569,18 @@
}
}
- pub fn trait_impls(&self, trait_did: DefId) -> &'hir [LocalDefId] {
+ pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] {
self.tcx.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..])
}
/// Gets the attributes on the crate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
- pub fn krate_attrs(&self) -> &'hir [ast::Attribute] {
+ pub fn krate_attrs(self) -> &'hir [ast::Attribute] {
self.attrs(CRATE_HIR_ID)
}
- pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
+ pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
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), .. })) => {
@@ -580,7 +601,7 @@
pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
let krate = self.krate();
for (owner, info) in krate.owners.iter_enumerated() {
- if let Some(info) = info {
+ if let MaybeOwner::Owner(info) = info {
for (local_id, attrs) in info.attrs.map.iter() {
let id = HirId { owner, local_id: *local_id };
for a in *attrs {
@@ -599,12 +620,12 @@
/// follows lexical scoping rules -- then you want a different
/// approach. You should override `visit_nested_item` in your
/// visitor and then call `intravisit::walk_crate` instead.
- pub fn visit_all_item_likes<V>(&self, visitor: &mut V)
+ pub fn visit_all_item_likes<V>(self, visitor: &mut V)
where
V: itemlikevisit::ItemLikeVisitor<'hir>,
{
let krate = self.krate();
- for owner in krate.owners.iter().filter_map(Option::as_ref) {
+ for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
match owner.node() {
OwnerNode::Item(item) => visitor.visit_item(item),
OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
@@ -616,21 +637,23 @@
}
/// A parallel version of `visit_all_item_likes`.
- pub fn par_visit_all_item_likes<V>(&self, visitor: &V)
+ pub fn par_visit_all_item_likes<V>(self, visitor: &V)
where
V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
{
let krate = self.krate();
- par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(OwnerInfo::node) {
- 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 => {}
+ par_for_each_in(&krate.owners.raw, |owner| match owner.map(OwnerInfo::node) {
+ MaybeOwner::Owner(OwnerNode::Item(item)) => visitor.visit_item(item),
+ MaybeOwner::Owner(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
+ MaybeOwner::Owner(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
+ MaybeOwner::Owner(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item),
+ MaybeOwner::Owner(OwnerNode::Crate(_))
+ | MaybeOwner::NonOwner(_)
+ | MaybeOwner::Phantom => {}
})
}
- pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
+ pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
where
V: ItemLikeVisitor<'hir>,
{
@@ -653,7 +676,7 @@
}
}
- pub fn for_each_module(&self, f: impl Fn(LocalDefId)) {
+ pub fn for_each_module(self, f: impl Fn(LocalDefId)) {
let mut queue = VecDeque::new();
queue.push_back(CRATE_DEF_ID);
@@ -666,12 +689,12 @@
#[cfg(not(parallel_compiler))]
#[inline]
- pub fn par_for_each_module(&self, f: impl Fn(LocalDefId)) {
+ pub fn par_for_each_module(self, f: impl Fn(LocalDefId)) {
self.for_each_module(f)
}
#[cfg(parallel_compiler)]
- pub fn par_for_each_module(&self, f: impl Fn(LocalDefId) + Sync) {
+ pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync) {
use rustc_data_structures::sync::{par_iter, ParallelIterator};
par_iter_submodules(self.tcx, CRATE_DEF_ID, &f);
@@ -698,7 +721,7 @@
}
/// Checks if the node is left-hand side of an assignment.
- pub fn is_lhs(&self, id: HirId) -> bool {
+ pub fn is_lhs(self, id: HirId) -> bool {
match self.find(self.get_parent_node(id)) {
Some(Node::Expr(expr)) => match expr.kind {
ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
@@ -710,7 +733,7 @@
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
/// Used exclusively for diagnostics, to avoid suggestion function calls.
- pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
+ pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
self.body_const_context(self.local_def_id(self.enclosing_body_owner(hir_id))).is_some()
}
@@ -736,7 +759,7 @@
/// false
/// }
/// ```
- pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
+ pub fn get_return_block(self, id: HirId) -> Option<HirId> {
let mut iter = self.parent_iter(id).peekable();
let mut ignore_tail = false;
if let Some(node) = self.find(id) {
@@ -776,23 +799,23 @@
/// parent item is in this map. The "parent item" is the closest parent node
/// 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 {
- if let Some((hir_id, _node)) = self.parent_owner_iter(hir_id).next() {
- hir_id
+ pub fn get_parent_item(self, hir_id: HirId) -> LocalDefId {
+ if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
+ def_id
} else {
- CRATE_HIR_ID
+ CRATE_DEF_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) {
+ pub(super) fn get_module_parent_node(self, hir_id: HirId) -> LocalDefId {
+ for (def_id, node) in self.parent_owner_iter(hir_id) {
if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
- return hir_id;
+ return def_id;
}
}
- CRATE_HIR_ID
+ CRATE_DEF_ID
}
/// When on an if expression, a match arm tail expression or a match arm, give back
@@ -800,7 +823,7 @@
///
/// Used by error reporting when there's a type error in an if or match arm caused by the
/// expression needing to be unit.
- pub fn get_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
+ pub fn get_if_cause(self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
for (_, node) in self.parent_iter(hir_id) {
match node {
Node::Item(_)
@@ -818,7 +841,7 @@
}
/// Returns the nearest enclosing scope. A scope is roughly an item or block.
- pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
+ pub fn get_enclosing_scope(self, hir_id: HirId) -> Option<HirId> {
for (hir_id, node) in self.parent_iter(hir_id) {
if let Node::Item(Item {
kind:
@@ -845,7 +868,7 @@
}
/// Returns the defining scope for an opaque type definition.
- pub fn get_defining_scope(&self, id: HirId) -> HirId {
+ pub fn get_defining_scope(self, id: HirId) -> HirId {
let mut scope = id;
loop {
scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
@@ -855,50 +878,49 @@
}
}
- pub fn get_parent_did(&self, id: HirId) -> LocalDefId {
- self.local_def_id(self.get_parent_item(id))
- }
-
- pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
+ pub fn get_foreign_abi(self, hir_id: HirId) -> Abi {
let parent = self.get_parent_item(hir_id);
- if let Some(node) = self.tcx.hir_owner(self.local_def_id(parent)) {
+ if let Some(node) = self.tcx.hir_owner(parent) {
if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
{
return *abi;
}
}
- bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
+ bug!(
+ "expected foreign mod or inlined parent, found {}",
+ self.node_to_string(HirId::make_owner(parent))
+ )
}
- pub fn expect_item(&self, id: LocalDefId) -> &'hir Item<'hir> {
+ pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::Item(item), .. }) => item,
_ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_impl_item(&self, id: LocalDefId) -> &'hir ImplItem<'hir> {
+ pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
_ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_trait_item(&self, id: LocalDefId) -> &'hir TraitItem<'hir> {
+ pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
_ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_variant(&self, id: HirId) -> &'hir Variant<'hir> {
+ pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> {
match self.find(id) {
Some(Node::Variant(variant)) => variant,
_ => bug!("expected variant, found {}", self.node_to_string(id)),
}
}
- pub fn expect_foreign_item(&self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+ pub fn expect_foreign_item(self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
_ => {
@@ -907,14 +929,14 @@
}
}
- pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
+ pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
match self.find(id) {
Some(Node::Expr(expr)) => expr,
_ => bug!("expected expr, found {}", self.node_to_string(id)),
}
}
- pub fn opt_name(&self, id: HirId) -> Option<Symbol> {
+ pub fn opt_name(self, id: HirId) -> Option<Symbol> {
Some(match self.get(id) {
Node::Item(i) => i.ident.name,
Node::ForeignItem(fi) => fi.ident.name,
@@ -925,12 +947,12 @@
Node::Lifetime(lt) => lt.name.ident().name,
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::Ctor(..) => self.name(HirId::make_owner(self.get_parent_item(id))),
_ => return None,
})
}
- pub fn name(&self, id: HirId) -> Symbol {
+ pub fn name(self, id: HirId) -> Symbol {
match self.opt_name(id) {
Some(name) => name,
None => bug!("no name for {}", self.node_to_string(id)),
@@ -939,18 +961,18 @@
/// Given a node ID, gets a list of attributes associated with the AST
/// corresponding to the node-ID.
- pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
+ pub fn attrs(self, id: HirId) -> &'hir [ast::Attribute] {
self.tcx.hir_attrs(id.owner).get(id.local_id)
}
/// Gets the span of the definition of the specified HIR node.
/// This is used by `tcx.get_span`
- pub fn span(&self, hir_id: HirId) -> Span {
+ pub fn span(self, hir_id: HirId) -> Span {
self.opt_span(hir_id)
.unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id))
}
- pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
+ pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
let span = match self.find(hir_id)? {
Node::Param(param) => param.span,
Node::Item(item) => match &item.kind {
@@ -999,7 +1021,7 @@
/// Like `hir.span()`, but includes the body of function items
/// (instead of just the function header)
- pub fn span_with_body(&self, hir_id: HirId) -> Span {
+ pub fn span_with_body(self, hir_id: HirId) -> Span {
match self.find(hir_id) {
Some(Node::TraitItem(item)) => item.span,
Some(Node::ImplItem(impl_item)) => impl_item.span,
@@ -1009,11 +1031,11 @@
}
}
- pub fn span_if_local(&self, id: DefId) -> Option<Span> {
+ pub fn span_if_local(self, id: DefId) -> Option<Span> {
id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id)))
}
- pub fn res_span(&self, res: Res) -> Option<Span> {
+ pub fn res_span(self, res: Res) -> Option<Span> {
match res {
Res::Err => None,
Res::Local(id) => Some(self.span(id)),
@@ -1023,13 +1045,13 @@
/// Get a representation of this `id` for debugging purposes.
/// NOTE: Do NOT use this in diagnostics!
- pub fn node_to_string(&self, id: HirId) -> String {
+ 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> {
+ 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,
@@ -1043,27 +1065,27 @@
impl<'hir> intravisit::Map<'hir> for Map<'hir> {
fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
- self.find(hir_id)
+ (*self).find(hir_id)
}
fn body(&self, id: BodyId) -> &'hir Body<'hir> {
- self.body(id)
+ (*self).body(id)
}
fn item(&self, id: ItemId) -> &'hir Item<'hir> {
- self.item(id)
+ (*self).item(id)
}
fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- self.trait_item(id)
+ (*self).trait_item(id)
}
fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- self.impl_item(id)
+ (*self).impl_item(id)
}
fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- self.foreign_item(id)
+ (*self).foreign_item(id)
}
}
@@ -1101,7 +1123,7 @@
.owners
.iter_enumerated()
.filter_map(|(def_id, info)| {
- let _ = info.as_ref()?;
+ let _ = info.as_owner()?;
let def_path_hash = definitions.def_path_hash(def_id);
let span = definitions.def_span(def_id);
debug_assert_eq!(span.parent(), None);
@@ -1132,7 +1154,7 @@
upstream_crates
}
-fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
+fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
let id_str = format!(" (hir_id={})", id);
let path_str = || {
@@ -1256,10 +1278,10 @@
}
impl<'hir> Visitor<'hir> for ModuleCollector<'hir> {
- type Map = Map<'hir>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'hir Item<'hir>) {
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 95d7273..1053f0c 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -2,8 +2,8 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-pub mod exports;
pub mod map;
+pub mod nested_filter;
pub mod place;
use crate::ty::query::Providers;
@@ -59,26 +59,33 @@
pub fn provide(providers: &mut Providers) {
providers.parent_module_from_def_id = |tcx, id| {
let hir = tcx.hir();
- hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
+ hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
};
providers.hir_crate = |tcx, ()| tcx.untracked_crate;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.hir_owner = |tcx, id| {
- let owner = tcx.hir_crate(()).owners[id].as_ref()?;
+ let owner = tcx.hir_crate(()).owners.get(id)?.as_owner()?;
let node = owner.node();
Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
};
- providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes);
+ providers.local_def_id_to_hir_id = |tcx, id| {
+ let owner = tcx.hir_crate(()).owners[id].map(|_| ());
+ match owner {
+ MaybeOwner::Owner(_) => HirId::make_owner(id),
+ MaybeOwner::Phantom => bug!("No HirId for {:?}", id),
+ MaybeOwner::NonOwner(hir_id) => hir_id,
+ }
+ };
+ providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].map(|i| &i.nodes);
providers.hir_owner_parent = |tcx, id| {
// Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash.
let parent = tcx.untracked_resolutions.definitions.def_key(id).parent;
let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| {
let def_id = LocalDefId { local_def_index };
- let mut parent_hir_id =
- tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id);
+ let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
if let Some(local_id) =
- tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id)
+ tcx.hir_crate(()).owners[parent_hir_id.owner].unwrap().parenting.get(&id)
{
parent_hir_id.local_id = *local_id;
}
@@ -87,7 +94,7 @@
parent
};
providers.hir_attrs =
- |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs);
+ |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs);
providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
providers.fn_arg_names = |tcx, id| {
@@ -111,4 +118,6 @@
let id = id.expect_local();
tcx.resolutions(()).definitions.expansion_that_defined(id)
};
+ providers.in_scope_traits_map =
+ |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map(|owner_info| &owner_info.trait_map);
}
diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs
new file mode 100644
index 0000000..7cfb207
--- /dev/null
+++ b/compiler/rustc_middle/src/hir/nested_filter.rs
@@ -0,0 +1,27 @@
+use rustc_hir::intravisit::nested_filter::NestedFilter;
+
+/// Do not visit nested item-like things, but visit nested things
+/// that are inside of an item-like.
+///
+/// **This is the most common choice.** A very common pattern is
+/// to use `visit_all_item_likes()` as an outer loop,
+/// and to have the visitor that visits the contents of each item
+/// using this setting.
+pub struct OnlyBodies(());
+impl<'hir> NestedFilter<'hir> for OnlyBodies {
+ type Map = crate::hir::map::Map<'hir>;
+ const INTER: bool = false;
+ const INTRA: bool = true;
+}
+
+/// Visits all nested things, including item-likes.
+///
+/// **This is an unusual choice.** It is used when you want to
+/// process everything within their lexical context. Typically you
+/// kick off the visit by doing `walk_krate()`.
+pub struct All(());
+impl<'hir> NestedFilter<'hir> for All {
+ type Map = crate::hir::map::Map<'hir>;
+ const INTER: bool = true;
+ const INTRA: bool = true;
+}
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 605fff6..419ed42 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -23,7 +23,7 @@
use crate::infer::MemberConstraint;
use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, TyCtxt};
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use smallvec::SmallVec;
@@ -64,9 +64,9 @@
/// result.
#[derive(Clone, Debug)]
pub struct OriginalQueryValues<'tcx> {
- /// Map from the universes that appear in the query to the
- /// universes in the caller context. For the time being, we only
- /// ever put ROOT values into the query, so this map is very
+ /// Map from the universes that appear in the query to the universes in the
+ /// caller context. For all queries except `evaluate_goal` (used by Chalk),
+ /// we only ever put ROOT values into the query, so this map is very
/// simple.
pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
@@ -104,7 +104,7 @@
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
- CanonicalVarKind::Const(_) => true,
+ CanonicalVarKind::Const(..) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
}
}
@@ -130,7 +130,7 @@
PlaceholderRegion(ty::PlaceholderRegion),
/// Some kind of const inference variable.
- Const(ty::UniverseIndex),
+ Const(ty::UniverseIndex, Ty<'tcx>),
/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst<'tcx>),
@@ -147,7 +147,7 @@
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
- CanonicalVarKind::Const(ui) => ui,
+ CanonicalVarKind::Const(ui, _) => ui,
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
}
}
@@ -328,8 +328,8 @@
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
GenericArgKind::Const(ct) => tcx
- .mk_const(ty::Const {
- ty: ct.ty,
+ .mk_const(ty::ConstS {
+ ty: ct.ty(),
val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
})
.into(),
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index dcc49a5..dd303aa 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -32,9 +32,11 @@
impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
type Value = UnifiedRegion<'tcx>;
+ #[inline]
fn index(&self) -> u32 {
self.vid.as_u32()
}
+ #[inline]
fn from_index(i: u32) -> Self {
RegionVidKey::from(ty::RegionVid::from_u32(i))
}
@@ -95,14 +97,14 @@
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
- Known { value: &'tcx ty::Const<'tcx> },
+ Known { value: ty::Const<'tcx> },
Unknown { universe: ty::UniverseIndex },
}
impl<'tcx> ConstVariableValue<'tcx> {
/// If this value is known, returns the const it is known to be.
/// Otherwise, `None`.
- pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> {
+ pub fn known(&self) -> Option<ty::Const<'tcx>> {
match *self {
ConstVariableValue::Unknown { .. } => None,
ConstVariableValue::Known { value } => Some(value),
@@ -118,9 +120,11 @@
impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
type Value = ConstVarValue<'tcx>;
+ #[inline]
fn index(&self) -> u32 {
self.index
}
+ #[inline]
fn from_index(i: u32) -> Self {
ty::ConstVid { index: i, phantom: PhantomData }
}
@@ -130,7 +134,7 @@
}
impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
- type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
+ type Error = (ty::Const<'tcx>, ty::Const<'tcx>);
fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
Ok(match (value1.val, value2.val) {
@@ -162,18 +166,18 @@
}
}
-impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
+impl<'tcx> EqUnifyValue for ty::Const<'tcx> {}
pub fn replace_if_possible<'tcx, V, L>(
table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>, V, L>>,
- c: &'tcx ty::Const<'tcx>,
-) -> &'tcx ty::Const<'tcx>
+ c: ty::Const<'tcx>,
+) -> ty::Const<'tcx>
where
V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>,
L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>,
{
- if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c {
- match table.probe_value(*vid).val.known() {
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = c.val() {
+ match table.probe_value(vid).val.known() {
Some(c) => c,
None => c,
}
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index e6dd4e4..e85cb41 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -56,6 +56,7 @@
#![feature(nonzero_ops)]
#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate bitflags;
@@ -84,6 +85,7 @@
pub mod hir;
pub mod infer;
pub mod lint;
+pub mod metadata;
pub mod middle;
pub mod mir;
pub mod thir;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index eef1035..17c77c1 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -221,7 +221,6 @@
decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
) {
// Check for future incompatibility lints and issue a stronger warning.
- let lint_id = LintId::of(lint);
let future_incompatible = lint.future_incompatible;
let has_future_breakage = future_incompatible.map_or(
@@ -262,7 +261,7 @@
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
// Any suggestions made here are likely to be incorrect, so anything we
// emit shouldn't be automatically fixed by rustfix.
- err.allow_suggestions(false);
+ err.disable_suggestions();
// If this is a future incompatible that is not an edition fixing lint
// it'll become a hard error, so we have to emit *something*. Also,
@@ -345,31 +344,29 @@
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
if let Some(future_incompatible) = future_incompatible {
- let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
- "once this associated item is added to the standard library, the ambiguity may \
- cause an error or change in behavior!"
- .to_owned()
- } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
- "this borrowing pattern was not meant to be accepted, and may become a hard error \
- in the future"
- .to_owned()
- } else if let FutureIncompatibilityReason::EditionError(edition) =
- future_incompatible.reason
- {
- let current_edition = sess.edition();
- format!(
- "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!",
- current_edition, edition
- )
- } else if let FutureIncompatibilityReason::EditionSemanticsChange(edition) =
- future_incompatible.reason
- {
- format!("this changes meaning in Rust {}", edition)
- } else {
- "this was previously accepted by the compiler but is being phased out; \
- it will become a hard error in a future release!"
- .to_owned()
+ let explanation = match future_incompatible.reason {
+ FutureIncompatibilityReason::FutureReleaseError
+ | FutureIncompatibilityReason::FutureReleaseErrorReportNow => {
+ "this was previously accepted by the compiler but is being phased out; \
+ it will become a hard error in a future release!"
+ .to_owned()
+ }
+ FutureIncompatibilityReason::FutureReleaseSemanticsChange => {
+ "this will change its meaning in a future release!".to_owned()
+ }
+ FutureIncompatibilityReason::EditionError(edition) => {
+ let current_edition = sess.edition();
+ format!(
+ "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!",
+ current_edition, edition
+ )
+ }
+ FutureIncompatibilityReason::EditionSemanticsChange(edition) => {
+ format!("this changes meaning in Rust {}", edition)
+ }
+ FutureIncompatibilityReason::Custom(reason) => reason.to_owned(),
};
+
if future_incompatible.explain_reason {
err.warn(&explanation);
}
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
new file mode 100644
index 0000000..6dcdc58
--- /dev/null
+++ b/compiler/rustc_middle/src/metadata.rs
@@ -0,0 +1,24 @@
+use crate::ty;
+
+use rustc_hir::def::Res;
+use rustc_macros::HashStable;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates
+/// during name resolution. Right now the bindings are not recreated entirely precisely so we may
+/// need to add more data in the future to correctly support macros 2.0, for example.
+/// Module child can be either a proper item or a reexport (including private imports).
+/// In case of reexport all the fields describe the reexport item itself, not what it refers to.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ModChild {
+ /// Name of the item.
+ pub ident: Ident,
+ /// Resolution result corresponding to the item.
+ /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
+ pub res: Res<!>,
+ /// Visibility of the item.
+ pub vis: ty::Visibility,
+ /// Span of the item.
+ pub span: Span,
+}
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index b054d21a..54eb2dc 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -89,6 +89,8 @@
/// the MIR `InstrumentCoverage` pass and not added to the coverage map
/// during codegen.
const NO_COVERAGE = 1 << 15;
+ /// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function.
+ const USED_LINKER = 1 << 16;
}
}
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index f33bd34..ff993ac 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -28,7 +28,7 @@
}
/// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct AccessLevels<Id = LocalDefId> {
pub map: FxHashMap<Id, AccessLevel>,
}
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 39ca41c..75dd223 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -308,7 +308,7 @@
/// The reason is that semantically, until the `box` expression returns,
/// the values are still owned by their containing expressions. So
/// we'll see that `&x`.
- pub yield_in_scope: FxHashMap<Scope, YieldData>,
+ pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,
/// The number of visit_expr and visit_pat calls done in the body.
/// Used to sanity check visit_expr/visit_pat call count when
@@ -423,8 +423,8 @@
/// Checks whether the given scope contains a `yield`. If so,
/// returns `Some(YieldData)`. If not, returns `None`.
- pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
- self.yield_in_scope.get(&scope).cloned()
+ pub fn yield_in_scope(&self, scope: Scope) -> Option<&Vec<YieldData>> {
+ self.yield_in_scope.get(&scope)
}
/// Gives the number of expressions visited in a body.
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 175d31d..fedf456 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -29,7 +29,7 @@
}
/// An entry in the `depr_map`.
-#[derive(Clone, HashStable, Debug)]
+#[derive(Copy, Clone, HashStable, Debug)]
pub struct DeprecationEntry {
/// The metadata of the attribute associated with this entry.
pub attr: Deprecation,
@@ -198,7 +198,7 @@
} else {
let since = since.as_ref().map(Symbol::as_str);
- if since.as_deref() == Some("TBD") {
+ if since == Some("TBD") {
format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path)
} else {
format!(
@@ -348,7 +348,7 @@
// Deprecated attributes apply in-crate and cross-crate.
if let Some(id) = id {
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
- let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id));
+ let parent_def_id = self.hir().get_parent_item(id);
let skip = self
.lookup_deprecation_entry(parent_def_id.to_def_id())
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
index 5f02897..e2f3d6e 100644
--- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
+++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
@@ -45,8 +45,9 @@
impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache {
#[inline]
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+ fn decode(d: &mut D) -> Self {
+ let () = serialize::Decodable::decode(d);
+ Self::new()
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b762a10..66f2c6e 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -273,20 +273,20 @@
impl<'s> AllocDecodingSession<'s> {
/// Decodes an `AllocId` in a thread-safe way.
- pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> Result<AllocId, D::Error>
+ pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
where
D: TyDecoder<'tcx>,
{
// Read the index of the allocation.
- let idx = usize::try_from(decoder.read_u32()?).unwrap();
+ let idx = usize::try_from(decoder.read_u32()).unwrap();
let pos = usize::try_from(self.state.data_offsets[idx]).unwrap();
// Decode the `AllocDiscriminant` now so that we know if we have to reserve an
// `AllocId`.
let (alloc_kind, pos) = decoder.with_position(pos, |decoder| {
- let alloc_kind = AllocDiscriminant::decode(decoder)?;
- Ok((alloc_kind, decoder.position()))
- })?;
+ let alloc_kind = AllocDiscriminant::decode(decoder);
+ (alloc_kind, decoder.position())
+ });
// Check the decoding state to see if it's already decoded or if we should
// decode it here.
@@ -295,7 +295,7 @@
match *entry {
State::Done(alloc_id) => {
- return Ok(alloc_id);
+ return alloc_id;
}
ref mut entry @ State::Empty => {
// We are allowed to decode.
@@ -329,7 +329,7 @@
State::InProgress(ref mut sessions, alloc_id) => {
if sessions.contains(&self.session_id) {
// Don't recurse.
- return Ok(alloc_id);
+ return alloc_id;
} else {
// Start decoding concurrently.
sessions.insert(self.session_id);
@@ -343,37 +343,37 @@
let alloc_id = decoder.with_position(pos, |decoder| {
match alloc_kind {
AllocDiscriminant::Alloc => {
- let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder)?;
+ let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder);
// We already have a reserved `AllocId`.
let alloc_id = alloc_id.unwrap();
trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc);
- Ok(alloc_id)
+ alloc_id
}
AllocDiscriminant::Fn => {
assert!(alloc_id.is_none());
trace!("creating fn alloc ID");
- let instance = ty::Instance::decode(decoder)?;
+ let instance = ty::Instance::decode(decoder);
trace!("decoded fn alloc instance: {:?}", instance);
let alloc_id = decoder.tcx().create_fn_alloc(instance);
- Ok(alloc_id)
+ alloc_id
}
AllocDiscriminant::Static => {
assert!(alloc_id.is_none());
trace!("creating extern static alloc ID");
- let did = <DefId as Decodable<D>>::decode(decoder)?;
+ let did = <DefId as Decodable<D>>::decode(decoder);
trace!("decoded static def-ID: {:?}", did);
let alloc_id = decoder.tcx().create_static_alloc(did);
- Ok(alloc_id)
+ alloc_id
}
}
- })?;
+ });
self.state.decoding_state[idx].with_lock(|entry| {
*entry = State::Done(alloc_id);
});
- Ok(alloc_id)
+ alloc_id
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index f983185..4a57f48 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(self)) {
+ match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
@@ -98,4 +98,12 @@
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
}
+
+ /// Destructure a constant ADT or array into its variant index and its field values.
+ pub fn destructure_const(
+ self,
+ param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>,
+ ) -> mir::DestructuredConst<'tcx> {
+ self.try_destructure_const(param_env_and_val).unwrap()
+ }
}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 52ef380..7e5f801 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -13,6 +13,7 @@
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
+use rustc_errors::ErrorReported;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::{self, GeneratorKind};
@@ -162,7 +163,7 @@
}
/// Where a specific `mir::Body` comes from.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)]
pub struct MirSource<'tcx> {
pub instance: InstanceDef<'tcx>,
@@ -284,11 +285,12 @@
predecessor_cache: PredecessorCache,
is_cyclic: GraphIsCyclicCache,
+
+ pub tainted_by_errors: Option<ErrorReported>,
}
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>>,
@@ -298,6 +300,7 @@
var_debug_info: Vec<VarDebugInfo<'tcx>>,
span: Span,
generator_kind: Option<GeneratorKind>,
+ tainted_by_errors: Option<ErrorReported>,
) -> Self {
// We need `arg_count` locals, and one for the return place.
assert!(
@@ -330,8 +333,9 @@
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
+ tainted_by_errors,
};
- body.is_polymorphic = body.definitely_has_param_types_or_consts(tcx);
+ body.is_polymorphic = body.has_param_types_or_consts();
body
}
@@ -341,7 +345,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 {
- Body {
+ let mut body = Body {
phase: MirPhase::Build,
source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
basic_blocks,
@@ -357,7 +361,10 @@
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
- }
+ tainted_by_errors: None,
+ };
+ body.is_polymorphic = body.has_param_types_or_consts();
+ body
}
#[inline]
@@ -618,20 +625,20 @@
}
impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
#[inline]
- fn decode(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> {
+ fn decode(d: &mut D) -> ClearCrossCrate<T> {
if D::CLEAR_CROSS_CRATE {
- return Ok(ClearCrossCrate::Clear);
+ return ClearCrossCrate::Clear;
}
- let discr = u8::decode(d)?;
+ let discr = u8::decode(d);
match discr {
- TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(ClearCrossCrate::Clear),
+ TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear,
TAG_CLEAR_CROSS_CRATE_SET => {
- let val = T::decode(d)?;
- Ok(ClearCrossCrate::Set(val))
+ let val = T::decode(d);
+ ClearCrossCrate::Set(val)
}
- tag => Err(d.error(&format!("Invalid tag for ClearCrossCrate: {:?}", tag))),
+ tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag),
}
}
}
@@ -893,7 +900,7 @@
/// across a suspension point against the type components of the generator
/// which type checking knows are live across a suspension point. We need to
/// flag drop flags to avoid triggering this check as they are introduced
- /// after typeck.
+ /// outside of type inference.
///
/// This should be sound because the drop flags are fully algebraic, and
/// therefore don't affect the auto-trait or outlives properties of the
@@ -1254,17 +1261,7 @@
ResumedAfterPanic(GeneratorKind),
}
-#[derive(
- Clone,
- Debug,
- PartialEq,
- PartialOrd,
- TyEncodable,
- TyDecodable,
- Hash,
- HashStable,
- TypeFoldable
-)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
pub enum InlineAsmOperand<'tcx> {
In {
reg: InlineAsmRegOrRegClass,
@@ -1565,10 +1562,6 @@
/// End the current live range for the storage of the local.
StorageDead(Local),
- /// Executes a piece of inline Assembly. Stored in a Box to keep the size
- /// of `StatementKind` low.
- LlvmInlineAsm(Box<LlvmInlineAsm<'tcx>>),
-
/// Retag references in the given place, ensuring they got fresh tags. This is
/// part of the Stacked Borrows model. These statements are currently only interpreted
/// by miri and only generated when "-Z mir-emit-retag" is passed.
@@ -1590,7 +1583,7 @@
/// - `Bivariant` -- no effect
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
- /// Marks the start of a "coverage region", injected with '-Zinstrument-coverage'. A
+ /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
/// `Coverage` statement carries metadata about the coverage region, used to inject a coverage
/// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates
/// executable code, to increment a counter variable at runtime, each time the code region is
@@ -1655,7 +1648,7 @@
ForMatchedPlace(Option<DefId>),
/// A fake read of the RefWithinGuard version of a bind-by-value variable
- /// in a match guard to ensure that it's value hasn't change by the time
+ /// in a match guard to ensure that its value hasn't change by the time
/// we create the OutsideGuard version.
ForGuardBinding,
@@ -1688,13 +1681,6 @@
ForIndex,
}
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
-pub struct LlvmInlineAsm<'tcx> {
- pub asm: hir::LlvmInlineAsmInner,
- pub outputs: Box<[Place<'tcx>]>,
- pub inputs: Box<[(Span, Operand<'tcx>)]>,
-}
-
impl Debug for Statement<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::StatementKind::*;
@@ -1719,9 +1705,6 @@
SetDiscriminant { ref place, variant_index } => {
write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
}
- LlvmInlineAsm(ref asm) => {
- write!(fmt, "llvm_asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
- }
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}
@@ -1760,7 +1743,7 @@
/// A path to a value; something that can be evaluated without
/// changing or disturbing program state.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)]
pub struct Place<'tcx> {
pub local: Local,
@@ -2085,7 +2068,7 @@
/// These are values that can appear inside an rvalue. They are intentionally
/// limited to prevent rvalues from being nested in one another.
-#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum Operand<'tcx> {
/// Copy: The value must be available for use afterwards.
///
@@ -2202,7 +2185,7 @@
Use(Operand<'tcx>),
/// [x; 32]
- Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>),
+ Repeat(Operand<'tcx>, ty::Const<'tcx>),
/// &x or &mut x
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
@@ -2287,11 +2270,13 @@
Mul,
/// The `/` operator (division)
///
- /// Division by zero is UB.
+ /// Division by zero is UB, because the compiler should have inserted checks
+ /// prior to this.
Div,
/// The `%` operator (modulus)
///
- /// Using zero as the modulus (second operand) is UB.
+ /// Using zero as the modulus (second operand) is UB, because the compiler
+ /// should have inserted checks prior to this.
Rem,
/// The `^` operator (bitwise xor)
BitXor,
@@ -2352,7 +2337,7 @@
match *self {
Use(ref place) => write!(fmt, "{:?}", place),
- Repeat(ref a, ref b) => {
+ Repeat(ref a, b) => {
write!(fmt, "[{:?}; ", a)?;
pretty_print_const(b, fmt, false)?;
write!(fmt, "]")
@@ -2439,7 +2424,7 @@
CtorKind::Fictive => {
let mut struct_fmt = fmt.debug_struct(&name);
for (field, place) in iter::zip(&variant_def.fields, places) {
- struct_fmt.field(field.ident.as_str(), place);
+ struct_fmt.field(field.name.as_str(), place);
}
struct_fmt.finish()
}
@@ -2449,7 +2434,6 @@
AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| {
if let Some(def_id) = def_id.as_local() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let name = if tcx.sess.opts.debugging_opts.span_free_formats {
let substs = tcx.lift(substs).unwrap();
format!(
@@ -2457,7 +2441,7 @@
tcx.def_path_str_with_substs(def_id.to_def_id(), substs),
)
} else {
- let span = tcx.hir().span(hir_id);
+ let span = tcx.def_span(def_id);
format!(
"[closure@{}]",
tcx.sess.source_map().span_to_diagnostic_string(span)
@@ -2481,8 +2465,7 @@
AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| {
if let Some(def_id) = def_id.as_local() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let name = format!("[generator@{:?}]", tcx.hir().span(hir_id));
+ let name = format!("[generator@{:?}]", tcx.def_span(def_id));
let mut struct_fmt = fmt.debug_struct(&name);
// FIXME(project-rfc-2229#48): This should be a list of capture names/places
@@ -2515,7 +2498,7 @@
/// this does not necessarily mean that they are `==` in Rust. In
/// particular, one must be wary of `NaN`!
-#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
pub struct Constant<'tcx> {
pub span: Span,
@@ -2529,11 +2512,11 @@
pub literal: ConstantKind<'tcx>,
}
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
#[derive(Lift)]
pub enum ConstantKind<'tcx> {
/// This constant came from the type system
- Ty(&'tcx ty::Const<'tcx>),
+ Ty(ty::Const<'tcx>),
/// This constant cannot go back into the type system, as it represents
/// something the type system cannot handle (e.g. pointers).
Val(interpret::ConstValue<'tcx>, Ty<'tcx>),
@@ -2541,7 +2524,7 @@
impl<'tcx> Constant<'tcx> {
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
- match self.literal.const_for_ty()?.val.try_to_scalar() {
+ match self.literal.try_to_scalar() {
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
@@ -2558,33 +2541,33 @@
}
}
-impl<'tcx> From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> {
+impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
#[inline]
- fn from(ct: &'tcx ty::Const<'tcx>) -> Self {
+ fn from(ct: ty::Const<'tcx>) -> Self {
Self::Ty(ct)
}
}
impl<'tcx> ConstantKind<'tcx> {
/// Returns `None` if the constant is not trivially safe for use in the type system.
- pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> {
+ pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> {
match self {
- ConstantKind::Ty(c) => Some(c),
+ ConstantKind::Ty(c) => Some(*c),
ConstantKind::Val(..) => None,
}
}
pub fn ty(&self) -> Ty<'tcx> {
match self {
- ConstantKind::Ty(c) => c.ty,
- ConstantKind::Val(_, ty) => ty,
+ ConstantKind::Ty(c) => c.ty(),
+ ConstantKind::Val(_, ty) => *ty,
}
}
#[inline]
pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
match self {
- ConstantKind::Ty(c) => c.val.try_to_value(),
+ ConstantKind::Ty(c) => c.val().try_to_value(),
ConstantKind::Val(val, _) => Some(val),
}
}
@@ -2785,7 +2768,7 @@
field: Field,
) -> Self {
self.projs.push(ProjectionElem::Downcast(
- Some(adt_def.variants[variant_index].ident.name),
+ Some(adt_def.variants[variant_index].name),
variant_index,
));
self.projs.push(ProjectionElem::Field(field, ()));
@@ -2848,7 +2831,7 @@
}
fn pretty_print_const<'tcx>(
- c: &ty::Const<'tcx>,
+ c: ty::Const<'tcx>,
fmt: &mut Formatter<'_>,
print_types: bool,
) -> fmt::Result {
@@ -2964,7 +2947,7 @@
let mut visited = FxHashSet::default();
while let Some(block) = queue.pop() {
- // If we haven't visited this block before, then make sure we visit it's predecessors.
+ // If we haven't visited this block before, then make sure we visit its predecessors.
if visited.insert(block) {
queue.extend(predecessors[block].iter().cloned());
} else {
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 1422537..8928083 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -179,15 +179,11 @@
pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
match *self {
- MonoItem::Fn(Instance { def, .. }) => {
- def.def_id().as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- }
- MonoItem::Static(def_id) => {
- def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- }
- MonoItem::GlobalAsm(item_id) => Some(item_id.hir_id()),
+ MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(),
+ MonoItem::Static(def_id) => def_id.as_local(),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.def_id),
}
- .map(|hir_id| tcx.hir().span(hir_id))
+ .map(|def_id| tcx.def_span(def_id))
}
// Only used by rustc_codegen_cranelift
@@ -247,6 +243,9 @@
items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
size_estimate: Option<usize>,
primary: bool,
+ /// True if this is CGU is used to hold code coverage information for dead code,
+ /// false otherwise.
+ is_code_coverage_dead_code_cgu: bool,
}
/// Specifies the linkage type for a `MonoItem`.
@@ -277,7 +276,13 @@
impl<'tcx> CodegenUnit<'tcx> {
#[inline]
pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
- CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
+ CodegenUnit {
+ name,
+ items: Default::default(),
+ size_estimate: None,
+ primary: false,
+ is_code_coverage_dead_code_cgu: false,
+ }
}
pub fn name(&self) -> Symbol {
@@ -304,6 +309,15 @@
&mut self.items
}
+ pub fn is_code_coverage_dead_code_cgu(&self) -> bool {
+ self.is_code_coverage_dead_code_cgu
+ }
+
+ /// Marks this CGU as the one used to contain code coverage information for dead code.
+ pub fn make_code_coverage_dead_code_cgu(&mut self) {
+ self.is_code_coverage_dead_code_cgu = true;
+ }
+
pub fn mangle_name(human_readable_name: &str) -> String {
// We generate a 80 bit hash from the name. This should be enough to
// avoid collisions and is still reasonably short for filenames.
@@ -404,9 +418,11 @@
// The size estimate is not relevant to the hash
size_estimate: _,
primary: _,
+ is_code_coverage_dead_code_cgu,
} = *self;
name.hash_stable(hcx, hasher);
+ is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher);
let mut items: Vec<(Fingerprint, _)> = items
.iter()
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
index fd6bb76..2562baac 100644
--- a/compiler/rustc_middle/src/mir/predecessors.rs
+++ b/compiler/rustc_middle/src/mir/predecessors.rs
@@ -57,14 +57,15 @@
impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache {
#[inline]
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- serialize::Encodable::encode(&(), s)
+ s.emit_unit()
}
}
impl<D: serialize::Decoder> serialize::Decodable<D> for PredecessorCache {
#[inline]
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+ fn decode(d: &mut D) -> Self {
+ let () = d.read_unit();
+ Self::new()
}
}
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 8cc7053..784babf 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -17,9 +17,8 @@
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::MirSource;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
use rustc_target::abi::Size;
-use std::ops::ControlFlow;
const INDENT: &str = " ";
/// Alignment for lining up comments following MIR statements
@@ -427,12 +426,12 @@
}
}
-fn use_verbose<'tcx>(ty: &&TyS<'tcx>, fn_def: bool) -> bool {
- match ty.kind() {
+fn use_verbose<'tcx>(ty: Ty<'tcx>, fn_def: bool) -> bool {
+ match *ty.kind() {
ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false,
// Unit type
ty::Tuple(g_args) if g_args.is_empty() => false,
- ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty(), fn_def)),
+ ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(g_arg.expect_ty(), fn_def)),
ty::Array(ty, _) => use_verbose(ty, fn_def),
ty::FnDef(..) => fn_def,
_ => true,
@@ -443,7 +442,7 @@
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
self.super_constant(constant, location);
let Constant { span, user_ty, literal } = constant;
- if use_verbose(&literal.ty(), true) {
+ if use_verbose(literal.ty(), true) {
self.push("mir::Constant");
self.push(&format!(
"+ span: {}",
@@ -462,9 +461,10 @@
}
}
- fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
+ fn visit_const(&mut self, constant: ty::Const<'tcx>, _: Location) {
self.super_const(constant);
- let ty::Const { ty, val, .. } = constant;
+ let ty = constant.ty();
+ let val = constant.val();
if use_verbose(ty, false) {
self.push("ty::Const");
self.push(&format!("+ ty: {:?}", ty));
@@ -476,8 +476,8 @@
ty::ConstKind::Unevaluated(uv) => format!(
"Unevaluated({}, {:?}, {:?})",
self.tcx.def_path_str(uv.def.did),
- uv.substs(self.tcx),
- uv.promoted
+ uv.substs,
+ uv.promoted,
),
ty::ConstKind::Value(val) => format!("Value({:?})", val),
ty::ConstKind::Error(_) => "Error".to_string(),
@@ -668,6 +668,7 @@
fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
alloc.relocations().values().map(|id| *id)
}
+
fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
match val {
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => {
@@ -681,23 +682,29 @@
}
}
}
- 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 {
+ struct CollectAllocIds(BTreeSet<AllocId>);
+
+ impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+ fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
+ if let ty::ConstKind::Value(val) = c.val() {
self.0.extend(alloc_ids_from_const(val));
}
- c.super_visit_with(self)
+ }
+
+ fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+ match c.literal {
+ ConstantKind::Ty(c) => self.visit_const(c, loc),
+ ConstantKind::Val(val, _) => {
+ self.0.extend(alloc_ids_from_const(val));
+ }
+ }
}
}
+
let mut visitor = CollectAllocIds(Default::default());
- body.visit_with(&mut visitor);
+ visitor.visit_body(body);
+
// `seen` contains all seen allocations, including the ones we have *not* printed yet.
// The protocol is to first `insert` into `seen`, and only if that returns `true`
// then push to `todo`.
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index cb3f385..fbd5a2d 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -214,6 +214,7 @@
pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
+ pub tainted_by_errors: Option<ErrorReported>,
}
/// The result of the `mir_const_qualif` query.
@@ -227,7 +228,7 @@
pub needs_drop: bool,
pub needs_non_const_drop: bool,
pub custom_eq: bool,
- pub error_occured: Option<ErrorReported>,
+ pub tainted_by_errors: Option<ErrorReported>,
}
/// After we borrow check a closure, we are left with various
@@ -340,7 +341,7 @@
/// like `Foo { field: my_val }`)
Usage,
OpaqueType,
- ClosureUpvar(hir::HirId),
+ ClosureUpvar(Field),
/// A constraint from a user-written predicate
/// with the provided span, written on the item
@@ -362,7 +363,7 @@
#[derive(TyEncodable, TyDecodable, HashStable)]
pub enum ReturnConstraint {
Normal,
- ClosureUpvar(hir::HirId),
+ ClosureUpvar(Field),
}
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
@@ -386,11 +387,11 @@
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
- pub fields: &'tcx [&'tcx ty::Const<'tcx>],
+ pub fields: &'tcx [ty::Const<'tcx>],
}
/// Coverage information summarized from a MIR if instrumented for source code coverage (see
-/// compiler option `-Zinstrument-coverage`). This information is generated by the
+/// compiler option `-Cinstrument-coverage`). This information is generated by the
/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
pub struct CoverageInfo {
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 507f997..965d30a 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -230,7 +230,7 @@
}
/// Format a string showing the start line and column, and end line and column within a file.
-pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String {
+pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
let source_map = tcx.sess.source_map();
let start = source_map.lookup_char_pos(span.lo());
let end = source_map.lookup_char_pos(span.hi());
@@ -245,7 +245,6 @@
SetDiscriminant { .. } => "SetDiscriminant",
StorageLive(..) => "StorageLive",
StorageDead(..) => "StorageDead",
- LlvmInlineAsm(..) => "LlvmInlineAsm",
Retag(..) => "Retag",
AscribeUserType(..) => "AscribeUserType",
Coverage(..) => "Coverage",
@@ -630,7 +629,7 @@
let mut text = Vec::new();
text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span)));
for statement in statements {
- let source_range = source_range_no_file(tcx, &statement.source_info.span);
+ let source_range = source_range_no_file(tcx, statement.source_info.span);
text.push(format!(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
@@ -640,7 +639,7 @@
));
}
if let Some(term) = terminator {
- let source_range = source_range_no_file(tcx, &term.source_info.span);
+ let source_range = source_range_no_file(tcx, term.source_info.span);
text.push(format!(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
@@ -665,9 +664,7 @@
}
fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
- let hir_id =
- tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
- let fn_decl_span = tcx.hir().span(hir_id);
+ let fn_decl_span = tcx.def_span(def_id);
if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span }
} else {
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index dc53dc8..302921c 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -57,7 +57,7 @@
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
- self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
+ self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, &ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -93,11 +93,11 @@
ProjectionElem::Subslice { from, to, from_end } => {
PlaceTy::from_ty(match self.ty.kind() {
ty::Slice(..) => self.ty,
- ty::Array(inner, _) if !from_end => tcx.mk_array(inner, (to - from) as u64),
+ ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
ty::Array(inner, size) if from_end => {
let size = size.eval_usize(tcx, param_env);
let len = size - (from as u64) - (to as u64);
- tcx.mk_array(inner, len)
+ tcx.mk_array(*inner, len)
}
_ => bug!("cannot subslice non-array type: `{:?}`", self),
})
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 51e4afa..ae94bd1 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -105,7 +105,7 @@
impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
pub enum TerminatorKind<'tcx> {
/// Block should have one successor in the graph; we jump there.
Goto { target: BasicBlock },
@@ -430,7 +430,7 @@
pub fn as_switch(&self) -> Option<(&Operand<'tcx>, Ty<'tcx>, &SwitchTargets)> {
match self {
TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
- Some((discr, switch_ty, targets))
+ Some((discr, *switch_ty, targets))
}
_ => None,
}
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 8c930fd..480f286 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -4,8 +4,9 @@
/// Preorder traversal of a graph.
///
-/// Preorder traversal is when each node is visited before any of its
-/// successors
+/// Preorder traversal is when each node is visited after at least one of its predecessors. If you
+/// are familar with some basic graph theory, then this performs a depth first search and returns
+/// nodes in order of discovery time.
///
/// ```text
///
@@ -82,8 +83,9 @@
/// Postorder traversal of a graph.
///
-/// Postorder traversal is when each node is visited after all of its
-/// successors, except when the successor is only reachable by a back-edge
+/// Postorder traversal is when each node is visited after all of its successors, except when the
+/// successor is only reachable by a back-edge. If you are familiar with some basic graph theory,
+/// then this performs a depth first search and returns nodes in order of completion time.
///
///
/// ```text
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index f301c68..a618800 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -194,13 +194,13 @@
}
fn visit_region(&mut self,
- region: & $($mutability)? ty::Region<'tcx>,
+ region: $(& $mutability)? ty::Region<'tcx>,
_: Location) {
self.super_region(region);
}
fn visit_const(&mut self,
- constant: & $($mutability)? &'tcx ty::Const<'tcx>,
+ constant: $(& $mutability)? ty::Const<'tcx>,
_: Location) {
self.super_const(constant);
}
@@ -242,7 +242,7 @@
) {
let span = body.span;
if let Some(gen) = &$($mutability)? body.generator {
- if let Some(yield_ty) = &$($mutability)? gen.yield_ty {
+ if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
@@ -266,7 +266,7 @@
}
self.visit_ty(
- &$($mutability)? body.return_ty(),
+ $(& $mutability)? body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost(body.span))
);
@@ -355,7 +355,7 @@
ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
ty::InstanceDef::CloneShim(_def_id, ty) => {
// FIXME(eddyb) use a better `TyContext` here.
- self.visit_ty(ty, TyContext::Location(location));
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
}
self.visit_substs(callee_substs, location);
@@ -408,19 +408,6 @@
location
);
}
- StatementKind::LlvmInlineAsm(asm) => {
- for output in & $($mutability)? asm.outputs[..] {
- self.visit_place(
- output,
- PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
- location
- );
- }
- for (span, input) in & $($mutability)? asm.inputs[..] {
- self.visit_span(span);
- self.visit_operand(input, location);
- }
- }
StatementKind::Retag(kind, place) => {
self.visit_retag(kind, place, location);
}
@@ -500,7 +487,7 @@
targets: _
} => {
self.visit_operand(discr, location);
- self.visit_ty(switch_ty, TyContext::Location(location));
+ self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location));
}
TerminatorKind::Drop {
@@ -654,7 +641,7 @@
Rvalue::ThreadLocalRef(_) => {}
Rvalue::Ref(r, bk, path) => {
- self.visit_region(r, location);
+ self.visit_region($(& $mutability)? *r, location);
let ctx = match bk {
BorrowKind::Shared => PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
@@ -693,7 +680,7 @@
Rvalue::Cast(_cast_kind, operand, ty) => {
self.visit_operand(operand, location);
- self.visit_ty(ty, TyContext::Location(location));
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
@@ -715,14 +702,14 @@
}
Rvalue::NullaryOp(_op, ty) => {
- self.visit_ty(ty, TyContext::Location(location));
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
Rvalue::Aggregate(kind, operands) => {
let kind = &$($mutability)? **kind;
match kind {
AggregateKind::Array(ty) => {
- self.visit_ty(ty, TyContext::Location(location));
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
AggregateKind::Tuple => {
}
@@ -757,7 +744,7 @@
Rvalue::ShallowInitBox(operand, ty) => {
self.visit_operand(operand, location);
- self.visit_ty(ty, TyContext::Location(location));
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
}
}
@@ -828,7 +815,7 @@
is_block_tail: _,
} = local_decl;
- self.visit_ty(ty, TyContext::LocalDecl {
+ self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
local,
source_info: *source_info,
});
@@ -877,8 +864,8 @@
self.visit_span(span);
drop(user_ty); // no visit method for this
match literal {
- ConstantKind::Ty(ct) => self.visit_const(ct, location),
- ConstantKind::Val(_, t) => self.visit_ty(t, TyContext::Location(location)),
+ ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location),
+ ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
}
}
@@ -907,16 +894,16 @@
ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
) {
self.visit_span(& $($mutability)? ty.span);
- self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
+ self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
}
fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
}
- fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) {
+ fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
}
- fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) {
+ fn super_const(&mut self, _const: $(& $mutability)? ty::Const<'tcx>) {
}
fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
@@ -1178,10 +1165,6 @@
pub enum MutatingUseContext {
/// Appears as LHS of an assignment.
Store,
- /// Can often be treated as a `Store`, but needs to be separate because
- /// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
- /// cannot be simplified the way a `Store`-`Store` can be.
- LlvmAsmOutput,
/// Output operand of an inline assembly block.
AsmOutput,
/// Destination of a call.
@@ -1271,7 +1254,6 @@
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Call
- | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput,
)
)
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b3db2e6..43cfe6f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -56,6 +56,14 @@
desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
}
+ /// Gives access to the HIR ID for the given `LocalDefId` owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
+ desc { |tcx| "HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
/// Gives access to the HIR node's parent for the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
@@ -68,7 +76,7 @@
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
+ query hir_owner_nodes(key: LocalDefId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
}
@@ -105,15 +113,11 @@
/// Given the def_id of a const-generic parameter, computes the associated default const
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
- query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> {
+ query const_param_default(param: DefId) -> ty::Const<'tcx> {
desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
separate_provide_extern
}
- 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|
@@ -211,7 +215,8 @@
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
}
- query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
+ query native_libraries(_: CrateNum) -> Vec<NativeLib> {
+ storage(ArenaCacheSelector<'tcx>)
desc { "looking up the native libraries of a linked crate" }
separate_provide_extern
}
@@ -250,13 +255,14 @@
/// Create a THIR tree for debugging.
query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
no_hash
+ storage(ArenaCacheSelector<'tcx>)
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.
- query mir_keys(_: ()) -> FxHashSet<LocalDefId> {
+ query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> {
storage(ArenaCacheSelector<'tcx>)
desc { "getting a list of all mir_keys" }
}
@@ -364,6 +370,7 @@
query symbols_for_closure_captures(
key: (LocalDefId, DefId)
) -> Vec<rustc_span::Symbol> {
+ storage(ArenaCacheSelector<'tcx>)
desc {
|tcx| "symbols for captures of closure `{}` in `{}`",
tcx.def_path_str(key.1),
@@ -380,22 +387,12 @@
}
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
- /// MIR pass (assuming the -Zinstrument-coverage option is enabled).
+ /// MIR pass (assuming the -Cinstrument-coverage option is enabled).
query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
storage(ArenaCacheSelector<'tcx>)
}
- /// Returns the name of the file that contains the function body, if instrumented for coverage.
- query covered_file_name(key: DefId) -> Option<Symbol> {
- desc {
- |tcx| "retrieving the covered file name, if instrumented, for `{}`",
- tcx.def_path_str(key)
- }
- storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { key.is_local() }
- }
-
/// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
/// function was optimized out before codegen, and before being added to the Coverage Map.
query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
@@ -544,7 +541,7 @@
query adt_dtorck_constraint(
key: DefId
- ) -> Result<DtorckConstraint<'tcx>, NoSolution> {
+ ) -> Result<&'tcx DtorckConstraint<'tcx>, NoSolution> {
desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
}
@@ -630,6 +627,32 @@
desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
}
+ /// Maps from associated items on a trait to the corresponding associated
+ /// item on the impl specified by `impl_id`.
+ ///
+ /// For example, with the following code
+ ///
+ /// ```
+ /// struct Type {}
+ /// // DefId
+ /// trait Trait { // trait_id
+ /// fn f(); // trait_f
+ /// fn g() {} // trait_g
+ /// }
+ ///
+ /// impl Trait for Type { // impl_id
+ /// fn f() {} // impl_f
+ /// fn g() {} // impl_g
+ /// }
+ /// ```
+ ///
+ /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
+ ///`{ trait_f: impl_f, trait_g: impl_g }`
+ query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+ }
+
/// Given an `impl_id`, return the trait it implements.
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
@@ -738,6 +761,22 @@
desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
}
+ /// Return the live symbols in the crate for dead code check.
+ ///
+ /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
+ /// their respective impl (i.e., part of the derive macro)
+ query live_symbols_and_ignored_derived_traits(_: ()) -> (
+ FxHashSet<LocalDefId>,
+ FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
+ ) {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "find live symbols in crate" }
+ }
+
+ query check_mod_deathness(key: LocalDefId) -> () {
+ desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) }
+ }
+
query check_mod_impl_wf(key: LocalDefId) -> () {
desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
}
@@ -772,24 +811,11 @@
desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
load_cached(tcx, id) {
- #[cfg(bootstrap)]
- {
- match match tcx.on_disk_cache().as_ref() {
- Some(c) => c.try_load_query_result(*tcx, id),
- None => None,
- } {
- Some(x) => Some(&*tcx.arena.alloc(x)),
- None => None,
- }
- }
- #[cfg(not(bootstrap))]
- {
- let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
- .on_disk_cache().as_ref()
- .and_then(|c| c.try_load_query_result(*tcx, id));
+ let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+ .on_disk_cache().as_ref()
+ .and_then(|c| c.try_load_query_result(*tcx, id));
- typeck_results.map(|x| &*tcx.arena.alloc(x))
- }
+ typeck_results.map(|x| &*tcx.arena.alloc(x))
}
}
@@ -898,10 +924,12 @@
}
/// Destructure a constant ADT or array into its variant index and its
- /// field values.
- query destructure_const(
- key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
- ) -> mir::DestructuredConst<'tcx> {
+ /// field values or return `None` if constant is invalid.
+ ///
+ /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
+ query try_destructure_const(
+ key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
+ ) -> Option<mir::DestructuredConst<'tcx>> {
desc { "destructure constant" }
remap_env_constness
}
@@ -909,8 +937,8 @@
/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_const(
- key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
- ) -> &'tcx ty::Const<'tcx> {
+ key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
+ ) -> ty::Const<'tcx> {
desc { "deref constant" }
remap_env_constness
}
@@ -921,7 +949,7 @@
query lit_to_const(
key: LitToConstInput<'tcx>
- ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+ ) -> Result<ty::Const<'tcx>, LitToConstError> {
desc { "converting literal to const" }
}
@@ -1019,6 +1047,7 @@
/// Gets the rendered value of the specified constant or associated constant.
/// Used by rustdoc.
query rendered_const(def_id: DefId) -> String {
+ storage(ArenaCacheSelector<'tcx>)
desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
@@ -1068,7 +1097,7 @@
query codegen_fulfill_obligation(
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
- ) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
+ ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorReported> {
cache_on_disk_if { true }
desc { |tcx|
"checking if `{}` fulfills its obligations",
@@ -1077,7 +1106,7 @@
}
/// Return all `impl` blocks in the current crate.
- query all_local_trait_impls(_: ()) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> {
+ query all_local_trait_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap<DefId, Vec<LocalDefId>> {
desc { "local trait impls" }
}
@@ -1119,33 +1148,33 @@
desc { "computing whether `{}` is `Copy`", env.value }
remap_env_constness
}
- /// Query backing `TyS::is_sized`.
+ /// Query backing `Ty::is_sized`.
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Sized`", env.value }
remap_env_constness
}
- /// Query backing `TyS::is_freeze`.
+ /// Query backing `Ty::is_freeze`.
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is freeze", env.value }
remap_env_constness
}
- /// Query backing `TyS::is_unpin`.
+ /// Query backing `Ty::is_unpin`.
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Unpin`", env.value }
remap_env_constness
}
- /// Query backing `TyS::needs_drop`.
+ /// Query backing `Ty::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` needs drop", env.value }
remap_env_constness
}
- /// Query backing `TyS::has_significant_drop_raw`.
+ /// Query backing `Ty::has_significant_drop_raw`.
query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` has a significant drop", env.value }
remap_env_constness
}
- /// Query backing `TyS::is_structural_eq_shallow`.
+ /// Query backing `Ty::is_structural_eq_shallow`.
///
/// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
/// correctly.
@@ -1214,6 +1243,7 @@
}
query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
+ storage(ArenaCacheSelector<'tcx>)
desc { "get the linkage format of all dependencies" }
}
@@ -1274,8 +1304,8 @@
desc { "traits in scope at a block" }
}
- query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> {
- desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
+ desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
@@ -1346,13 +1376,15 @@
/// You likely want to call `Instance::upstream_monomorphization()`
/// instead of invoking this query directly.
query upstream_monomorphizations_for(def_id: DefId)
- -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {
- desc { |tcx|
- "collecting available upstream monomorphizations for `{}`",
- tcx.def_path_str(def_id),
- }
- separate_provide_extern
+ -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
+ {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx|
+ "collecting available upstream monomorphizations for `{}`",
+ tcx.def_path_str(def_id),
}
+ separate_provide_extern
+ }
/// Returns the upstream crate that exports drop-glue for the given
/// type (`substs` is expected to be a single-item list containing the
@@ -1373,7 +1405,8 @@
desc { "available upstream drop-glue for `{:?}`", substs }
}
- query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
+ query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
+ storage(ArenaCacheSelector<'tcx>)
desc { "looking up the foreign modules of a linked crate" }
separate_provide_extern
}
@@ -1399,11 +1432,13 @@
separate_provide_extern
}
query extra_filename(_: CrateNum) -> String {
+ storage(ArenaCacheSelector<'tcx>)
eval_always
desc { "looking up the extra filename for a crate" }
separate_provide_extern
}
query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+ storage(ArenaCacheSelector<'tcx>)
eval_always
desc { "looking up the paths for extern crates" }
separate_provide_extern
@@ -1416,13 +1451,6 @@
separate_provide_extern
}
- /// Given a crate, look up all trait impls in that crate.
- /// Return `(impl_id, self_ty)`.
- query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<SimplifiedType>)] {
- desc { "looking up all (?) trait implementations" }
- separate_provide_extern
- }
-
query is_dllimport_foreign_item(def_id: DefId) -> bool {
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
}
@@ -1462,8 +1490,7 @@
/// for each parameter if a trait object were to be passed for that parameter.
/// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`.
/// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
- query object_lifetime_defaults_map(_: LocalDefId)
- -> Option<Vec<ObjectLifetimeDefault>> {
+ query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> {
desc { "looking up lifetime defaults for a region on an item" }
}
query late_bound_vars_map(_: LocalDefId)
@@ -1472,6 +1499,7 @@
}
query lifetime_scope_map(_: LocalDefId) -> Option<FxHashMap<ItemLocalId, LifetimeScopeForPath>> {
+ storage(ArenaCacheSelector<'tcx>)
desc { "finds the lifetime scope for an HirId of a PathSegment" }
}
@@ -1485,7 +1513,7 @@
/// check whether the forest is empty.
query type_uninhabited_from(
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
- ) -> ty::inhabitedness::DefIdForest {
+ ) -> ty::inhabitedness::DefIdForest<'tcx> {
desc { "computing the inhabitedness of `{:?}`", key }
remap_env_constness
}
@@ -1502,8 +1530,8 @@
desc { "fetching what a crate is named" }
separate_provide_extern
}
- query item_children(def_id: DefId) -> &'tcx [Export] {
- desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
+ query module_children(def_id: DefId) -> &'tcx [ModChild] {
+ desc { |tcx| "collecting child items of module `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
@@ -1564,6 +1592,7 @@
separate_provide_extern
}
query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+ storage(ArenaCacheSelector<'tcx>)
eval_always
desc { "looking at the source for a crate" }
separate_provide_extern
@@ -1654,7 +1683,11 @@
desc { "optimization level used by backend" }
}
- query output_filenames(_: ()) -> Arc<OutputFilenames> {
+ /// Return the filenames where output artefacts shall be stored.
+ ///
+ /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
+ /// has been destroyed.
+ query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
eval_always
desc { "output_filenames" }
}
@@ -1896,6 +1929,7 @@
/// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
/// because the `ty::Ty`-based wfcheck is always run.
query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
+ storage(ArenaCacheSelector<'tcx>)
eval_always
no_hash
desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 8d6fd1e..04bc0c8 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -17,6 +17,7 @@
use rustc_index::vec::IndexVec;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{
BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
};
@@ -213,7 +214,7 @@
#[derive(Debug, HashStable)]
pub enum ExprKind<'tcx> {
- /// `Scope`s are used to explicitely mark destruction scopes,
+ /// `Scope`s are used to explicitly mark destruction scopes,
/// and to track the `HirId` of the expressions within the scope.
Scope {
region_scope: region::Scope,
@@ -368,12 +369,12 @@
},
/// An inline `const` block, e.g. `const {}`.
ConstBlock {
- value: &'tcx Const<'tcx>,
+ value: Const<'tcx>,
},
/// An array literal constructed from one repeated element, e.g. `[1; 5]`.
Repeat {
value: ExprId,
- count: &'tcx Const<'tcx>,
+ count: Const<'tcx>,
},
/// An array, e.g. `[a, b, c, d]`.
Array {
@@ -407,7 +408,7 @@
},
/// A literal.
Literal {
- literal: &'tcx Const<'tcx>,
+ literal: Const<'tcx>,
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
/// The `DefId` of the `const` item this literal
/// was produced from, if this is not a user-written
@@ -419,7 +420,8 @@
/// This is only distinguished from `Literal` so that we can register some
/// info for diagnostics.
StaticRef {
- literal: &'tcx Const<'tcx>,
+ alloc_id: AllocId,
+ ty: Ty<'tcx>,
def_id: DefId,
},
/// Inline assembly, i.e. `asm!()`.
@@ -431,12 +433,6 @@
},
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),
- /// Inline LLVM assembly, i.e. `llvm_asm!()`.
- LlvmInlineAsm {
- asm: &'tcx hir::LlvmInlineAsmInner,
- outputs: Box<[ExprId]>,
- inputs: Box<[ExprId]>,
- },
/// A `yield` expression.
Yield {
value: ExprId,
@@ -507,7 +503,7 @@
out_expr: Option<ExprId>,
},
Const {
- value: &'tcx Const<'tcx>,
+ value: Const<'tcx>,
span: Span,
},
SymFn {
@@ -646,7 +642,7 @@
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
/// `PartialEq` and `Eq`.
Constant {
- value: &'tcx ty::Const<'tcx>,
+ value: ty::Const<'tcx>,
},
Range(PatRange<'tcx>),
@@ -676,8 +672,8 @@
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
pub struct PatRange<'tcx> {
- pub lo: &'tcx ty::Const<'tcx>,
- pub hi: &'tcx ty::Const<'tcx>,
+ pub lo: ty::Const<'tcx>,
+ pub hi: ty::Const<'tcx>,
pub end: RangeEnd,
}
@@ -726,7 +722,7 @@
};
if let Some(variant) = variant {
- write!(f, "{}", variant.ident)?;
+ write!(f, "{}", variant.name)?;
// Only for Adt we can have `S {...}`,
// which we handle separately here.
@@ -738,7 +734,7 @@
if let PatKind::Wild = *p.pattern.kind {
continue;
}
- let name = variant.fields[p.field.index()].ident;
+ let name = variant.fields[p.field.index()].name;
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
printed += 1;
}
diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
index f80bead..e3d004e 100644
--- a/compiler/rustc_middle/src/thir/abstract_const.rs
+++ b/compiler/rustc_middle/src/thir/abstract_const.rs
@@ -22,7 +22,7 @@
/// A node of an `AbstractConst`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub enum Node<'tcx> {
- Leaf(&'tcx ty::Const<'tcx>),
+ Leaf(ty::Const<'tcx>),
Binop(mir::BinOp, NodeId, NodeId),
UnaryOp(mir::UnOp, NodeId),
FunctionCall(NodeId, &'tcx [NodeId]),
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 7fc15e0..b3e2cb1 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -26,7 +26,7 @@
walk_pat(self, pat);
}
- fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
+ fn visit_const(&mut self, _cnst: Const<'tcx>) {}
}
pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
@@ -123,7 +123,7 @@
}
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
- StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+ StaticRef { .. } => {}
InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
for op in &**operands {
use InlineAsmOperand::*;
@@ -145,14 +145,6 @@
}
}
ThreadLocalRef(_) => {}
- LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
- for &out_expr in &**outputs {
- visitor.visit_expr(&visitor.thir()[out_expr]);
- }
- for &in_expr in &**inputs {
- visitor.visit_expr(&visitor.thir()[in_expr]);
- }
- }
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
}
}
@@ -217,7 +209,7 @@
visitor.visit_pat(&subpattern.pattern);
}
}
- Constant { value } => visitor.visit_const(value),
+ Constant { value } => visitor.visit_const(*value),
Range(range) => {
visitor.visit_const(range.lo);
visitor.visit_const(range.hi);
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index de5beff..b54418e 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -285,6 +285,12 @@
trait_item_def_id: DefId,
},
+ /// Checking that the bounds of a trait's associated type hold for a given impl
+ CheckAssociatedTypeBounds {
+ impl_item_def_id: DefId,
+ trait_item_def_id: DefId,
+ },
+
/// Checking that this expression can be assigned where it needs to be
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable,
@@ -402,7 +408,7 @@
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(ObligationCauseCode<'_>, 40);
+static_assert_size!(ObligationCauseCode<'_>, 48);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum StatementAsExpression {
@@ -440,11 +446,11 @@
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct DerivedObligationCause<'tcx> {
- /// The trait reference of the parent obligation that led to the
+ /// The trait predicate of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
- /// derived obligations, so we just store the trait reference here
+ /// derived obligations, so we just store the trait predicate here
/// directly.
- pub parent_trait_ref: ty::PolyTraitRef<'tcx>,
+ pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
/// The parent trait had this cause.
pub parent_code: Lrc<ObligationCauseCode<'tcx>>,
@@ -566,7 +572,7 @@
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
/// ImplSource for a `const Drop` implementation.
- ConstDrop(ImplSourceConstDropData),
+ ConstDrop(ImplSourceConstDropData<N>),
}
impl<'tcx, N> ImplSource<'tcx, N> {
@@ -581,10 +587,10 @@
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
- | ImplSource::Pointee(ImplSourcePointeeData)
- | ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(),
+ | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
ImplSource::TraitAlias(d) => d.nested,
ImplSource::TraitUpcasting(d) => d.nested,
+ ImplSource::ConstDrop(i) => i.nested,
}
}
@@ -599,10 +605,10 @@
ImplSource::Object(d) => &d.nested,
ImplSource::FnPointer(d) => &d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
- | ImplSource::Pointee(ImplSourcePointeeData)
- | ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
+ | ImplSource::Pointee(ImplSourcePointeeData) => &[],
ImplSource::TraitAlias(d) => &d.nested,
ImplSource::TraitUpcasting(d) => &d.nested,
+ ImplSource::ConstDrop(i) => &i.nested,
}
}
@@ -661,9 +667,9 @@
nested: d.nested.into_iter().map(f).collect(),
})
}
- ImplSource::ConstDrop(ImplSourceConstDropData) => {
- ImplSource::ConstDrop(ImplSourceConstDropData)
- }
+ ImplSource::ConstDrop(i) => ImplSource::ConstDrop(ImplSourceConstDropData {
+ nested: i.nested.into_iter().map(f).collect(),
+ }),
}
}
}
@@ -755,8 +761,10 @@
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub struct ImplSourcePointeeData;
-#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
-pub struct ImplSourceConstDropData;
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+pub struct ImplSourceConstDropData<N> {
+ pub nested: Vec<N>,
+}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceTraitAliasData<'tcx, N> {
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index cb35a40..07cfe83 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -11,7 +11,6 @@
use crate::ty::{self, Ty, TyCtxt};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_query_system::ich::StableHashingContext;
use rustc_span::source_map::Span;
@@ -97,7 +96,7 @@
pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
-#[derive(Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable)]
pub struct NoSolution;
pub type Fallible<T> = Result<T, NoSolution>;
@@ -191,12 +190,12 @@
pub unsize: bool,
}
-#[derive(Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable)]
pub struct MethodAutoderefStepsResult<'tcx> {
/// The valid autoderef steps that could be find.
- pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
+ pub steps: &'tcx [CandidateStep<'tcx>],
/// If Some(T), a type autoderef reported an error on.
- pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
+ pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>,
/// If `true`, `steps` has been truncated due to reaching the
/// recursion limit.
pub reached_recursion_limit: bool,
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 71ee00c..e18f04d 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -146,8 +146,8 @@
BuiltinUnsizeCandidate,
- /// Implementation of `const Drop`.
- ConstDropCandidate,
+ /// Implementation of `const Drop`, optionally from a custom `impl const Drop`.
+ ConstDropCandidate(Option<DefId>),
}
/// The result of trait evaluation. The order is important
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 3e9cd6b..03a6daa 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -4,7 +4,7 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::ErrorReported;
use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::sym;
/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
@@ -46,6 +46,41 @@
}
}
+/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
+/// purposes.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable, Debug, TyEncodable, TyDecodable)]
+pub enum OverlapMode {
+ /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
+ Stable,
+ /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
+ WithNegative,
+ /// Just check for negative impls, not for "where clause not implemented": used for testing.
+ Strict,
+}
+
+impl OverlapMode {
+ pub fn get<'tcx>(tcx: TyCtxt<'tcx>, trait_id: DefId) -> OverlapMode {
+ let with_negative_coherence = tcx.features().with_negative_coherence;
+ let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence);
+
+ if with_negative_coherence {
+ if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative }
+ } else if strict_coherence {
+ bug!("To use strict_coherence you need to set with_negative_coherence feature flag");
+ } else {
+ OverlapMode::Stable
+ }
+ }
+
+ pub fn use_negative_impl(&self) -> bool {
+ *self == OverlapMode::Strict || *self == OverlapMode::WithNegative
+ }
+
+ pub fn use_implicit_negative(&self) -> bool {
+ *self == OverlapMode::Stable || *self == OverlapMode::WithNegative
+ }
+}
+
/// Children of a given impl, grouped into blanket/non-blanket varieties as is
/// done in `TraitDef`.
#[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)]
@@ -75,34 +110,28 @@
Trait(DefId),
}
-impl<'tcx> Node {
+impl Node {
pub fn is_from_trait(&self) -> bool {
matches!(self, Node::Trait(..))
}
- /// Iterate over the items defined directly by the given (impl or trait) node.
- pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> {
- tcx.associated_items(self.def_id()).in_definition_order()
- }
-
- /// Finds an associated item defined in this node.
+ /// Trys to find the associated item that implements `trait_item_def_id`
+ /// defined in this node.
///
/// If this returns `None`, the item can potentially still be found in
/// parents of this node.
- pub fn item(
+ pub fn item<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
- trait_item_name: Ident,
- trait_item_kind: ty::AssocKind,
- trait_def_id: DefId,
- ) -> Option<ty::AssocItem> {
- tcx.associated_items(self.def_id())
- .filter_by_name_unhygienic(trait_item_name.name)
- .find(move |impl_item| {
- trait_item_kind == impl_item.kind
- && tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
- })
- .copied()
+ trait_item_def_id: DefId,
+ ) -> Option<&'tcx ty::AssocItem> {
+ match *self {
+ Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)),
+ Node::Impl(impl_def_id) => {
+ let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?;
+ Some(tcx.associated_item(*id))
+ }
+ }
}
pub fn def_id(&self) -> DefId {
@@ -181,17 +210,11 @@
impl<'tcx> Ancestors<'tcx> {
/// Finds the bottom-most (ie. most specialized) definition of an associated
/// item.
- pub fn leaf_def(
- mut self,
- tcx: TyCtxt<'tcx>,
- trait_item_name: Ident,
- trait_item_kind: ty::AssocKind,
- ) -> Option<LeafDef> {
- let trait_def_id = self.trait_def_id;
+ pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option<LeafDef> {
let mut finalizing_node = None;
self.find_map(|node| {
- if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) {
+ if let Some(item) = node.item(tcx, trait_item_def_id) {
if finalizing_node.is_none() {
let is_specializable = item.defaultness.is_default()
|| tcx.impl_defaultness(node.def_id()).is_default();
@@ -201,7 +224,7 @@
}
}
- Some(LeafDef { item, defining_node: node, finalizing_node })
+ Some(LeafDef { item: *item, defining_node: node, finalizing_node })
} else {
// Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
finalizing_node = Some(node);
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index aa2f37b..6ce9f5e 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -120,6 +120,12 @@
}
}
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDropData<N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ImplSourceConstDropData(nested={:?})", self.nested)
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// Lift implementations
@@ -127,5 +133,4 @@
super::IfExpressionCause,
super::ImplSourceDiscriminantKindData,
super::ImplSourcePointeeData,
- super::ImplSourceConstDropData,
}
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index e0e3feb..738c48d 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -77,7 +77,7 @@
) => Ok(a),
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
- Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
+ Err(TypeError::Sorts(relate::expected_found(self, a, b)))
}
(&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()),
@@ -88,21 +88,21 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
- match (a.val, b.val) {
+ match (a.val(), b.val()) {
(_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
return Ok(a);
}
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
- return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b)));
+ return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b)));
}
_ => {}
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 5cde54c..40fbea7 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -4,6 +4,7 @@
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
@@ -25,7 +26,7 @@
Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
};
-#[derive(Clone, HashStable, Debug)]
+#[derive(Copy, Clone, HashStable, Debug)]
pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
bitflags! {
@@ -136,12 +137,13 @@
impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
thread_local! {
- static CACHE: RefCell<FxHashMap<usize, Fingerprint>> = Default::default();
+ static CACHE: RefCell<FxHashMap<(usize, HashingControls), Fingerprint>> = Default::default();
}
let hash: Fingerprint = CACHE.with(|cache| {
let addr = self as *const AdtDef as usize;
- *cache.borrow_mut().entry(addr).or_insert_with(|| {
+ let hashing_controls = hcx.hashing_controls();
+ *cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| {
let ty::AdtDef { did, ref variants, ref flags, ref repr } = *self;
let mut hasher = StableHasher::new();
@@ -393,7 +395,7 @@
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::AssocTy, _)
- | Res::SelfTy(..)
+ | Res::SelfTy { .. }
| Res::SelfCtor(..) => self.non_enum_variant(),
_ => bug!("unexpected res {:?} in variant_of_res", res),
}
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index bf5a3e6..49f8465 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -40,22 +40,30 @@
}
}
+/// Information about an associated item
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
pub struct AssocItem {
pub def_id: DefId,
- #[stable_hasher(project(name))]
- pub ident: Ident,
+ pub name: Symbol,
pub kind: AssocKind,
pub vis: Visibility,
pub defaultness: hir::Defaultness,
pub container: AssocItemContainer,
+ /// If this is an item in an impl of a trait then this is the `DefId` of
+ /// the associated item on the trait that this implements.
+ pub trait_item_def_id: Option<DefId>,
+
/// Whether this is a method with an explicit self
/// as its first parameter, allowing method calls.
pub fn_has_self_parameter: bool,
}
impl AssocItem {
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+ }
+
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
match self.kind {
ty::AssocKind::Fn => {
@@ -65,9 +73,9 @@
// regions just fine, showing `fn(&MyType)`.
tcx.fn_sig(self.def_id).skip_binder().to_string()
}
- ty::AssocKind::Type => format!("type {};", self.ident),
+ ty::AssocKind::Type => format!("type {};", self.name),
ty::AssocKind::Const => {
- format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id))
+ format!("const {}: {:?};", self.name, tcx.type_of(self.def_id))
}
}
}
@@ -110,7 +118,7 @@
impl<'tcx> AssocItems<'tcx> {
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self {
- let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect();
+ let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
AssocItems { items }
}
@@ -134,21 +142,6 @@
self.items.get_by_key(name).copied()
}
- /// Returns an iterator over all associated items with the given name.
- ///
- /// Multiple items may have the same name if they are in different `Namespace`s. For example,
- /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*`
- /// methods below if you know which item you are looking for.
- pub fn filter_by_name<'a>(
- &'a self,
- tcx: TyCtxt<'a>,
- ident: Ident,
- parent_def_id: DefId,
- ) -> impl 'a + Iterator<Item = &'a ty::AssocItem> {
- self.filter_by_name_unhygienic(ident.name)
- .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
- }
-
/// Returns the associated item with the given name and `AssocKind`, if one exists.
pub fn find_by_name_and_kind(
&self,
@@ -159,7 +152,19 @@
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.kind == kind)
- .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+ .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
+ }
+
+ /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
+ pub fn find_by_name_and_kinds(
+ &self,
+ tcx: TyCtxt<'_>,
+ ident: Ident,
+ // Sorted in order of what kinds to look at
+ kinds: &[AssocKind],
+ parent_def_id: DefId,
+ ) -> Option<&ty::AssocItem> {
+ kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
}
/// Returns the associated item with the given name in the given `Namespace`, if one exists.
@@ -172,6 +177,6 @@
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.kind.namespace() == ns)
- .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+ .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
}
}
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 771acc2..8ba6c1f 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -52,35 +52,18 @@
/// Information describing the capture of an upvar. This is computed
/// during `typeck`, specifically by `regionck`.
#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub enum UpvarCapture<'tcx> {
+pub enum UpvarCapture {
/// Upvar is captured by value. This is always true when the
/// closure is labeled `move`, but can also be true in other cases
/// depending on inference.
- ///
- /// If the upvar was inferred to be captured by value (e.g. `move`
- /// was not used), then the `Span` points to a usage that
- /// required it. There may be more than one such usage
- /// (e.g. `|| { a; a; }`), in which case we pick an
- /// arbitrary one.
- ByValue(Option<Span>),
+ ByValue,
/// Upvar is captured by reference.
- ByRef(UpvarBorrow<'tcx>),
-}
-
-#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub struct UpvarBorrow<'tcx> {
- /// The kind of borrow: by-ref upvars have access to shared
- /// immutable borrows, which are not part of the normal language
- /// syntax.
- pub kind: BorrowKind,
-
- /// Region of the resulting reference.
- pub region: ty::Region<'tcx>,
+ ByRef(BorrowKind),
}
pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
-pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
+pub type UpvarCaptureMap = FxHashMap<UpvarId, UpvarCapture>;
/// Given the closure DefId this map provides a map of root variables to minimum
/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
@@ -133,7 +116,7 @@
}
/// Returns the representative scalar type for this closure kind.
- /// See `TyS::to_opt_closure_kind` for more details.
+ /// See `Ty::to_opt_closure_kind` for more details.
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self {
ty::ClosureKind::Fn => tcx.types.i8,
@@ -150,10 +133,13 @@
pub place: HirPlace<'tcx>,
/// `CaptureKind` and expression(s) that resulted in such capture of `place`.
- pub info: CaptureInfo<'tcx>,
+ pub info: CaptureInfo,
/// Represents if `place` can be mutated or not.
pub mutability: hir::Mutability,
+
+ /// Region of the resulting reference if the upvar is captured by ref.
+ pub region: Option<ty::Region<'tcx>>,
}
impl<'tcx> CapturedPlace<'tcx> {
@@ -178,7 +164,7 @@
write!(
&mut symbol,
"__{}",
- def.variants[variant].fields[idx as usize].ident.name.as_str(),
+ def.variants[variant].fields[idx as usize].name.as_str(),
)
.unwrap();
}
@@ -287,7 +273,7 @@
/// for a particular capture as well as identifying the part of the source code
/// that triggered this capture to occur.
#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub struct CaptureInfo<'tcx> {
+pub struct CaptureInfo {
/// Expr Id pointing to use that resulted in selecting the current capture kind
///
/// Eg:
@@ -325,7 +311,7 @@
pub path_expr_id: Option<hir::HirId>,
/// Capture mode that was selected
- pub capture_kind: UpvarCapture<'tcx>,
+ pub capture_kind: UpvarCapture,
}
pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
@@ -344,7 +330,7 @@
curr_string = format!(
"{}.{}",
curr_string,
- def.variants[variant].fields[idx as usize].ident.name.as_str()
+ def.variants[variant].fields[idx as usize].name.as_str()
);
}
ty::Tuple(_) => {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index db37d98..ecd30ba 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -13,8 +13,9 @@
interpret::{AllocId, Allocation},
};
use crate::thir;
+use crate::traits;
use crate::ty::subst::SubstsRef;
-use crate::ty::{self, List, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::Span;
@@ -71,7 +72,7 @@
/// `Decodable` can still be implemented in cases where `Decodable` is required
/// by a trait bound.
pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> {
- fn decode(d: &mut D) -> Result<&'tcx Self, D::Error>;
+ fn decode(d: &mut D) -> &'tcx Self;
}
/// Encode the given value or a previously cached shorthand.
@@ -137,6 +138,18 @@
}
}
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Region<'tcx> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ self.kind().encode(e)
+ }
+}
+
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Const<'tcx> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ self.0.0.encode(e)
+ }
+}
+
impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
e.encode_alloc_id(self)
@@ -155,7 +168,7 @@
encodable_via_deref! {
&'tcx ty::TypeckResults<'tcx>,
- ty::Region<'tcx>,
+ &'tcx traits::ImplSource<'tcx, ()>,
&'tcx mir::Body<'tcx>,
&'tcx mir::UnsafetyCheckResult,
&'tcx mir::BorrowCheckResult<'tcx>,
@@ -172,13 +185,9 @@
fn position(&self) -> usize;
- fn cached_ty_for_shorthand<F>(
- &mut self,
- shorthand: usize,
- or_insert_with: F,
- ) -> Result<Ty<'tcx>, Self::Error>
+ fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
where
- F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
+ F: FnOnce(&mut Self) -> Ty<'tcx>;
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
where
@@ -188,35 +197,35 @@
(self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
}
- fn decode_alloc_id(&mut self) -> Result<AllocId, Self::Error>;
+ fn decode_alloc_id(&mut self) -> AllocId;
}
#[inline]
fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
decoder: &mut D,
-) -> Result<&'tcx T, D::Error>
+) -> &'tcx T
where
D: TyDecoder<'tcx>,
{
- Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?))
+ decoder.tcx().arena.alloc(Decodable::decode(decoder))
}
#[inline]
fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
decoder: &mut D,
-) -> Result<&'tcx [T], D::Error>
+) -> &'tcx [T]
where
D: TyDecoder<'tcx>,
{
- Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder)?))
+ decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
}
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> {
+ fn decode(decoder: &mut D) -> Ty<'tcx> {
// Handle shorthands first, if we have a usize > 0x80.
if decoder.positioned_at_shorthand() {
- let pos = decoder.read_usize()?;
+ let pos = decoder.read_usize();
assert!(pos >= SHORTHAND_OFFSET);
let shorthand = pos - SHORTHAND_OFFSET;
@@ -225,87 +234,89 @@
})
} else {
let tcx = decoder.tcx();
- Ok(tcx.mk_ty(ty::TyKind::decode(decoder)?))
+ tcx.mk_ty(ty::TyKind::decode(decoder))
}
}
}
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)?;
+ fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+ let bound_vars = Decodable::decode(decoder);
// Handle shorthands first, if we have a usize > 0x80.
- Ok(ty::Binder::bind_with_vars(
+ ty::Binder::bind_with_vars(
if decoder.positioned_at_shorthand() {
- let pos = decoder.read_usize()?;
+ let pos = decoder.read_usize();
assert!(pos >= SHORTHAND_OFFSET);
let shorthand = pos - SHORTHAND_OFFSET;
- decoder.with_position(shorthand, ty::PredicateKind::decode)?
+ decoder.with_position(shorthand, ty::PredicateKind::decode)
} else {
- ty::PredicateKind::decode(decoder)?
+ ty::PredicateKind::decode(decoder)
},
bound_vars,
- ))
+ )
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
- fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
- let predicate_kind = Decodable::decode(decoder)?;
- let predicate = decoder.tcx().mk_predicate(predicate_kind);
- Ok(predicate)
+ fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
+ let predicate_kind = Decodable::decode(decoder);
+ decoder.tcx().mk_predicate(predicate_kind)
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
- let len = decoder.read_usize()?;
+ fn decode(decoder: &mut D) -> Self {
+ let len = decoder.read_usize();
let tcx = decoder.tcx();
- tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))
+ tcx.mk_substs(
+ (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)),
+ )
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for mir::Place<'tcx> {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
- let local: mir::Local = Decodable::decode(decoder)?;
- let len = decoder.read_usize()?;
- let projection: &'tcx List<mir::PlaceElem<'tcx>> =
- decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
- Ok(mir::Place { local, projection })
+ fn decode(decoder: &mut D) -> Self {
+ let local: mir::Local = Decodable::decode(decoder);
+ let len = decoder.read_usize();
+ let projection = decoder.tcx().mk_place_elems(
+ (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)),
+ );
+ mir::Place { local, projection }
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
- Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?))
+ fn decode(decoder: &mut D) -> Self {
+ decoder.tcx().mk_region(Decodable::decode(decoder))
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
- let len = decoder.read_usize()?;
- let interned: Result<Vec<CanonicalVarInfo<'tcx>>, _> =
+ fn decode(decoder: &mut D) -> Self {
+ let len = decoder.read_usize();
+ let interned: Vec<CanonicalVarInfo<'tcx>> =
(0..len).map(|_| Decodable::decode(decoder)).collect();
- Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice()))
+ decoder.tcx().intern_canonical_var_infos(interned.as_slice())
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AllocId {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+ fn decode(decoder: &mut D) -> Self {
decoder.decode_alloc_id()
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::SymbolName<'tcx> {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
- Ok(ty::SymbolName::new(decoder.tcx(), &decoder.read_str()?))
+ fn decode(decoder: &mut D) -> Self {
+ ty::SymbolName::new(decoder.tcx(), &decoder.read_str())
}
}
macro_rules! impl_decodable_via_ref {
($($t:ty),+) => {
$(impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for $t {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+ fn decode(decoder: &mut D) -> Self {
RefDecodable::decode(decoder)
}
})*
@@ -313,77 +324,73 @@
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- let len = decoder.read_usize()?;
- decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.tcx().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D>
for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
{
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- let len = decoder.read_usize()?;
- decoder.tcx().mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.tcx().mk_poly_existential_predicates(
+ (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)),
+ )
}
}
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Const<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ decoder.tcx().mk_const(Decodable::decode(decoder))
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- Ok(decoder.tcx().arena.alloc_from_iter(
- (0..decoder.read_usize()?)
- .map(|_| Decodable::decode(decoder))
- .collect::<Result<Vec<_>, _>>()?,
- ))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.tcx().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- Ok(decoder.tcx().arena.alloc_from_iter(
- (0..decoder.read_usize()?)
- .map(|_| Decodable::decode(decoder))
- .collect::<Result<Vec<_>, _>>()?,
- ))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.tcx().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- Ok(decoder.tcx().arena.alloc_from_iter(
- (0..decoder.read_usize()?)
- .map(|_| Decodable::decode(decoder))
- .collect::<Result<Vec<_>, _>>()?,
- ))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.tcx().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
- Ok(decoder.tcx().arena.alloc_from_iter(
- (0..decoder.read_usize()?)
- .map(|_| Decodable::decode(decoder))
- .collect::<Result<Vec<_>, _>>()?,
- ))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.tcx().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
}
}
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()?;
- decoder.tcx().mk_bound_variable_kinds((0..len).map(|_| Decodable::decode(decoder)))
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.tcx().mk_bound_variable_kinds(
+ (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
+ )
}
}
@@ -391,6 +398,7 @@
&'tcx ty::TypeckResults<'tcx>,
&'tcx ty::List<Ty<'tcx>>,
&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ &'tcx traits::ImplSource<'tcx, ()>,
&'tcx Allocation,
&'tcx mir::Body<'tcx>,
&'tcx mir::UnsafetyCheckResult,
@@ -405,7 +413,7 @@
($($name:ident -> $ty:ty;)*) => {
$(
#[inline]
- fn $name(&mut self) -> Result<$ty, Self::Error> {
+ fn $name(&mut self) -> $ty {
self.opaque.$name()
}
)*
@@ -418,14 +426,14 @@
[$name:ident: $ty:ty]) => {
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty {
#[inline]
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+ fn decode(decoder: &mut D) -> &'tcx Self {
decode_arena_allocable(decoder)
}
}
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] {
#[inline]
- fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+ fn decode(decoder: &mut D) -> &'tcx Self {
decode_arena_allocable_slice(decoder)
}
}
@@ -456,10 +464,8 @@
use super::$DecoderName;
impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
- type Error = String;
-
$crate::__impl_decoder_methods! {
- read_nil -> ();
+ read_unit -> ();
read_u128 -> u128;
read_u64 -> u64;
@@ -483,13 +489,9 @@
}
#[inline]
- fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
+ fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) {
self.opaque.read_raw_bytes_into(bytes)
}
-
- fn error(&mut self, err: &str) -> Self::Error {
- self.opaque.error(err)
- }
}
}
}
@@ -505,9 +507,9 @@
}
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, $t> {
- fn decode(decoder: &mut D) -> Result<Self, D::Error> {
- let bound_vars = Decodable::decode(decoder)?;
- Ok(ty::Binder::bind_with_vars(Decodable::decode(decoder)?, bound_vars))
+ fn decode(decoder: &mut D) -> Self {
+ let bound_vars = Decodable::decode(decoder);
+ ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
}
}
)*
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 27e22cc..a794a8c 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -4,10 +4,12 @@
self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
TyCtxt, TypeFoldable,
};
+use rustc_data_structures::intern::Interned;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::HashStable;
+use std::fmt;
mod int;
mod kind;
@@ -17,34 +19,53 @@
pub use kind::*;
pub use valtree::*;
-/// Typed constant value.
-#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
-#[derive(HashStable)]
-pub struct Const<'tcx> {
- pub ty: Ty<'tcx>,
+/// Use this rather than `ConstS`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Const<'tcx>(pub Interned<'tcx, ConstS<'tcx>>);
+impl<'tcx> fmt::Debug for Const<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This reflects what `Const` looked liked before `Interned` was
+ // introduced. We print it like this to avoid having to update expected
+ // output in a lot of tests.
+ write!(f, "Const {{ ty: {:?}, val: {:?} }}", self.ty(), self.val())
+ }
+}
+
+/// Typed constant value.
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
+pub struct ConstS<'tcx> {
+ pub ty: Ty<'tcx>,
pub val: ConstKind<'tcx>,
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Const<'_>, 48);
+static_assert_size!(ConstS<'_>, 48);
impl<'tcx> Const<'tcx> {
+ pub fn ty(self) -> Ty<'tcx> {
+ self.0.ty
+ }
+
+ pub fn val(self) -> ConstKind<'tcx> {
+ self.0.val
+ }
+
/// Literals and const generic parameters are eagerly converted to a constant, everything else
/// becomes `Unevaluated`.
- pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+ pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
}
+ #[instrument(skip(tcx), level = "debug")]
pub fn from_opt_const_arg_anon_const(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
- ) -> &'tcx Self {
+ ) -> Self {
debug!("Const::from_anon_const(def={:?})", def);
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-
- let body_id = match tcx.hir().get(hir_id) {
+ let body_id = match tcx.hir().get_by_def_id(def.did) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
tcx.def_span(def.did.to_def_id()),
@@ -53,15 +74,16 @@
};
let expr = &tcx.hir().body(body_id).value;
+ debug!(?expr);
let ty = tcx.type_of(def.def_id_for_type_of());
match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
- None => tcx.mk_const(ty::Const {
+ None => tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(),
- substs_: None,
+ substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None,
}),
ty,
@@ -69,11 +91,21 @@
}
}
+ #[instrument(skip(tcx), level = "debug")]
fn try_eval_lit_or_param(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
- ) -> Option<&'tcx Self> {
+ ) -> Option<Self> {
+ // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+ // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+ let expr = match &expr.kind {
+ hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+ block.expr.as_ref().unwrap()
+ }
+ _ => expr,
+ };
+
let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
@@ -88,22 +120,17 @@
if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
- if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
- return Some(c);
- } else {
- tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
+ match tcx.at(expr.span).lit_to_const(lit_input) {
+ Ok(c) => return Some(c),
+ Err(e) => {
+ tcx.sess.delay_span_bug(
+ expr.span,
+ &format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+ );
+ }
}
}
- // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
- // currently have to be wrapped in curly brackets, so it's necessary to special-case.
- let expr = match &expr.kind {
- hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
- block.expr.as_ref().unwrap()
- }
- _ => expr,
- };
-
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
@@ -115,7 +142,7 @@
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
- Some(tcx.mk_const(ty::Const {
+ Some(tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
ty,
}))
@@ -124,7 +151,7 @@
}
}
- pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
debug!("Const::from_inline_const(def_id={:?})", def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
@@ -150,35 +177,35 @@
let substs =
InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
.substs;
- tcx.mk_const(ty::Const {
+ tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: ty::WithOptConstParam::unknown(def_id).to_global(),
- substs_: Some(substs),
+ substs,
promoted: None,
}),
ty,
})
}
};
- debug_assert!(!ret.has_free_regions(tcx));
+ debug_assert!(!ret.has_free_regions());
ret
}
/// Interns the given value as a constant.
#[inline]
- pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
- tcx.mk_const(Self { val: ConstKind::Value(val), ty })
+ pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
+ tcx.mk_const(ConstS { val: ConstKind::Value(val), ty })
}
#[inline]
/// Interns the given scalar as a constant.
- pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self {
+ pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> Self {
Self::from_value(tcx, ConstValue::Scalar(val), ty)
}
#[inline]
/// Creates a constant with the given integer value and interns it.
- pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self {
+ pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
let size = tcx
.layout_of(ty)
.unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
@@ -188,19 +215,19 @@
#[inline]
/// Creates an interned zst constant.
- pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+ pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
Self::from_scalar(tcx, Scalar::ZST, ty)
}
#[inline]
/// Creates an interned bool constant.
- pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self {
+ pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
}
#[inline]
/// Creates an interned usize constant.
- pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self {
+ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
}
@@ -209,35 +236,35 @@
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
/// contains const generic parameters or pointers).
pub fn try_eval_bits(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Option<u128> {
- assert_eq!(self.ty, ty);
+ assert_eq!(self.ty(), ty);
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env
- self.val.eval(tcx, param_env).try_to_bits(size)
+ self.val().eval(tcx, param_env).try_to_bits(size)
}
#[inline]
- pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
- self.val.eval(tcx, param_env).try_to_bool()
+ pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+ self.val().eval(tcx, param_env).try_to_bool()
}
#[inline]
- pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
- self.val.eval(tcx, param_env).try_to_machine_usize(tcx)
+ pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
+ self.val().eval(tcx, param_env).try_to_machine_usize(tcx)
}
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
/// unevaluated constant.
- pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
- if let Some(val) = self.val.try_eval(tcx, param_env) {
+ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
+ if let Some(val) = self.val().try_eval(tcx, param_env) {
match val {
- Ok(val) => Const::from_value(tcx, val, self.ty),
- Err(ErrorReported) => tcx.const_error(self.ty),
+ Ok(val) => Const::from_value(tcx, val, self.ty()),
+ Err(ErrorReported) => tcx.const_error(self.ty()),
}
} else {
self
@@ -246,22 +273,21 @@
#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
- pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
+ pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env, ty)
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
}
#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
- pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
+ pub fn eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
self.try_eval_usize(tcx, param_env)
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
}
-pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Const<'tcx> {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let default_def_id = match tcx.hir().get(hir_id) {
+pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
+ let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { ty: _, default: Some(ac) },
..
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 1f4ebd0..ca1db2f 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -147,8 +147,8 @@
}
impl<D: Decoder> Decodable<D> for ScalarInt {
- fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
- Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
+ fn decode(d: &mut D) -> ScalarInt {
+ ScalarInt { data: d.read_u128(), size: d.read_u8() }
}
}
@@ -294,12 +294,22 @@
}
}
+/// Error returned when a conversion from ScalarInt to char fails.
+#[derive(Debug)]
+pub struct CharTryFromScalarInt;
+
impl TryFrom<ScalarInt> for char {
- type Error = Size;
+ type Error = CharTryFromScalarInt;
+
#[inline]
- fn try_from(int: ScalarInt) -> Result<Self, Size> {
- int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
- .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
+ fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
+ let Ok(bits) = int.to_bits(Size::from_bytes(std::mem::size_of::<char>())) else {
+ return Err(CharTryFromScalarInt);
+ };
+ match char::from_u32(bits.try_into().unwrap()) {
+ Some(c) => Ok(c),
+ None => Err(CharTryFromScalarInt),
+ }
}
}
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 7188eed..af7c2c5 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,5 +1,4 @@
use std::convert::TryInto;
-use std::fmt;
use crate::mir::interpret::{AllocId, ConstValue, Scalar};
use crate::mir::Promoted;
@@ -13,17 +12,11 @@
use super::ScalarInt;
/// An unevaluated, potentially generic, constant.
-///
-/// 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, P = Option<Promoted>> {
pub def: ty::WithOptConstParam<DefId>,
- pub substs_: Option<SubstsRef<'tcx>>,
+ pub substs: SubstsRef<'tcx>,
pub promoted: P,
}
@@ -31,34 +24,21 @@
#[inline]
pub fn shrink(self) -> Unevaluated<'tcx, ()> {
debug_assert_eq!(self.promoted, None);
- Unevaluated { def: self.def, substs_: self.substs_, promoted: () }
+ 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 }
+ 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)
- })
+ Unevaluated { def, substs, promoted: Default::default() }
}
}
@@ -173,7 +153,7 @@
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)),
+ substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did),
promoted: unevaluated.promoted,
})
} else {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index dd571e2..41145d2 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -5,10 +5,12 @@
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
-use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
+use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
-use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::mir::{
+ Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
+};
use crate::thir::Thir;
use crate::traits;
use crate::ty::query::{self, TyCtxtAt};
@@ -16,14 +18,15 @@
use crate::ty::TyKind::*;
use crate::ty::{
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
- ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar,
- FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
- ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind,
- ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
+ ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
+ FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
+ ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
+ RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
};
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
@@ -89,7 +92,7 @@
#[derive(TyEncodable, TyDecodable, HashStable)]
pub struct DelaySpanBugEmitted(());
-type InternedSet<'tcx, T> = ShardedHashMap<Interned<'tcx, T>, ()>;
+type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
pub struct CtxtInterners<'tcx> {
/// The arena that types, regions, etc. are allocated from.
@@ -104,15 +107,21 @@
region: InternedSet<'tcx, RegionKind>,
poly_existential_predicates:
InternedSet<'tcx, List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>>,
- predicate: InternedSet<'tcx, PredicateInner<'tcx>>,
+ predicate: InternedSet<'tcx, PredicateS<'tcx>>,
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
- const_: InternedSet<'tcx, Const<'tcx>>,
+ const_: InternedSet<'tcx, ConstS<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
layout: InternedSet<'tcx, Layout>,
adt_def: InternedSet<'tcx, AdtDef>,
+
+ /// `#[stable]` and `#[unstable]` attributes
+ stability: InternedSet<'tcx, attr::Stability>,
+
+ /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
+ const_stability: InternedSet<'tcx, attr::ConstStability>,
}
impl<'tcx> CtxtInterners<'tcx> {
@@ -134,6 +143,8 @@
bound_variable_kinds: Default::default(),
layout: Default::default(),
adt_def: Default::default(),
+ stability: Default::default(),
+ const_stability: Default::default(),
}
}
@@ -141,39 +152,40 @@
#[allow(rustc::usage_of_ty_tykind)]
#[inline(never)]
fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> {
- self.type_
- .intern(kind, |kind| {
- let flags = super::flags::FlagComputation::for_kind(&kind);
+ Ty(Interned::new_unchecked(
+ self.type_
+ .intern(kind, |kind| {
+ let flags = super::flags::FlagComputation::for_kind(&kind);
- let ty_struct = TyS {
- kind,
- flags: flags.flags,
- outer_exclusive_binder: flags.outer_exclusive_binder,
- };
+ let ty_struct = TyS {
+ kind,
+ flags: flags.flags,
+ outer_exclusive_binder: flags.outer_exclusive_binder,
+ };
- Interned(self.arena.alloc(ty_struct))
- })
- .0
+ InternedInSet(self.arena.alloc(ty_struct))
+ })
+ .0,
+ ))
}
#[inline(never)]
- fn intern_predicate(
- &self,
- kind: Binder<'tcx, PredicateKind<'tcx>>,
- ) -> &'tcx PredicateInner<'tcx> {
- self.predicate
- .intern(kind, |kind| {
- let flags = super::flags::FlagComputation::for_predicate(kind);
+ fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
+ Predicate(Interned::new_unchecked(
+ self.predicate
+ .intern(kind, |kind| {
+ let flags = super::flags::FlagComputation::for_predicate(kind);
- let predicate_struct = PredicateInner {
- kind,
- flags: flags.flags,
- outer_exclusive_binder: flags.outer_exclusive_binder,
- };
+ let predicate_struct = PredicateS {
+ kind,
+ flags: flags.flags,
+ outer_exclusive_binder: flags.outer_exclusive_binder,
+ };
- Interned(self.arena.alloc(predicate_struct))
- })
- .0
+ InternedInSet(self.arena.alloc(predicate_struct))
+ })
+ .0,
+ ))
}
}
@@ -212,12 +224,12 @@
/// `ReStatic`
pub re_static: Region<'tcx>,
- /// Erased region, used after type-checking
+ /// Erased region, used outside of type inference.
pub re_erased: Region<'tcx>,
}
pub struct CommonConsts<'tcx> {
- pub unit: &'tcx Const<'tcx>,
+ pub unit: Const<'tcx>,
}
pub struct LocalTableInContext<'a, V> {
@@ -352,7 +364,7 @@
field_indices: ItemLocalMap<usize>,
/// Stores the types for various nodes in the AST. Note that this table
- /// is not guaranteed to be populated until after typeck. See
+ /// is not guaranteed to be populated outside inference. See
/// typeck::check::fn_ctxt for details.
node_types: ItemLocalMap<Ty<'tcx>>,
@@ -848,16 +860,16 @@
_ => false,
},
- GenericArgKind::Lifetime(r) => match r {
+ GenericArgKind::Lifetime(r) => match *r {
ty::ReLateBound(debruijn, br) => {
// We only allow a `ty::INNERMOST` index in substitutions.
- assert_eq!(*debruijn, ty::INNERMOST);
+ assert_eq!(debruijn, ty::INNERMOST);
cvar == br.var
}
_ => false,
},
- GenericArgKind::Const(ct) => match ct.val {
+ GenericArgKind::Const(ct) => match ct.val() {
ty::ConstKind::Bound(debruijn, b) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(debruijn, ty::INNERMOST);
@@ -918,22 +930,30 @@
impl<'tcx> CommonLifetimes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> {
- let mk = |r| interners.region.intern(r, |r| Interned(interners.arena.alloc(r))).0;
+ let mk = |r| {
+ Region(Interned::new_unchecked(
+ interners.region.intern(r, |r| InternedInSet(interners.arena.alloc(r))).0,
+ ))
+ };
CommonLifetimes {
- re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)),
- re_static: mk(RegionKind::ReStatic),
- re_erased: mk(RegionKind::ReErased),
+ re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)),
+ re_static: mk(ty::ReStatic),
+ re_erased: mk(ty::ReErased),
}
}
}
impl<'tcx> CommonConsts<'tcx> {
fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> {
- let mk_const = |c| interners.const_.intern(c, |c| Interned(interners.arena.alloc(c))).0;
+ let mk_const = |c| {
+ Const(Interned::new_unchecked(
+ interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0,
+ ))
+ };
CommonConsts {
- unit: mk_const(ty::Const {
+ unit: mk_const(ty::ConstS {
val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)),
ty: types.unit,
}),
@@ -961,6 +981,7 @@
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html
#[derive(Copy, Clone)]
#[rustc_diagnostic_item = "TyCtxt"]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
pub struct TyCtxt<'tcx> {
gcx: &'tcx GlobalCtxt<'tcx>,
}
@@ -1034,12 +1055,6 @@
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
- /// `#[stable]` and `#[unstable]` attributes
- stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
-
- /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
- const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
-
/// Stores memory for globals (statics/consts).
pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
@@ -1058,6 +1073,17 @@
}
}
+ pub fn mir_borrowck_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<LocalDefId>,
+ ) -> &'tcx BorrowCheckResult<'tcx> {
+ if let Some(param_did) = def.const_param_did {
+ self.mir_borrowck_const_arg((def.did, param_did))
+ } else {
+ self.mir_borrowck(def.did)
+ }
+ }
+
pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
self.arena.alloc(Steal::new(thir))
}
@@ -1091,16 +1117,6 @@
self.create_memory_alloc(alloc)
}
- // FIXME(eddyb) move to `direct_interners!`.
- pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
- self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
- }
-
- // FIXME(eddyb) move to `direct_interners!`.
- pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
- self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
- }
-
/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
@@ -1184,8 +1200,6 @@
evaluation_cache: Default::default(),
crate_name: Symbol::intern(crate_name),
data_layout,
- stability_interner: Default::default(),
- const_stability_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
output_filenames: Arc::new(output_filenames),
}
@@ -1209,12 +1223,26 @@
self.mk_ty(Error(DelaySpanBugEmitted(())))
}
- /// Like `err` but for constants.
+ /// Like [TyCtxt::ty_error] but for constants.
#[track_caller]
- pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
- self.sess
- .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported.");
- self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
+ pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> {
+ self.const_error_with_message(
+ ty,
+ DUMMY_SP,
+ "ty::ConstKind::Error constructed but no error reported",
+ )
+ }
+
+ /// Like [TyCtxt::ty_error_with_message] but for constants.
+ #[track_caller]
+ pub fn const_error_with_message<S: Into<MultiSpan>>(
+ self,
+ ty: Ty<'tcx>,
+ span: S,
+ msg: &str,
+ ) -> Const<'tcx> {
+ self.sess.delay_span_bug(span, msg);
+ self.mk_const(ty::ConstS { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
}
pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
@@ -1307,7 +1335,7 @@
/// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
/// session, if it still exists. This is used during incremental compilation to
/// turn a deserialized `DefPathHash` into its current `DefId`.
- pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId {
+ pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() -> !) -> DefId {
debug!("def_path_hash_to_def_id({:?})", hash);
let stable_crate_id = hash.stable_crate_id();
@@ -1315,7 +1343,10 @@
// If this is a DefPathHash from the local crate, we can look up the
// DefId in the tcx's `Definitions`.
if stable_crate_id == self.sess.local_stable_crate_id() {
- self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id()
+ self.untracked_resolutions
+ .definitions
+ .local_def_path_hash_to_def_id(hash, err)
+ .to_def_id()
} else {
// If this is a DefPathHash from an upstream crate, let the CrateStore map
// it to a DefId.
@@ -1461,8 +1492,7 @@
_ => return None, // not a free region
};
- let hir_id = self.hir().local_def_id_to_hir_id(suitable_region_binding_scope);
- let is_impl_item = match self.hir().find(hir_id) {
+ let is_impl_item = match self.hir().find_by_def_id(suitable_region_binding_scope) {
Some(Node::Item(..) | Node::TraitItem(..)) => false,
Some(Node::ImplItem(..)) => {
self.is_bound_region_in_impl_item(suitable_region_binding_scope)
@@ -1495,8 +1525,7 @@
pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
// `type_of()` will fail on these (#55796, #86483), so only allow `fn`s or closures.
- let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
- match self.hir().get(hir_id) {
+ match self.hir().get_by_def_id(scope_def_id) {
Node::Item(&hir::Item { kind: ItemKind::Fn(..), .. }) => {}
Node::TraitItem(&hir::TraitItem { kind: TraitItemKind::Fn(..), .. }) => {}
Node::ImplItem(&hir::ImplItem { kind: ImplItemKind::Fn(..), .. }) => {}
@@ -1510,6 +1539,7 @@
let sig = ret_ty.fn_sig(self);
let output = self.erase_late_bound_regions(sig.output());
if output.is_impl_trait() {
+ let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
Some((output, fn_decl.output.span()))
} else {
@@ -1607,12 +1637,28 @@
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>;
}
+// Deprecated: we are in the process of converting all uses to `nop_lift`.
+macro_rules! nop_lift_old {
+ ($set:ident; $ty:ty => $lifted:ty) => {
+ impl<'a, 'tcx> Lift<'tcx> for $ty {
+ type Lifted = $lifted;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
+ Some(unsafe { mem::transmute(self) })
+ } else {
+ None
+ }
+ }
+ }
+ };
+}
+
macro_rules! nop_lift {
($set:ident; $ty:ty => $lifted:ty) => {
impl<'a, 'tcx> Lift<'tcx> for $ty {
type Lifted = $lifted;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- if tcx.interners.$set.contains_pointer_to(&Interned(self)) {
+ if tcx.interners.$set.contains_pointer_to(&InternedInSet(self.0.0)) {
Some(unsafe { mem::transmute(self) })
} else {
None
@@ -1630,7 +1676,7 @@
if self.is_empty() {
return Some(List::empty());
}
- if tcx.interners.$set.contains_pointer_to(&Interned(self)) {
+ if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
Some(unsafe { mem::transmute(self) })
} else {
None
@@ -1642,9 +1688,9 @@
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
-nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation}
-nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
+nop_lift! {const_; Const<'a> => Const<'tcx>}
+nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>}
@@ -1661,7 +1707,7 @@
pub mod tls {
use super::{ptr_eq, GlobalCtxt, TyCtxt};
- use crate::dep_graph::{DepKind, TaskDeps};
+ use crate::dep_graph::TaskDepsRef;
use crate::ty::query;
use rustc_data_structures::sync::{self, Lock};
use rustc_data_structures::thin_vec::ThinVec;
@@ -1686,7 +1732,7 @@
/// The current query job, if any. This is updated by `JobOwner::start` in
/// `ty::query::plumbing` when executing a query.
- pub query: Option<query::QueryJobId<DepKind>>,
+ pub query: Option<query::QueryJobId>,
/// Where to store diagnostics for the current query job, if any.
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
@@ -1697,13 +1743,19 @@
/// The current dep graph task. This is used to add dependencies to queries
/// when executing them.
- pub task_deps: Option<&'a Lock<TaskDeps>>,
+ pub task_deps: TaskDepsRef<'a>,
}
impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
let tcx = TyCtxt { gcx };
- ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None }
+ ImplicitCtxt {
+ tcx,
+ query: None,
+ diagnostics: None,
+ layout_depth: 0,
+ task_deps: TaskDepsRef::Ignore,
+ }
}
}
@@ -1831,7 +1883,7 @@
#[allow(non_snake_case)]
mod inner {
use crate::ty::{self, TyCtxt};
- use crate::ty::context::Interned;
+ use crate::ty::context::InternedInSet;
#[derive(Copy, Clone)]
struct DebugStat {
@@ -1854,16 +1906,16 @@
let shards = tcx.interners.type_.lock_shards();
let types = shards.iter().flat_map(|shard| shard.keys());
- for &Interned(t) in types {
- let variant = match t.kind() {
+ for &InternedInSet(t) in types {
+ let variant = match t.kind {
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
ty::Float(..) | ty::Str | ty::Never => continue,
ty::Error(_) => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)*
};
- let lt = t.flags().intersects(ty::TypeFlags::HAS_RE_INFER);
- let ty = t.flags().intersects(ty::TypeFlags::HAS_TY_INFER);
- let ct = t.flags().intersects(ty::TypeFlags::HAS_CT_INFER);
+ let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
+ let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
+ let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
variant.total += 1;
total.total += 1;
@@ -1929,11 +1981,11 @@
writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?;
writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
- writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?;
+ writeln!(fmt, "Stability interner: #{}", self.0.interners.stability.len())?;
writeln!(
fmt,
"Const Stability interner: #{}",
- self.0.const_stability_interner.len()
+ self.0.interners.const_stability.len()
)?;
writeln!(
fmt,
@@ -1950,122 +2002,180 @@
}
}
-/// An entry in an interner.
-struct Interned<'tcx, T: ?Sized>(&'tcx T);
+// This type holds a `T` in the interner. The `T` is stored in the arena and
+// this type just holds a pointer to it, but it still effectively owns it. It
+// impls `Borrow` so that it can be looked up using the original
+// (non-arena-memory-owning) types.
+struct InternedInSet<'tcx, T: ?Sized>(&'tcx T);
-impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
+impl<'tcx, T: 'tcx + ?Sized> Clone for InternedInSet<'tcx, T> {
fn clone(&self) -> Self {
- Interned(self.0)
+ InternedInSet(self.0)
}
}
-impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {}
-impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
+impl<'tcx, T: 'tcx + ?Sized> Copy for InternedInSet<'tcx, T> {}
+
+impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> {
fn into_pointer(&self) -> *const () {
self.0 as *const _ as *const ()
}
}
-// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`.
-impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
- fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
- self.0.kind() == other.0.kind()
- }
-}
-
-impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
-
-impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
- fn hash<H: Hasher>(&self, s: &mut H) {
- self.0.kind().hash(s)
- }
-}
#[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
+impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, TyS<'tcx>> {
fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
- &self.0.kind()
+ &self.0.kind
}
}
-// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
-impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
- fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+
+impl<'tcx> PartialEq for InternedInSet<'tcx, TyS<'tcx>> {
+ fn eq(&self, other: &InternedInSet<'tcx, TyS<'tcx>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
self.0.kind == other.0.kind
}
}
-impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
+impl<'tcx> Eq for InternedInSet<'tcx, TyS<'tcx>> {}
-impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
+impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> {
fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0.kind.hash(s)
}
}
-impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for InternedInSet<'tcx, PredicateS<'tcx>> {
fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
&self.0.kind
}
}
-// N.B., an `Interned<List<T>>` compares and hashes as its elements.
-impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
- fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool {
- self.0[..] == other.0[..]
+impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> {
+ fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
+ self.0.kind == other.0.kind
}
}
-impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {}
+impl<'tcx> Eq for InternedInSet<'tcx, PredicateS<'tcx>> {}
-impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> {
+impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> {
fn hash<H: Hasher>(&self, s: &mut H) {
- self.0[..].hash(s)
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
+ self.0.kind.hash(s)
}
}
-impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
+impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, List<T>> {
fn borrow<'a>(&'a self) -> &'a [T] {
&self.0[..]
}
}
+impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, List<T>> {
+ fn eq(&self, other: &InternedInSet<'tcx, List<T>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
+ self.0[..] == other.0[..]
+ }
+}
+
+impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, List<T>> {}
+
+impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
+ self.0[..].hash(s)
+ }
+}
+
macro_rules! direct_interners {
- ($($name:ident: $method:ident($ty:ty),)+) => {
- $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
- fn eq(&self, other: &Self) -> bool {
- self.0 == other.0
- }
- }
-
- impl<'tcx> Eq for Interned<'tcx, $ty> {}
-
- impl<'tcx> Hash for Interned<'tcx, $ty> {
- fn hash<H: Hasher>(&self, s: &mut H) {
- self.0.hash(s)
- }
- }
-
- impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+ ($($name:ident: $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
+ $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
fn borrow<'a>(&'a self) -> &'a $ty {
&self.0
}
}
+ impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
+ fn eq(&self, other: &Self) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+ // equals `x == y`.
+ self.0 == other.0
+ }
+ }
+
+ impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
+
+ impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) ==
+ // x.hash(s)`.
+ self.0.hash(s)
+ }
+ }
+
impl<'tcx> TyCtxt<'tcx> {
- pub fn $method(self, v: $ty) -> &'tcx $ty {
- self.interners.$name.intern(v, |v| {
- Interned(self.interners.arena.alloc(v))
- }).0
+ pub fn $method(self, v: $ty) -> $ret_ty {
+ $ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| {
+ InternedInSet(self.interners.arena.alloc(v))
+ }).0))
}
})+
}
}
direct_interners! {
- region: mk_region(RegionKind),
- const_: mk_const(Const<'tcx>),
+ region: mk_region(RegionKind): Region -> Region<'tcx>,
+ const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+}
+
+macro_rules! direct_interners_old {
+ ($($name:ident: $method:ident($ty:ty),)+) => {
+ $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
+ fn borrow<'a>(&'a self) -> &'a $ty {
+ &self.0
+ }
+ }
+
+ impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
+ fn eq(&self, other: &Self) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+ // equals `x == y`.
+ self.0 == other.0
+ }
+ }
+
+ impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
+
+ impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) ==
+ // x.hash(s)`.
+ self.0.hash(s)
+ }
+ }
+
+ impl<'tcx> TyCtxt<'tcx> {
+ pub fn $method(self, v: $ty) -> &'tcx $ty {
+ self.interners.$name.intern(v, |v| {
+ InternedInSet(self.interners.arena.alloc(v))
+ }).0
+ }
+ })+
+ }
+}
+
+// FIXME: eventually these should all be converted to `direct_interners`.
+direct_interners_old! {
const_allocation: intern_const_alloc(Allocation),
layout: intern_layout(Layout),
adt_def: intern_adt_def(AdtDef),
+ stability: intern_stability(attr::Stability),
+ const_stability: intern_const_stability(attr::ConstStability),
}
macro_rules! slice_interners {
@@ -2073,7 +2183,7 @@
impl<'tcx> TyCtxt<'tcx> {
$(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
self.interners.$field.intern_ref(v, || {
- Interned(List::from_arena(&*self.arena, v))
+ InternedInSet(List::from_arena(&*self.arena, v))
}).0
})+
}
@@ -2173,8 +2283,7 @@
#[inline]
pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
- let inner = self.interners.intern_predicate(binder);
- Predicate { inner }
+ self.interners.intern_predicate(binder)
}
#[inline]
@@ -2385,8 +2494,8 @@
}
#[inline]
- pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
- self.mk_const(ty::Const { val: ty::ConstKind::Infer(InferConst::Var(v)), ty })
+ pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+ self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(InferConst::Var(v)), ty })
}
#[inline]
@@ -2405,8 +2514,8 @@
}
#[inline]
- pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
- self.mk_const(ty::Const { val: ty::ConstKind::Infer(ic), ty })
+ pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+ self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(ic), ty })
}
#[inline]
@@ -2415,8 +2524,8 @@
}
#[inline]
- pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
- self.mk_const(ty::Const { val: ty::ConstKind::Param(ParamConst { index, name }), ty })
+ pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> Const<'tcx> {
+ self.mk_const(ty::ConstS { val: ty::ConstKind::Param(ParamConst { index, name }), ty })
}
pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
@@ -2452,7 +2561,7 @@
) -> Place<'tcx> {
self.mk_place_elem(
place,
- PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index),
+ PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index),
)
}
@@ -2677,10 +2786,6 @@
.map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id))
}
- pub fn object_lifetime_defaults(self, id: HirId) -> Option<Vec<ObjectLifetimeDefault>> {
- self.object_lifetime_defaults_map(id.owner)
- }
-
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
self.mk_bound_variable_kinds(
self.late_bound_vars_map(id.owner)
@@ -2692,8 +2797,8 @@
)
}
- pub fn lifetime_scope(self, id: HirId) -> Option<LifetimeScopeForPath> {
- self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id))
+ pub fn lifetime_scope(self, id: HirId) -> Option<&'tcx LifetimeScopeForPath> {
+ self.lifetime_scope_map(id.owner).as_ref().and_then(|map| map.get(&id.local_id))
}
/// Whether the `def_id` counts as const fn in the current crate, considering all active
@@ -2763,8 +2868,33 @@
impl<T, R> InternIteratorElement<T, R> for T {
type Output = R;
- fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
- f(&iter.collect::<SmallVec<[_; 8]>>())
+ fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+ mut iter: I,
+ f: F,
+ ) -> Self::Output {
+ // This code is hot enough that it's worth specializing for the most
+ // common length lists, to avoid the overhead of `SmallVec` creation.
+ // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+ // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+ // `assert`.
+ match iter.size_hint() {
+ (0, Some(0)) => {
+ assert!(iter.next().is_none());
+ f(&[])
+ }
+ (1, Some(1)) => {
+ let t0 = iter.next().unwrap();
+ assert!(iter.next().is_none());
+ f(&[t0])
+ }
+ (2, Some(2)) => {
+ let t0 = iter.next().unwrap();
+ let t1 = iter.next().unwrap();
+ assert!(iter.next().is_none());
+ f(&[t0, t1])
+ }
+ _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
+ }
}
}
@@ -2774,6 +2904,7 @@
{
type Output = R;
fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+ // This code isn't hot.
f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
}
}
@@ -2786,10 +2917,15 @@
) -> Self::Output {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
- // The match arms are in order of frequency. The 1, 2, and 0 cases are
- // typically hit in ~95% of cases. We assume that if the upper and
- // lower bounds from `size_hint` agree they are correct.
+ // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+ // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+ // `assert`, unless a failure happens first, in which case the result
+ // will be an error anyway.
Ok(match iter.size_hint() {
+ (0, Some(0)) => {
+ assert!(iter.next().is_none());
+ f(&[])
+ }
(1, Some(1)) => {
let t0 = iter.next().unwrap()?;
assert!(iter.next().is_none());
@@ -2801,10 +2937,6 @@
assert!(iter.next().is_none());
f(&[t0, t1])
}
- (0, Some(0)) => {
- assert!(iter.next().is_none());
- f(&[])
- }
_ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
})
}
@@ -2817,10 +2949,9 @@
}
pub fn provide(providers: &mut ty::query::Providers) {
- providers.in_scope_traits_map =
- |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map);
providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
- providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]);
+ providers.module_reexports =
+ |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
providers.crate_name = |tcx, id| {
assert_eq!(id, LOCAL_CRATE);
tcx.crate_name
@@ -2840,7 +2971,7 @@
|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();
+ providers.output_filenames = |tcx, ()| &tcx.output_filenames;
providers.features_query = |tcx, ()| tcx.sess.features_untracked();
providers.is_panic_runtime = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index ee00f6c..64b2edd 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,10 +1,10 @@
-//! Diagnostics related methods for `TyS`.
+//! Diagnostics related methods for `Ty`.
use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::TyKind::*;
use crate::ty::{
ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
- ProjectionTy, TyCtxt, TyS, TypeAndMut,
+ ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
};
use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -13,9 +13,9 @@
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
use rustc_span::Span;
-impl<'tcx> TyS<'tcx> {
- /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
- pub fn is_primitive_ty(&self) -> bool {
+impl<'tcx> Ty<'tcx> {
+ /// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive.
+ pub fn is_primitive_ty(self) -> bool {
matches!(
self.kind(),
Bool | Char
@@ -34,7 +34,7 @@
/// Whether the type is succinctly representable as a type instead of just referred to with a
/// description in error messages. This is used in the main error message.
- pub fn is_simple_ty(&self) -> bool {
+ pub fn is_simple_ty(self) -> bool {
match self.kind() {
Bool
| Char
@@ -58,7 +58,7 @@
/// description in error messages. This is used in the primary span label. Beyond what
/// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
/// ADTs with no type arguments.
- pub fn is_simple_text(&self) -> bool {
+ pub fn is_simple_text(self) -> bool {
match self.kind() {
Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
Ref(_, ty, _) => ty.is_simple_text(),
@@ -67,11 +67,11 @@
}
/// Whether the type can be safely suggested during error recovery.
- pub fn is_suggestable(&self) -> bool {
+ pub fn is_suggestable(self) -> bool {
fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool {
match arg.unpack() {
GenericArgKind::Type(ty) => ty.is_suggestable(),
- GenericArgKind::Const(c) => const_is_suggestable(c.val),
+ GenericArgKind::Const(c) => const_is_suggestable(c.val()),
_ => true,
}
}
@@ -105,8 +105,14 @@
ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
substs.iter().all(generic_arg_is_suggestible)
}
- ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
- ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
+ ExistentialPredicate::Projection(ExistentialProjection {
+ substs, term, ..
+ }) => {
+ let term_is_suggestable = match term {
+ Term::Ty(ty) => ty.is_suggestable(),
+ Term::Const(c) => const_is_suggestable(c.val()),
+ };
+ term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
}
_ => true,
}),
@@ -114,7 +120,7 @@
args.iter().all(generic_arg_is_suggestible)
}
Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(),
- Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val),
+ Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()),
_ => true,
}
}
@@ -448,12 +454,6 @@
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
- type Map = rustc_hir::intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::None
- }
-
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
match ty.kind {
hir::TyKind::TraitObject(
@@ -482,12 +482,6 @@
pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
- type Map = rustc_hir::intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::None
- }
-
fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
lt.name
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 0d29075..ef4f77c 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -21,9 +21,7 @@
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_POTENTIAL_FREE_REGIONS)
- {
+ if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_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 df6e739..2ccfeba 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -60,13 +60,13 @@
/// created a cycle (because it appears somewhere within that
/// type).
CyclicTy(Ty<'tcx>),
- CyclicConst(&'tcx ty::Const<'tcx>),
+ CyclicConst(ty::Const<'tcx>),
ProjectionMismatched(ExpectedFound<DefId>),
ExistentialMismatch(
ExpectedFound<&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>>,
),
ObjectUnsafeCoercion(DefId),
- ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
+ ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
IntrinsicCast,
/// Safe `#[target_feature]` functions are not assignable to safe function pointers.
@@ -239,8 +239,8 @@
}
}
-impl<'tcx> ty::TyS<'tcx> {
- pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
+impl<'tcx> Ty<'tcx> {
+ pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
match *self.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
format!("`{}`", self).into()
@@ -255,7 +255,7 @@
}
let n = tcx.lift(n).unwrap();
- if let ty::ConstKind::Value(v) = n.val {
+ if let ty::ConstKind::Value(v) = n.val() {
if let Some(n) = v.try_to_machine_usize(tcx) {
return format!("array of {} element{}", n, pluralize!(n)).into();
}
@@ -306,7 +306,7 @@
}
}
- pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
+ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
match *self.kind() {
ty::Infer(_)
| ty::Error(_)
@@ -869,7 +869,7 @@
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
// `expected` and point at it.
let parent_id = self.hir().get_parent_item(hir_id);
- let item = self.hir().find(parent_id);
+ let item = self.hir().find_by_def_id(parent_id);
debug!("expected_projection parent item {:?}", item);
match item {
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
@@ -972,10 +972,10 @@
let (span, sugg) = if has_params {
let pos = span.hi() - BytePos(1);
let span = Span::new(pos, pos, span.ctxt(), span.parent());
- (span, format!(", {} = {}", assoc.ident, ty))
+ (span, format!(", {} = {}", assoc.ident(self), ty))
} else {
let item_args = self.format_generic_args(assoc_substs);
- (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
+ (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
};
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
return true;
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index daf9156..983057b 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -54,12 +54,6 @@
No,
}
-#[derive(PartialEq, Eq, Debug, Clone, Copy)]
-pub enum StripReferences {
- Yes,
- No,
-}
-
/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
///
/// The idea is to get something simple that we can use to quickly decide if two types could unify,
@@ -73,8 +67,6 @@
/// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
/// the reasoning for this can be seen at the places doing this.
///
-/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best
-/// way to skip some unhelpful suggestions.
///
/// ¹ meaning that if two outermost layers are different, then the whole types are also different.
/// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
@@ -87,7 +79,6 @@
tcx: TyCtxt<'_>,
ty: Ty<'_>,
can_simplify_params: SimplifyParams,
- strip_references: StripReferences,
) -> Option<SimplifiedType> {
match *ty.kind() {
ty::Bool => Some(BoolSimplifiedType),
@@ -106,16 +97,7 @@
}
_ => Some(MarkerTraitObjectSimplifiedType),
},
- ty::Ref(_, ty, mutbl) => {
- if strip_references == StripReferences::Yes {
- // For diagnostics, when recommending similar impls we want to
- // recommend impls even when there is a reference mismatch,
- // so we treat &T and T equivalently in that case.
- simplify_type(tcx, ty, can_simplify_params, strip_references)
- } else {
- Some(RefSimplifiedType(mutbl))
- }
- }
+ ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)),
ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
ty::GeneratorWitness(ref tys) => {
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 617c522..948a48c 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -1,12 +1,12 @@
use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, InferConst, Ty, TypeFlags};
+use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
use std::slice;
#[derive(Debug)]
pub struct FlagComputation {
pub flags: TypeFlags,
- // see `TyS::outer_exclusive_binder` for details
+ // see `Ty::outer_exclusive_binder` for details
pub outer_exclusive_binder: ty::DebruijnIndex,
}
@@ -28,7 +28,7 @@
result
}
- pub fn for_const(c: &ty::Const<'_>) -> TypeFlags {
+ pub fn for_const(c: ty::Const<'_>) -> TypeFlags {
let mut result = FlagComputation::new();
result.add_const(c);
result.flags
@@ -97,7 +97,7 @@
&ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
&ty::Param(_) => {
- self.add_flags(TypeFlags::HAS_KNOWN_TY_PARAM);
+ self.add_flags(TypeFlags::HAS_TY_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
@@ -241,9 +241,12 @@
self.add_ty(a);
self.add_ty(b);
}
- ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+ ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
self.add_projection_ty(projection_ty);
- self.add_ty(ty);
+ match term {
+ Term::Ty(ty) => self.add_ty(ty),
+ Term::Const(c) => self.add_const(c),
+ }
}
ty::PredicateKind::WellFormed(arg) => {
self.add_substs(slice::from_ref(&arg));
@@ -267,7 +270,7 @@
fn add_ty(&mut self, ty: Ty<'_>) {
self.add_flags(ty.flags());
- self.add_exclusive_binder(ty.outer_exclusive_binder);
+ self.add_exclusive_binder(ty.outer_exclusive_binder());
}
fn add_tys(&mut self, tys: &[Ty<'_>]) {
@@ -283,9 +286,9 @@
}
}
- fn add_const(&mut self, c: &ty::Const<'_>) {
- self.add_ty(c.ty);
- match c.val {
+ fn add_const(&mut self, c: ty::Const<'_>) {
+ self.add_ty(c.ty());
+ match c.val() {
ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
ty::ConstKind::Infer(infer) => {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -298,7 +301,7 @@
self.add_bound_var(debruijn);
}
ty::ConstKind::Param(_) => {
- self.add_flags(TypeFlags::HAS_KNOWN_CT_PARAM);
+ self.add_flags(TypeFlags::HAS_CT_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Placeholder(_) => {
@@ -311,29 +314,16 @@
}
fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'_, 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_substs(ct.substs);
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
}
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_substs(projection.substs);
- self.add_ty(projection.ty);
+ match projection.term {
+ ty::Term::Ty(ty) => self.add_ty(ty),
+ ty::Term::Const(ct) => self.add_const(ct),
+ }
}
fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index f5be8b2..4922d07 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1,38 +1,56 @@
-//! Generalized type folding mechanism. The setup is a bit convoluted
-//! but allows for convenient usage. Let T be an instance of some
-//! "foldable type" (one which implements `TypeFoldable`) and F be an
-//! instance of a "folder" (a type which implements `TypeFolder`). Then
-//! the setup is intended to be:
+//! A generalized traversal mechanism for complex data structures that contain
+//! type information.
//!
-//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F)
+//! There are two types of traversal.
+//! - Folding. This is a modifying traversal. It consumes the data structure,
+//! producing a (possibly) modified version of it. Both fallible and
+//! infallible versions are available. The name is potentially
+//! confusing, because this traversal is more like `Iterator::map` than
+//! `Iterator::fold`.
+//! - Visiting. This is a read-only traversal of the data structure.
//!
-//! This way, when you define a new folder F, you can override
-//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()`
-//! to get the original behavior. Meanwhile, to actually fold
-//! something, you can just write `T.fold_with(F)`, which is
-//! convenient. (Note that `fold_with` will also transparently handle
-//! things like a `Vec<T>` where T is foldable and so on.)
+//! These traversals have limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! modification (when folding) or custom visitation (when visiting). These are
+//! the ones containing the most important type-related information, such as
+//! `Ty`, `Predicate`, `Region`, and `Const`.
//!
-//! In this ideal setup, the only function that actually *does*
-//! anything is `T.super_fold_with()`, which traverses the type `T`.
-//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`.
+//! There are two traits involved in each traversal type.
+//! - The first trait is `TypeFoldable`, which is implemented once for many
+//! types. This includes both (a) types of interest, and (b) all other
+//! relevant types, including generic containers like `Vec` and `Option`. It
+//! defines a "skeleton" of how they should be traversed, for both folding
+//! and visiting.
+//! - The second trait is `TypeFolder`/`FallibleTypeFolder` (for
+//! infallible/fallible folding traversals) or `TypeVisitor` (for visiting
+//! traversals). One of these is implemented for each folder/visitor. This
+//! defines how types of interest are handled.
//!
-//! In some cases, we follow a degenerate pattern where we do not have
-//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly.
-//! This is suboptimal because the behavior cannot be overridden, but it's
-//! much less work to implement. If you ever *do* need an override that
-//! doesn't exist, it's not hard to convert the degenerate pattern into the
-//! proper thing.
+//! This means each traversal is a mixture of (a) generic traversal operations,
+//! and (b) custom fold/visit operations that are specific to the
+//! folder/visitor.
+//! - The `TypeFoldable` impls handle most of the traversal, and call into
+//! `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a
+//! type of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call back into
+//! a `TypeFoldable` impl, because (a) the types of interest are recursive
+//! and can contain other types of interest, and (b) each folder/visitor
+//! might provide custom handling only for some types of interest, or only
+//! for some variants of each type of interest, and then use default
+//! traversal for the remaining cases.
//!
-//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup:
-//!
-//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V).
-//!
-//! These methods return true to indicate that the visitor has found what it is
-//! looking for, and does not need to visit anything else.
+//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
+//! TypeFoldable`, and an instance `S(ty, u)`, it would be visited like so:
+//! ```
+//! s.visit_with(visitor) calls
+//! - s.super_visit_with(visitor) calls
+//! - ty.visit_with(visitor) calls
+//! - visitor.visit_ty(ty) may call
+//! - ty.super_visit_with(visitor)
+//! - u.visit_with(visitor)
+//! ```
use crate::mir;
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
-use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_data_structures::fx::FxHashSet;
@@ -41,42 +59,67 @@
use std::fmt;
use std::ops::ControlFlow;
-/// This trait is implemented for every type that can be folded.
-/// Basically, every type that has a corresponding method in `TypeFolder`.
+/// This trait is implemented for every type that can be folded/visited,
+/// providing the skeleton of the traversal.
///
-/// To implement this conveniently, use the derive macro located in `rustc_macros`.
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
- /// Consumers may find this more convenient to use with infallible folders than
- /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the
- /// provided default definition delegates. Implementors **should not** override
- /// this provided default definition, to ensure that the two methods are coherent
- /// (provide a definition of `try_super_fold_with` instead).
- fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
- self.try_super_fold_with(folder).into_ok()
+ /// The main entry point for folding. To fold a value `t` with a folder `f`
+ /// call: `t.try_fold_with(f)`.
+ ///
+ /// For types of interest (such as `Ty`), this default is overridden with a
+ /// method that calls a folder method specifically for that type (such as
+ /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
+ /// to `TypeFolder`.
+ ///
+ /// For other types, this default is used.
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_super_fold_with(folder)
}
- /// Consumers may find this more convenient to use with infallible folders than
- /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided
- /// default definition delegates. Implementors **should not** override this
- /// provided default definition, to ensure that the two methods are coherent
- /// (provide a definition of `try_fold_with` instead).
+
+ /// A convenient alternative to `try_fold_with` for use with infallible
+ /// folders. Do not override this method, to ensure coherence with
+ /// `try_fold_with`.
fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
self.try_fold_with(folder).into_ok()
}
+ /// Traverses the type in question, typically by calling `try_fold_with` on
+ /// each field/element. This is true even for types of interest such as
+ /// `Ty`. This should only be called within `TypeFolder` methods, when
+ /// non-custom traversals are desired for types of interest.
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error>;
- fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- self.try_super_fold_with(folder)
+ /// A convenient alternative to `try_super_fold_with` for use with
+ /// infallible folders. Do not override this method, to ensure coherence
+ /// with `try_super_fold_with`.
+ fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_super_fold_with(folder).into_ok()
}
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+ /// The entry point for visiting. To visit a value `t` with a visitor `v`
+ /// call: `t.visit_with(v)`.
+ ///
+ /// For types of interest (such as `Ty`), this default is overridden with a
+ /// method that calls a visitor method specifically for that type (such as
+ /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+ /// `TypeVisitor`.
+ ///
+ /// For other types, this default is used.
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.super_visit_with(visitor)
}
+ /// Traverses the type in question, typically by calling `visit_with` on
+ /// each field/element. This is true even for types of interest such as
+ /// `Ty`. This should only be called within `TypeVisitor` methods, when
+ /// non-custom traversals are desired for types of interest.
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+
/// Returns `true` if `self` has any late-bound regions that are either
/// bound by `binder` or bound by some binder outside of `binder`.
/// If `binder` is `ty::INNERMOST`, this indicates whether
@@ -95,15 +138,9 @@
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)
- }
-
#[instrument(level = "trace")]
fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value()
- == Some(FoundFlags)
+ self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
}
fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION)
@@ -114,18 +151,8 @@
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ERROR)
}
- 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_param_types_or_consts(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
}
fn has_infer_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_INFER)
@@ -146,18 +173,13 @@
| TypeFlags::HAS_CT_PLACEHOLDER,
)
}
- 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)
+ fn needs_subst(&self) -> bool {
+ self.has_type_flags(TypeFlags::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, tcx: TyCtxt<'tcx>) -> bool {
- self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
+ fn has_free_regions(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
}
fn has_erased_regions(&self) -> bool {
@@ -165,25 +187,15 @@
}
/// True if there are any un-erased 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)
+ fn has_erasable_regions(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
}
/// 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, tcx: TyCtxt<'tcx>) -> bool {
- !self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES)
+ fn is_global(&self) -> bool {
+ !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
}
/// True if there are any late-bound regions
@@ -199,24 +211,13 @@
}
}
-impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
- fn try_super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
- Ok(self)
- }
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
- ControlFlow::CONTINUE
- }
-}
-
-/// The `TypeFolder` trait defines the actual *folding*. There is a
-/// method defined for every foldable type. Each of these has a
-/// default implementation that does an "identity" fold. Within each
-/// identity fold, it should invoke `foo.fold_with(self)` to fold each
-/// sub-item.
+/// This trait is implemented for every folding traversal. There is a fold
+/// method defined for every type of interest. Each such method has a default
+/// that does an "identity" fold.
///
/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
-/// associated type is something other than the default, never),
-/// [`FallibleTypeFolder`] should be implemented manually; otherwise,
+/// associated type is something other than the default `!`) then
+/// [`FallibleTypeFolder`] should be implemented manually. Otherwise,
/// a blanket implementation of [`FallibleTypeFolder`] will defer to
/// the infallible methods of this trait to ensure that the two APIs
/// are coherent.
@@ -247,7 +248,7 @@
r.super_fold_with(self)
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx>
where
Self: TypeFolder<'tcx, Error = !>,
{
@@ -269,11 +270,9 @@
}
}
-/// The `FallibleTypeFolder` trait defines the actual *folding*. There is a
-/// method defined for every foldable type. Each of these has a
-/// default implementation that does an "identity" fold. Within each
-/// identity fold, it should invoke `foo.try_fold_with(self)` to fold each
-/// sub-item.
+/// This trait is implemented for every folding traversal. There is a fold
+/// method defined for every type of interest. Each such method has a default
+/// that does an "identity" fold.
///
/// A blanket implementation of this trait (that defers to the relevant
/// method of [`TypeFolder`]) is provided for all infallible folders in
@@ -294,10 +293,7 @@
r.try_super_fold_with(self)
}
- fn try_fold_const(
- &mut self,
- c: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
c.try_super_fold_with(self)
}
@@ -316,8 +312,8 @@
}
}
-// Blanket implementation of fallible trait for infallible folders
-// delegates to infallible methods to prevent incoherence
+// This blanket implementation of the fallible trait for infallible folders
+// delegates to infallible methods to ensure coherence.
impl<'tcx, F> FallibleTypeFolder<'tcx> for F
where
F: TypeFolder<'tcx, Error = !>,
@@ -337,10 +333,7 @@
Ok(self.fold_region(r))
}
- fn try_fold_const(
- &mut self,
- c: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
Ok(self.fold_const(c))
}
@@ -359,19 +352,11 @@
}
}
+/// This trait is implemented for every visiting traversal. There is a visit
+/// method defined for every type of interest. Each such method has a default
+/// that recurses into the type's fields in a non-custom fashion.
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,
@@ -388,7 +373,7 @@
r.super_visit_with(self)
}
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
c.super_visit_with(self)
}
@@ -408,7 +393,7 @@
where
F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
- H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>,
+ H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
{
pub tcx: TyCtxt<'tcx>,
pub ty_op: F,
@@ -420,7 +405,7 @@
where
F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
- H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>,
+ H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
{
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
@@ -436,7 +421,7 @@
(self.lt_op)(r)
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
let ct = ct.super_fold_with(self);
(self.ct_op)(ct)
}
@@ -488,8 +473,7 @@
value: &impl TypeFoldable<'tcx>,
callback: impl FnMut(ty::Region<'tcx>) -> bool,
) -> bool {
- struct RegionVisitor<'tcx, F> {
- tcx: TyCtxt<'tcx>,
+ struct RegionVisitor<F> {
/// 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:
@@ -511,16 +495,12 @@
callback: F,
}
- impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F>
+ impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<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>,
@@ -548,7 +528,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_POTENTIAL_FREE_REGIONS) {
+ if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
ty.super_visit_with(self)
} else {
ControlFlow::CONTINUE
@@ -556,9 +536,7 @@
}
}
- value
- .visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback })
- .is_break()
+ value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
}
}
@@ -642,7 +620,7 @@
fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
- fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a)>,
+ fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
}
impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
@@ -650,7 +628,7 @@
tcx: TyCtxt<'tcx>,
fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
- fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a)>,
+ fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
) -> Self {
BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c }
}
@@ -676,7 +654,7 @@
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
if let Some(fld_t) = self.fld_t.as_mut() {
let ty = fld_t(bound_ty);
- return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
+ return ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32());
}
}
_ if t.has_vars_bound_at_or_above(self.current_index) => {
@@ -709,14 +687,12 @@
r
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- match *ct {
- ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
- if debruijn == self.current_index =>
- {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ match ct.val() {
+ ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
if let Some(fld_c) = self.fld_c.as_mut() {
- let ct = fld_c(bound_const, ty);
- return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
+ let ct = fld_c(bound_const, ct.ty());
+ return ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32());
}
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => {
@@ -775,7 +751,7 @@
where
F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
G: FnMut(ty::BoundTy) -> Ty<'tcx>,
- H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
+ H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
T: TypeFoldable<'tcx>,
{
if !value.has_escaping_bound_vars() {
@@ -800,7 +776,7 @@
where
F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
G: FnMut(ty::BoundTy) -> Ty<'tcx>,
- H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
+ H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
T: TypeFoldable<'tcx>,
{
let mut region_map = BTreeMap::new();
@@ -853,7 +829,7 @@
))
},
|c, ty| {
- self.mk_const(ty::Const {
+ self.mk_const(ty::ConstS {
val: ty::ConstKind::Bound(
ty::INNERMOST,
ty::BoundVar::from_usize(c.as_usize() + bound_vars),
@@ -897,7 +873,7 @@
where
T: TypeFoldable<'tcx>,
{
- let mut collector = LateBoundRegionsCollector::new(self, just_constraint);
+ let mut collector = LateBoundRegionsCollector::new(just_constraint);
let result = value.as_ref().skip_binder().visit_with(&mut collector);
assert!(result.is_continue()); // should never have stopped early
collector.regions
@@ -964,11 +940,6 @@
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>,
@@ -980,7 +951,7 @@
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if t.outer_exclusive_binder < self.binder_index
+ if t.outer_exclusive_binder() < self.binder_index
|| !self.visited.insert((self.binder_index, t))
{
return ControlFlow::BREAK;
@@ -1014,10 +985,10 @@
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match r {
- ty::ReLateBound(index, br) if *index == self.binder_index => {
+ match *r {
+ ty::ReLateBound(index, br) if index == self.binder_index => {
if self.bound_vars.len() <= br.var.as_usize() {
- bug!("Not enough bound vars: {:?} not found in {:?}", *br, self.bound_vars);
+ bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
}
let list_var = self.bound_vars[br.var.as_usize()];
match list_var {
@@ -1111,13 +1082,16 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.val() {
if self.amount == 0 || debruijn < self.current_index {
ct
} else {
let debruijn = debruijn.shifted_in(self.amount);
- self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
+ self.tcx.mk_const(ty::ConstS {
+ val: ty::ConstKind::Bound(debruijn, bound_ct),
+ ty: ct.ty(),
+ })
}
} else {
ct.super_fold_with(self)
@@ -1130,9 +1104,9 @@
region: ty::Region<'tcx>,
amount: u32,
) -> ty::Region<'tcx> {
- match region {
+ match *region {
ty::ReLateBound(debruijn, br) if amount > 0 => {
- tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br))
+ tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br))
}
_ => region,
}
@@ -1183,11 +1157,6 @@
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>,
@@ -1205,7 +1174,7 @@
// bound at `outer_index` or above (because
// `outer_exclusive_binder` is always 1 higher than the
// content in `t`). Therefore, `t` has some escaping vars.
- if t.outer_exclusive_binder > self.outer_index {
+ if t.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::CONTINUE
@@ -1224,13 +1193,13 @@
}
}
- fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
// we don't have a `visit_infer_const` callback, so we have to
// hook in here to catch this case (annoying...), but
// otherwise we do want to remember to visit the rest of the
// const, as it has types/regions embedded in a lot of other
// places.
- match ct.val {
+ match ct.val() {
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
ControlFlow::Break(FoundEscapingVars)
}
@@ -1240,7 +1209,7 @@
#[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
- if predicate.inner.outer_exclusive_binder > self.outer_index {
+ if predicate.outer_exclusive_binder() > self.outer_index {
ControlFlow::Break(FoundEscapingVars)
} else {
ControlFlow::CONTINUE
@@ -1252,35 +1221,32 @@
struct FoundFlags;
// FIXME: Optimize for checking for infer flags
-struct HasTypeFlagsVisitor<'tcx> {
- tcx: Option<TyCtxt<'tcx>>,
+struct HasTypeFlagsVisitor {
flags: ty::TypeFlags,
}
-impl<'tcx> std::fmt::Debug for HasTypeFlagsVisitor<'tcx> {
+impl std::fmt::Debug for HasTypeFlagsVisitor {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.flags.fmt(fmt)
}
}
-impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> {
+impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
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]
#[instrument(level = "trace")]
- fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- let flags = t.flags();
- trace!(t.flags=?t.flags());
- if flags.intersects(self.flags) {
+ 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) {
ControlFlow::Break(FoundFlags)
} else {
- match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
- true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, t),
- _ => ControlFlow::CONTINUE,
- }
+ ControlFlow::CONTINUE
}
}
@@ -1298,16 +1264,13 @@
#[inline]
#[instrument(level = "trace")]
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_const(c);
trace!(r.flags=?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, c),
- _ => ControlFlow::CONTINUE,
- }
+ ControlFlow::CONTINUE
}
}
@@ -1319,128 +1282,30 @@
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,
- }
+ ControlFlow::CONTINUE
}
}
#[inline]
#[instrument(level = "trace")]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
- let flags = predicate.inner.flags;
- trace!(predicate.flags=?flags);
- if flags.intersects(self.flags) {
+ debug!(
+ "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+ predicate,
+ predicate.flags(),
+ self.flags
+ );
+ if predicate.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<'tcx> {
- tcx: TyCtxt<'tcx>,
+struct LateBoundRegionsCollector {
current_index: ty::DebruijnIndex,
regions: FxHashSet<ty::BoundRegionKind>,
@@ -1454,10 +1319,9 @@
just_constrained: bool,
}
-impl<'tcx> LateBoundRegionsCollector<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
+impl LateBoundRegionsCollector {
+ fn new(just_constrained: bool) -> Self {
LateBoundRegionsCollector {
- tcx,
current_index: ty::INNERMOST,
regions: Default::default(),
just_constrained,
@@ -1465,11 +1329,7 @@
}
}
-impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> {
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
+impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
@@ -1493,12 +1353,12 @@
t.super_visit_with(self)
}
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
// if we are only looking for "constrained" region, we have to
// ignore the inputs of an unevaluated const, as they may not appear
// in the normalized form
if self.just_constrained {
- if let ty::ConstKind::Unevaluated(..) = c.val {
+ if let ty::ConstKind::Unevaluated(..) = c.val() {
return ControlFlow::CONTINUE;
}
}
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 1c3a01e..0bd96f8 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -31,6 +31,13 @@
GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
}
}
+
+ pub fn is_ty_or_const(&self) -> bool {
+ match self {
+ GenericParamDefKind::Lifetime => false,
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
+ }
+ }
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 9f47ed8..00ce15b 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -6,6 +6,7 @@
use crate::ty;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_query_system::ich::StableHashingContext;
use std::cell::RefCell;
@@ -17,12 +18,12 @@
{
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
thread_local! {
- static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> =
+ static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> =
RefCell::new(Default::default());
}
let hash = CACHE.with(|cache| {
- let key = (self.as_ptr() as usize, self.len());
+ let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls());
if let Some(&hash) = cache.borrow().get(&key) {
return hash;
}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
index f31c7dd..c4ad698 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
@@ -1,9 +1,8 @@
use crate::ty::context::TyCtxt;
use crate::ty::{DefId, DefIdTree};
-use rustc_hir::CRATE_HIR_ID;
+use rustc_span::def_id::CRATE_DEF_ID;
use smallvec::SmallVec;
use std::mem;
-use std::sync::Arc;
use DefIdForest::*;
@@ -18,14 +17,13 @@
/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
-#[derive(Clone, HashStable, Debug)]
-pub enum DefIdForest {
+#[derive(Copy, Clone, HashStable, Debug)]
+pub enum DefIdForest<'a> {
Empty,
Single(DefId),
/// This variant is very rare.
/// Invariant: >1 elements
- /// We use `Arc` because this is used in the output of a query.
- Multiple(Arc<[DefId]>),
+ Multiple(&'a [DefId]),
}
/// Tests whether a slice of roots contains a given DefId.
@@ -34,21 +32,21 @@
slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
}
-impl<'tcx> DefIdForest {
+impl<'tcx> DefIdForest<'tcx> {
/// Creates an empty forest.
- pub fn empty() -> DefIdForest {
+ pub fn empty() -> DefIdForest<'tcx> {
DefIdForest::Empty
}
/// Creates a forest consisting of a single tree representing the entire
/// crate.
#[inline]
- pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
- DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id())
+ pub fn full() -> DefIdForest<'tcx> {
+ DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
}
/// Creates a forest containing a `DefId` and all its descendants.
- pub fn from_id(id: DefId) -> DefIdForest {
+ pub fn from_id(id: DefId) -> DefIdForest<'tcx> {
DefIdForest::Single(id)
}
@@ -61,11 +59,11 @@
}
// Only allocates in the rare `Multiple` case.
- fn from_slice(root_ids: &[DefId]) -> DefIdForest {
- match root_ids {
+ fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> {
+ match &root_ids[..] {
[] => Empty,
[id] => Single(*id),
- _ => DefIdForest::Multiple(root_ids.into()),
+ _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)),
}
}
@@ -88,15 +86,15 @@
}
/// Calculate the intersection of a collection of forests.
- pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
+ pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
where
- I: IntoIterator<Item = DefIdForest>,
+ I: IntoIterator<Item = DefIdForest<'tcx>>,
{
let mut iter = iter.into_iter();
let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
SmallVec::from_slice(first.as_slice())
} else {
- return DefIdForest::full(tcx);
+ return DefIdForest::full();
};
let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
@@ -114,13 +112,13 @@
mem::swap(&mut next_ret, &mut ret);
next_ret.clear();
}
- DefIdForest::from_slice(&ret)
+ DefIdForest::from_vec(tcx, ret)
}
/// Calculate the union of a collection of forests.
- pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
+ pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
where
- I: IntoIterator<Item = DefIdForest>,
+ I: IntoIterator<Item = DefIdForest<'tcx>>,
{
let mut ret: SmallVec<[_; 1]> = SmallVec::new();
let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
@@ -142,6 +140,6 @@
mem::swap(&mut next_ret, &mut ret);
next_ret.clear();
}
- DefIdForest::from_slice(&ret)
+ DefIdForest::from_vec(tcx, ret)
}
}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 77d82ee..f2682b8 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -3,7 +3,7 @@
use crate::ty;
use crate::ty::context::TyCtxt;
use crate::ty::TyKind::*;
-use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
+use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::{DefId, SubstsRef};
@@ -112,7 +112,7 @@
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest {
+ ) -> DefIdForest<'tcx> {
// Non-exhaustive ADTs from other crates are always considered inhabited.
if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
DefIdForest::empty()
@@ -135,7 +135,7 @@
substs: SubstsRef<'tcx>,
adt_kind: AdtKind,
param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest {
+ ) -> DefIdForest<'tcx> {
let is_enum = match adt_kind {
// For now, `union`s are never considered uninhabited.
// The precise semantics of inhabitedness with respect to unions is currently undecided.
@@ -163,7 +163,7 @@
substs: SubstsRef<'tcx>,
is_enum: bool,
param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest {
+ ) -> DefIdForest<'tcx> {
let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with
// `Visibility::Invisible` so we need to override `self.vis` if we're
@@ -184,14 +184,14 @@
}
}
-impl<'tcx> TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
fn uninhabited_from(
- &'tcx self,
+ self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest {
- tcx.type_uninhabited_from(param_env.and(self))
+ ) -> DefIdForest<'tcx> {
+ tcx.type_uninhabited_from(param_env.and(self)).clone()
}
}
@@ -199,13 +199,13 @@
pub(crate) fn type_uninhabited_from<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> DefIdForest {
+) -> DefIdForest<'tcx> {
let ty = key.value;
let param_env = key.param_env;
match *ty.kind() {
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
- Never => DefIdForest::full(tcx),
+ Never => DefIdForest::full(),
Tuple(ref tys) => DefIdForest::union(
tcx,
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index eaa7ee8..99c595f 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -101,7 +101,7 @@
/// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
let ty = tcx.type_of(self.def.def_id());
- tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty)
+ tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty)
}
/// Finds a crate that contains a monomorphization of this instance that
@@ -642,7 +642,7 @@
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
debug!("fold_ty: ty={:?}", ty);
- match ty.kind {
+ match *ty.kind() {
ty::Closure(def_id, substs) => {
let polymorphized_substs = polymorphize(
self.tcx,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 196fe7c..6d4178c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -10,7 +10,7 @@
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::call::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
@@ -1310,7 +1310,10 @@
},
};
let mut abi = Abi::Aggregate { sized: true };
- if tag.value.size(dl) == size {
+
+ // Without latter check aligned enums with custom discriminant values
+ // Would result in ICE see the issue #92464 for more info
+ if tag.value.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
abi = Abi::Scalar(tag);
} else {
// Try to use a ScalarPair for all tagged enums.
@@ -1769,9 +1772,7 @@
// 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.definitely_has_param_types_or_consts(self.tcx)
- || !self.param_env.caller_bounds().is_empty()
- {
+ if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
return;
}
@@ -1810,7 +1811,7 @@
let adt_kind = adt_def.adt_kind();
let adt_packed = adt_def.repr.pack.is_some();
- let build_variant_info = |n: Option<Ident>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
+ let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
let mut min_size = Size::ZERO;
let field_info: Vec<_> = flds
.iter()
@@ -1845,15 +1846,15 @@
if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive {
debug!(
"print-type-size `{:#?}` variant {}",
- layout, adt_def.variants[index].ident
+ layout, adt_def.variants[index].name
);
let variant_def = &adt_def.variants[index];
- let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect();
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
record(
adt_kind.into(),
adt_packed,
None,
- vec![build_variant_info(Some(variant_def.ident), &fields, layout)],
+ vec![build_variant_info(Some(variant_def.name), &fields, layout)],
);
} else {
// (This case arises for *empty* enums; so give it
@@ -1872,10 +1873,9 @@
.variants
.iter_enumerated()
.map(|(i, variant_def)| {
- let fields: Vec<_> =
- variant_def.fields.iter().map(|f| f.ident.name).collect();
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
build_variant_info(
- Some(variant_def.ident),
+ Some(variant_def.name),
&fields,
layout.for_variant(self, i),
)
@@ -1937,7 +1937,7 @@
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.kind() {
ty::Param(_) | ty::Projection(_) => {
- debug_assert!(tail.definitely_has_param_types_or_consts(tcx));
+ debug_assert!(tail.has_param_types_or_consts());
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
}
_ => bug!(
@@ -2776,17 +2776,20 @@
// [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 } => {
+ C { unwind }
+ | System { unwind }
+ | Cdecl { unwind }
+ | Stdcall { unwind }
+ | Fastcall { unwind }
+ | Vectorcall { unwind }
+ | Thiscall { unwind }
+ | Aapcs { unwind }
+ | Win64 { unwind }
+ | SysV64 { unwind } => {
unwind
|| (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
}
- Cdecl
- | Fastcall
- | Vectorcall
- | Aapcs
- | Win64
- | SysV64
- | PtxKernel
+ PtxKernel
| Msp430Interrupt
| X86Interrupt
| AmdGpuKernel
@@ -2813,14 +2816,14 @@
EfiApi => bug!("eficall abi should be selected elsewhere"),
Stdcall { .. } => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
+ Fastcall { .. } => Conv::X86Fastcall,
+ Vectorcall { .. } => Conv::X86VectorCall,
Thiscall { .. } => Conv::X86ThisCall,
C { .. } => Conv::C,
Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
+ Win64 { .. } => Conv::X86_64Win64,
+ SysV64 { .. } => Conv::X86_64SysV,
+ Aapcs { .. } => Conv::ArmAapcs,
CCmseNonSecureCall => Conv::CCmseNonSecureCall,
PtxKernel => Conv::PtxKernel,
Msp430Interrupt => Conv::Msp430Intr,
@@ -2831,12 +2834,12 @@
Wasm => Conv::C,
// These API constants ought to be more specific...
- Cdecl => Conv::C,
+ Cdecl { .. } => Conv::C,
}
}
/// Error produced by attempting to compute or adjust a `FnAbi`.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable)]
pub enum FnAbiError<'tcx> {
/// Error produced by a `layout_of` call, while computing `FnAbi` initially.
Layout(LayoutError<'tcx>),
@@ -3048,9 +3051,10 @@
layout: TyAndLayout<'tcx>,
offset: Size,
is_return: bool| {
- // Booleans are always an i1 that needs to be zero-extended.
+ // Booleans are always a noundef i1 that needs to be zero-extended.
if scalar.is_bool() {
attrs.ext(ArgExtension::Zext);
+ attrs.set(ArgAttribute::NoUndef);
return;
}
@@ -3075,6 +3079,11 @@
_ => pointee.size,
};
+ // `Box`, `&T`, and `&mut T` cannot be undef.
+ // Note that this only applies to the value of the pointer itself;
+ // this attribute doesn't make it UB for the pointed-to data to be undef.
+ attrs.set(ArgAttribute::NoUndef);
+
// `Box` pointer parameters never alias because ownership is transferred
// `&mut` pointer parameters never alias other parameters,
// or mutable global data
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 78ccfbd..f0b7f2a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -19,7 +19,8 @@
pub use generics::*;
pub use vtable::*;
-use crate::hir::exports::ExportMap;
+use crate::metadata::ModChild;
+use crate::middle::privacy::AccessLevels;
use crate::mir::{Body, GeneratorLayout};
use crate::traits::{self, Reveal};
use crate::ty;
@@ -27,7 +28,8 @@
use crate::ty::util::Discr;
use rustc_ast as ast;
use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_hir as hir;
@@ -41,11 +43,9 @@
use rustc_span::{sym, Span};
use rustc_target::abi::Align;
-use std::cmp::Ordering;
-use std::collections::BTreeMap;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
use std::ops::ControlFlow;
-use std::{fmt, ptr, str};
+use std::{fmt, str};
pub use crate::ty::diagnostics::*;
pub use rustc_type_ir::InferTy::*;
@@ -56,10 +56,12 @@
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,
+ RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
+ CAPTURE_STRUCT_LOCAL,
};
-pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree};
+pub use self::consts::{
+ Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree,
+};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
@@ -118,27 +120,31 @@
// Data types
+pub type RegisteredTools = FxHashSet<Ident>;
+
#[derive(Debug)]
pub struct ResolverOutputs {
pub definitions: rustc_hir::definitions::Definitions,
pub cstore: Box<CrateStoreDyn>,
pub visibilities: FxHashMap<LocalDefId, Visibility>,
+ pub access_levels: AccessLevels,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
- pub export_map: ExportMap,
+ pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
/// Extern prelude entries. The value is `true` if the entry was introduced
/// 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>>,
+ pub trait_impls: FxIndexMap<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>,
/// 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: FxHashMap<Span, Span>,
+ pub registered_tools: RegisteredTools,
}
#[derive(Clone, Copy, Debug)]
@@ -374,15 +380,32 @@
pub pos: usize,
}
+/// Represents a type.
+///
+/// IMPORTANT:
+/// - This is a very "dumb" struct (with no derives and no `impls`).
+/// - Values of this type are always interned and thus unique, and are stored
+/// as an `Interned<TyS>`.
+/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>`
+/// should be used everywhere instead of `TyS`. In particular, `Ty` has most
+/// of the relevant methods.
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
#[allow(rustc::usage_of_ty_tykind)]
-pub struct TyS<'tcx> {
+crate struct TyS<'tcx> {
/// This field shouldn't be used directly and may be removed in the future.
- /// Use `TyS::kind()` instead.
+ /// Use `Ty::kind()` instead.
kind: TyKind<'tcx>,
+
+ /// This field provides fast access to information that is also contained
+ /// in `kind`.
+ ///
/// This field shouldn't be used directly and may be removed in the future.
- /// Use `TyS::flags()` instead.
+ /// Use `Ty::flags()` instead.
flags: TypeFlags,
+ /// This field provides fast access to information that is also contained
+ /// in `kind`.
+ ///
/// This is a kind of confusing thing: it stores the smallest
/// binder such that
///
@@ -403,51 +426,27 @@
outer_exclusive_binder: ty::DebruijnIndex,
}
-impl<'tcx> TyS<'tcx> {
- /// A constructor used only for internal testing.
- #[allow(rustc::usage_of_ty_tykind)]
- pub fn make_for_test(
- kind: TyKind<'tcx>,
- flags: TypeFlags,
- outer_exclusive_binder: ty::DebruijnIndex,
- ) -> TyS<'tcx> {
- TyS { kind, flags, outer_exclusive_binder }
- }
-}
-
// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(TyS<'_>, 40);
-impl<'tcx> Ord for TyS<'tcx> {
- fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
- self.kind().cmp(other.kind())
- }
-}
+/// Use this rather than `TyS`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[rustc_diagnostic_item = "Ty"]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
-impl<'tcx> PartialOrd for TyS<'tcx> {
- fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> {
- Some(self.kind().cmp(other.kind()))
- }
-}
+// Statics only used for internal testing.
+pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&BOOL_TYS));
+static BOOL_TYS: TyS<'static> = TyS {
+ kind: ty::Bool,
+ flags: TypeFlags::empty(),
+ outer_exclusive_binder: DebruijnIndex::from_usize(0),
+};
-impl<'tcx> PartialEq for TyS<'tcx> {
- #[inline]
- fn eq(&self, other: &TyS<'tcx>) -> bool {
- ptr::eq(self, other)
- }
-}
-impl<'tcx> Eq for TyS<'tcx> {}
-
-impl<'tcx> Hash for TyS<'tcx> {
- fn hash<H: Hasher>(&self, s: &mut H) {
- (self as *const TyS<'_>).hash(s)
- }
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Ty<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let ty::TyS {
+ let TyS {
ref kind,
// The other fields just provide fast access to information that is
@@ -455,15 +454,12 @@
flags: _,
outer_exclusive_binder: _,
- } = *self;
+ } = self.0.0;
kind.hash_stable(hcx, hasher);
}
}
-#[rustc_diagnostic_item = "Ty"]
-pub type Ty<'tcx> = &'tcx TyS<'tcx>;
-
impl ty::EarlyBoundRegion {
/// Does this early bound region have a name? Early bound regions normally
/// always have names except when using anonymous lifetimes (`'_`).
@@ -472,51 +468,50 @@
}
}
+/// Represents a predicate.
+///
+/// See comments on `TyS`, which apply here too (albeit for
+/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`).
#[derive(Debug)]
-crate struct PredicateInner<'tcx> {
+crate struct PredicateS<'tcx> {
kind: Binder<'tcx, PredicateKind<'tcx>>,
flags: TypeFlags,
/// See the comment for the corresponding field of [TyS].
outer_exclusive_binder: ty::DebruijnIndex,
}
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateInner<'_>, 48);
+static_assert_size!(PredicateS<'_>, 56);
-#[derive(Clone, Copy, Lift)]
-pub struct Predicate<'tcx> {
- inner: &'tcx PredicateInner<'tcx>,
-}
-
-impl<'tcx> PartialEq for Predicate<'tcx> {
- fn eq(&self, other: &Self) -> bool {
- // `self.kind` is always interned.
- ptr::eq(self.inner, other.inner)
- }
-}
-
-impl Hash for Predicate<'_> {
- fn hash<H: Hasher>(&self, s: &mut H) {
- (self.inner as *const PredicateInner<'_>).hash(s)
- }
-}
-
-impl<'tcx> Eq for Predicate<'tcx> {}
+/// Use this rather than `PredicateS`, whenever possible.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>);
impl<'tcx> Predicate<'tcx> {
/// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
#[inline]
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
- self.inner.kind
+ self.0.kind
+ }
+
+ #[inline(always)]
+ pub fn flags(self) -> TypeFlags {
+ self.0.flags
+ }
+
+ #[inline(always)]
+ pub fn outer_exclusive_binder(self) -> DebruijnIndex {
+ self.0.outer_exclusive_binder
}
/// Flips the polarity of a Predicate.
///
/// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
- pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
+ pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
let kind = self
- .inner
- .kind
+ .kind()
.map_bound(|kind| match kind {
PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
Some(PredicateKind::Trait(TraitPredicate {
@@ -536,14 +531,14 @@
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let PredicateInner {
+ let PredicateS {
ref kind,
// The other fields just provide fast access to information that is
// also contained in `kind`, so no need to hash them.
flags: _,
outer_exclusive_binder: _,
- } = self.inner;
+ } = self.0.0;
kind.hash_stable(hcx, hasher);
}
@@ -599,7 +594,7 @@
ConstEvaluatable(ty::Unevaluated<'tcx, ()>),
/// Constants must be equal. The first component is the const that is expected.
- ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
+ ConstEquate(Const<'tcx>, Const<'tcx>),
/// Represents a type found in the environment that we can use for implied bounds.
///
@@ -743,6 +738,17 @@
*param_env = param_env.with_constness(self.constness.and(param_env.constness()))
}
}
+
+ /// Remap the constness of this predicate before emitting it for diagnostics.
+ pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
+ // this is different to `remap_constness` that callees want to print this predicate
+ // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the
+ // param_env is not const because we it is always satisfied in non-const contexts.
+ if let hir::Constness::NotConst = param_env.constness() {
+ self.constness = ty::BoundConstness::NotConst;
+ }
+ }
+
pub fn def_id(self) -> DefId {
self.trait_ref.def_id
}
@@ -750,6 +756,11 @@
pub fn self_ty(self) -> Ty<'tcx> {
self.trait_ref.self_ty()
}
+
+ #[inline]
+ pub fn is_const_if_const(self) -> bool {
+ self.constness == BoundConstness::ConstIfConst
+ }
}
impl<'tcx> PolyTraitPredicate<'tcx> {
@@ -761,6 +772,19 @@
pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> {
self.map_bound(|trait_ref| trait_ref.self_ty())
}
+
+ /// Remap the constness of this predicate before emitting it for diagnostics.
+ pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
+ *self = self.map_bound(|mut p| {
+ p.remap_constness_diag(param_env);
+ p
+ });
+ }
+
+ #[inline]
+ pub fn is_const_if_const(self) -> bool {
+ self.skip_binder().is_const_if_const()
+ }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
@@ -792,6 +816,34 @@
}
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable)]
+pub enum Term<'tcx> {
+ Ty(Ty<'tcx>),
+ Const(Const<'tcx>),
+}
+
+impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
+ fn from(ty: Ty<'tcx>) -> Self {
+ Term::Ty(ty)
+ }
+}
+
+impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
+ fn from(c: Const<'tcx>) -> Self {
+ Term::Const(c)
+ }
+}
+
+impl<'tcx> Term<'tcx> {
+ pub fn ty(&self) -> Option<Ty<'tcx>> {
+ if let Term::Ty(ty) = self { Some(*ty) } else { None }
+ }
+ pub fn ct(&self) -> Option<Const<'tcx>> {
+ if let Term::Const(c) = self { Some(*c) } else { None }
+ }
+}
+
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
@@ -808,7 +860,7 @@
#[derive(HashStable, TypeFoldable)]
pub struct ProjectionPredicate<'tcx> {
pub projection_ty: ProjectionTy<'tcx>,
- pub ty: Ty<'tcx>,
+ pub term: Term<'tcx>,
}
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
@@ -833,8 +885,8 @@
self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
}
- pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
- self.map_bound(|predicate| predicate.ty)
+ pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
+ self.map_bound(|predicate| predicate.term)
}
/// The `DefId` of the `TraitItem` for the associated type.
@@ -1321,6 +1373,11 @@
self.packed.tag().constness
}
+ #[inline]
+ pub fn is_const(self) -> bool {
+ self.packed.tag().constness == hir::Constness::Const
+ }
+
/// Construct a trait environment with no where-clauses in scope
/// where the values of all `impl Trait` and other hidden types
/// are revealed. This is suitable for monomorphized, post-typeck
@@ -1415,7 +1472,7 @@
Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
Reveal::All => {
- if value.is_known_global() {
+ if value.is_global() {
ParamEnvAnd { param_env: self.without_caller_bounds(), value }
} else {
ParamEnvAnd { param_env: self, value }
@@ -1436,6 +1493,7 @@
polarity: ty::ImplPolarity::Positive,
})
}
+
#[inline]
pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
self.with_constness(BoundConstness::NotConst)
@@ -1502,8 +1560,7 @@
/// If this variant is a struct variant, then this is `None`.
pub ctor_def_id: Option<DefId>,
/// Variant or struct name.
- #[stable_hasher(project(name))]
- pub ident: Ident,
+ pub name: Symbol,
/// Discriminant of this variant.
pub discr: VariantDiscr,
/// Fields of this variant.
@@ -1532,7 +1589,7 @@
/// If someone speeds up attribute loading to not be a performance concern, they can
/// remove this hack and use the constructor `DefId` everywhere.
pub fn new(
- ident: Ident,
+ name: Symbol,
variant_did: Option<DefId>,
ctor_def_id: Option<DefId>,
discr: VariantDiscr,
@@ -1544,9 +1601,9 @@
is_field_list_non_exhaustive: bool,
) -> Self {
debug!(
- "VariantDef::new(ident = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
+ "VariantDef::new(name = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})",
- ident, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
+ name, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
);
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
@@ -1561,7 +1618,7 @@
VariantDef {
def_id: variant_did.unwrap_or(parent_did),
ctor_def_id,
- ident,
+ name,
discr,
fields,
ctor_kind,
@@ -1580,6 +1637,11 @@
pub fn is_recovered(&self) -> bool {
self.flags.intersects(VariantFlags::IS_RECOVERED)
}
+
+ /// Computes the `Ident` of this variant by looking up the `Span`
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
@@ -1598,8 +1660,7 @@
#[derive(Debug, HashStable, TyEncodable, TyDecodable)]
pub struct FieldDef {
pub did: DefId,
- #[stable_hasher(project(name))]
- pub ident: Ident,
+ pub name: Symbol,
pub vis: Visibility,
}
@@ -1774,6 +1835,11 @@
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).subst(tcx, subst)
}
+
+ /// Computes the `Ident` of this variant by looking up the `Span`
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
+ }
}
pub type Attributes<'tcx> = &'tcx [ast::Attribute];
@@ -1890,7 +1956,10 @@
}
pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
- variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id))
+ variant
+ .fields
+ .iter()
+ .position(|field| self.hygienic_eq(ident, field.ident(self), variant.def_id))
}
/// Returns `true` if the impls are the same polarity and the trait either
@@ -2069,8 +2138,7 @@
/// with the name of the crate containing the impl.
pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
if let Some(impl_did) = impl_did.as_local() {
- let hir_id = self.hir().local_def_id_to_hir_id(impl_did);
- Ok(self.hir().span(hir_id))
+ Ok(self.def_span(impl_did))
} else {
Err(self.crate_name(impl_did.krate))
}
@@ -2117,7 +2185,7 @@
/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> {
let def_id = def_id.as_local()?;
- if let Node::Item(item) = tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
+ if let Node::Item(item) = tcx.hir().get_by_def_id(def_id) {
if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
return match opaque_ty.origin {
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 84ab42a..808be44 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -34,8 +34,8 @@
/// Erase the regions in `value` and then fully normalize all the
/// types found within. The result will also have regions erased.
///
- /// This is appropriate to use only after type-check: it assumes
- /// that normalization will succeed, for example.
+ /// This should only be used outside of type inference. For example,
+ /// it assumes that normalization will succeed.
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
where
T: TypeFoldable<'tcx>,
@@ -192,7 +192,7 @@
self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
}
@@ -244,13 +244,10 @@
}
}
- fn try_fold_const(
- &mut self,
- c: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
Ok(t) => Ok(t.expect_const()),
- Err(_) => Err(NormalizationError::Const(*c)),
+ Err(_) => Err(NormalizationError::Const(c)),
}
}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 94127a1..94cea50 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -66,7 +66,7 @@
predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
) -> Result<Self::DynExistential, Self::Error>;
- fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;
+ fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>;
@@ -321,19 +321,11 @@
characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
}
-impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind {
- type Output = P::Region;
- type Error = P::Error;
- fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
- cx.print_region(self)
- }
-}
-
impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> {
type Output = P::Region;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
- cx.print_region(self)
+ cx.print_region(*self)
}
}
@@ -341,7 +333,7 @@
type Output = P::Type;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
- cx.print_type(self)
+ cx.print_type(*self)
}
}
@@ -355,10 +347,10 @@
}
}
-impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> {
+impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
type Output = P::Const;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
- cx.print_const(self)
+ cx.print_const(*self)
}
}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 47a9234..bf7370c 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,8 +1,9 @@
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -130,11 +131,13 @@
///
/// Regions not selected by the region highlight mode are presently
/// unaffected.
-#[derive(Copy, Clone, Default)]
-pub struct RegionHighlightMode {
+#[derive(Copy, Clone)]
+pub struct RegionHighlightMode<'tcx> {
+ tcx: TyCtxt<'tcx>,
+
/// If enabled, when we see the selected region, use "`'N`"
/// instead of the ordinary behavior.
- highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
+ highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
/// If enabled, when printing a "free region" that originated from
/// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily
@@ -146,12 +149,20 @@
highlight_bound_region: Option<(ty::BoundRegionKind, usize)>,
}
-impl RegionHighlightMode {
+impl<'tcx> RegionHighlightMode<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+ Self {
+ tcx,
+ highlight_regions: Default::default(),
+ highlight_bound_region: Default::default(),
+ }
+ }
+
/// If `region` and `number` are both `Some`, invokes
/// `highlighting_region`.
pub fn maybe_highlighting_region(
&mut self,
- region: Option<ty::Region<'_>>,
+ region: Option<ty::Region<'tcx>>,
number: Option<usize>,
) {
if let Some(k) = region {
@@ -162,24 +173,24 @@
}
/// Highlights the region inference variable `vid` as `'N`.
- pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) {
+ pub fn highlighting_region(&mut self, region: ty::Region<'tcx>, number: usize) {
let num_slots = self.highlight_regions.len();
let first_avail_slot =
self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| {
bug!("can only highlight {} placeholders at a time", num_slots,)
});
- *first_avail_slot = Some((*region, number));
+ *first_avail_slot = Some((region, number));
}
/// Convenience wrapper for `highlighting_region`.
pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
- self.highlighting_region(&ty::ReVar(vid), number)
+ self.highlighting_region(self.tcx.mk_region(ty::ReVar(vid)), number)
}
/// Returns `Some(n)` with the number to use for the given region, if any.
fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
self.highlight_regions.iter().find_map(|h| match h {
- Some((r, n)) if r == region => Some(*n),
+ Some((r, n)) if *r == region => Some(*n),
_ => None,
})
}
@@ -458,7 +469,7 @@
// that's public and whose identifier isn't `_`.
let reexport = self
.tcx()
- .item_children(visible_parent)
+ .module_children(visible_parent)
.iter()
.filter(|child| child.res.opt_def_id() == Some(def_id))
.find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
@@ -595,7 +606,7 @@
ty::Infer(infer_ty) => {
let verbose = self.tcx().sess.verbose();
if let ty::TyVar(ty_vid) = infer_ty {
- if let Some(name) = self.infer_ty_name(ty_vid) {
+ if let Some(name) = self.ty_infer_name(ty_vid) {
p!(write("{}", name))
} else {
if verbose {
@@ -671,8 +682,7 @@
p!("generator");
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
- let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
- let span = self.tcx().hir().span(hir_id);
+ let span = self.tcx().def_span(did);
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
@@ -708,11 +718,10 @@
p!(write("closure"));
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
- let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
if self.tcx().sess.opts.debugging_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), substs));
} else {
- let span = self.tcx().hir().span(hir_id);
+ let span = self.tcx().def_span(did);
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
@@ -745,14 +754,14 @@
p!("[", print(ty), "; ");
if self.tcx().sess.verbose() {
p!(write("{:?}", sz));
- } else if let ty::ConstKind::Unevaluated(..) = sz.val {
+ } else if let ty::ConstKind::Unevaluated(..) = sz.val() {
// Do not try to evaluate unevaluated constants. If we are const evaluating an
// array length anon const, rustc will (with debug assertions) print the
// constant's path. Which will end up here again.
p!("_");
- } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
+ } else if let Some(n) = sz.val().try_to_bits(self.tcx().data_layout.pointer_size) {
p!(write("{}", n));
- } else if let ty::ConstKind::Param(param) = sz.val {
+ } else if let ty::ConstKind::Param(param) = sz.val() {
p!(write("{}", param));
} else {
p!("_");
@@ -801,7 +810,7 @@
let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
// Projection type entry -- the def-id for naming, and the ty.
- let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
+ let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
self.insert_trait_and_projection(
trait_ref,
@@ -852,8 +861,10 @@
}
p!(")");
- if !return_ty.skip_binder().is_unit() {
- p!("-> ", print(return_ty));
+ if let Term::Ty(ty) = return_ty.skip_binder() {
+ if !ty.is_unit() {
+ p!("-> ", print(return_ty));
+ }
}
p!(write("{}", if paren_needed { ")" } else { "" }));
@@ -904,23 +915,28 @@
first = false;
}
- for (assoc_item_def_id, ty) in assoc_items {
+ for (assoc_item_def_id, term) in assoc_items {
if !first {
p!(", ");
}
- p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
+ p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name));
- // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
- match ty.skip_binder().kind() {
- ty::Projection(ty::ProjectionTy { item_def_id, .. })
- if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
- {
- p!("[async output]")
+ match term.skip_binder() {
+ Term::Ty(ty) => {
+ // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+ if matches!(
+ ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
+ if Some(*item_def_id) == self.tcx().lang_items().generator_return()
+ ) {
+ p!("[async output]")
+ } else {
+ p!(print(ty))
+ }
}
- _ => {
- p!(print(ty))
+ Term::Const(c) => {
+ p!(print(c));
}
- }
+ };
first = false;
}
@@ -945,8 +961,11 @@
fn insert_trait_and_projection(
&mut self,
trait_ref: ty::PolyTraitRef<'tcx>,
- proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
- traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
+ proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
+ traits: &mut BTreeMap<
+ ty::PolyTraitRef<'tcx>,
+ BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+ >,
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
) {
let trait_def_id = trait_ref.def_id();
@@ -996,7 +1015,11 @@
}
}
- fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
+ fn ty_infer_name(&self, _: ty::TyVid) -> Option<String> {
+ None
+ }
+
+ fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<String> {
None
}
@@ -1021,7 +1044,11 @@
let mut projections = predicates.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) {
let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
- p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
+ p!(pretty_fn_sig(
+ &tys,
+ false,
+ proj.skip_binder().term.ty().expect("Return type was a const")
+ ));
resugared = true;
}
}
@@ -1041,7 +1068,7 @@
// Don't print `'_` if there's no unerased regions.
let print_regions = args.iter().any(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+ GenericArgKind::Lifetime(r) => !r.is_erased(),
_ => false,
});
let mut args = args.iter().cloned().filter(|arg| match arg.unpack() {
@@ -1125,13 +1152,13 @@
fn pretty_print_const(
mut self,
- ct: &'tcx ty::Const<'tcx>,
+ ct: ty::Const<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
if self.tcx().sess.verbose() {
- p!(write("Const({:?}: {:?})", ct.val, ct.ty));
+ p!(write("Const({:?}: {:?})", ct.val(), ct.ty()));
return Ok(self);
}
@@ -1143,7 +1170,7 @@
write!(this, "_")?;
Ok(this)
},
- |this| this.print_type(ct.ty),
+ |this| this.print_type(ct.ty()),
": ",
)?;
} else {
@@ -1152,37 +1179,45 @@
}};
}
- match ct.val {
- 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 {
- let tcx = self.tcx();
- match tcx.def_kind(uv.def.did) {
- DefKind::Static | DefKind::Const | DefKind::AssocConst => {
- p!(print_value_path(uv.def.did, uv.substs(tcx)))
- }
- _ => {
- 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!()
- }
+ match ct.val() {
+ ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def,
+ substs,
+ promoted: Some(promoted),
+ }) => {
+ p!(print_value_path(def.did, substs));
+ p!(write("::{:?}", promoted));
+ }
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => {
+ match self.tcx().def_kind(def.did) {
+ DefKind::Static | DefKind::Const | DefKind::AssocConst => {
+ p!(print_value_path(def.did, substs))
+ }
+ _ => {
+ 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) {
+ p!(write("{}", snip))
} else {
print_underscore!()
}
+ } else {
+ print_underscore!()
}
}
}
}
- ty::ConstKind::Infer(..) => print_underscore!(),
+ ty::ConstKind::Infer(infer_ct) => {
+ match infer_ct {
+ ty::InferConst::Var(ct_vid)
+ if let Some(name) = self.const_infer_name(ct_vid) =>
+ p!(write("{}", name)),
+ _ => print_underscore!(),
+ }
+ }
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
ty::ConstKind::Value(value) => {
- return self.pretty_print_const_value(value, ct.ty, print_ty);
+ return self.pretty_print_const_value(value, ct.ty(), print_ty);
}
ty::ConstKind::Bound(debruijn, bound_var) => {
@@ -1219,16 +1254,23 @@
// Byte strings (&[u8; N])
ty::Ref(
_,
- ty::TyS {
- kind:
- ty::Array(
- ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. },
- ty::Const {
- val: ty::ConstKind::Value(ConstValue::Scalar(int)), ..
- },
- ),
- ..
- },
+ Ty(Interned(
+ ty::TyS {
+ kind:
+ ty::Array(
+ Ty(Interned(ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, _)),
+ ty::Const(Interned(
+ ty::ConstS {
+ val: ty::ConstKind::Value(ConstValue::Scalar(int)),
+ ..
+ },
+ _,
+ )),
+ ),
+ ..
+ },
+ _,
+ )),
_,
) => match self.tcx().get_global_alloc(alloc_id) {
Some(GlobalAlloc::Memory(alloc)) => {
@@ -1386,7 +1428,7 @@
// Byte/string slices, printed as (byte) string literals.
(
ConstValue::Slice { data, start, end },
- ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _),
+ ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Slice(t), .. }, _)), _),
) if *t == u8_type => {
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
@@ -1396,7 +1438,7 @@
}
(
ConstValue::Slice { data, start, end },
- ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _),
+ ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Str, .. }, _)), _),
) => {
// 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
@@ -1407,7 +1449,7 @@
Ok(self)
}
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
- let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
+ let n = n.val().try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
// cast is ok because we already checked for pointer size (32 or 64 bit) above
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
@@ -1419,7 +1461,7 @@
// Aggregates, printed as array/tuple/struct/variant construction syntax.
//
- // NB: the `potentially_has_param_types_or_consts` check ensures that we can use
+ // NB: the `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`
@@ -1427,13 +1469,19 @@
//
// 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.potentially_has_param_types_or_consts() =>
- {
- let contents = self.tcx().destructure_const(
+ (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
+ let Some(contents) = self.tcx().try_destructure_const(
ty::ParamEnv::reveal_all()
- .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
- );
+ .and(self.tcx().mk_const(ty::ConstS { val: ty::ConstKind::Value(ct), ty })),
+ ) else {
+ // Fall back to debug pretty printing for invalid constants.
+ p!(write("{:?}", ct));
+ if print_ty {
+ p!(": ", print(ty));
+ }
+ return Ok(self);
+ };
+
let fields = contents.fields.iter().copied();
match *ty.kind() {
@@ -1475,7 +1523,7 @@
if !first {
p!(", ");
}
- p!(write("{}: ", field_def.ident), print(field));
+ p!(write("{}: ", field_def.name), print(field));
first = false;
}
p!(" }}");
@@ -1520,9 +1568,10 @@
binder_depth: usize,
printed_type_count: usize,
- pub region_highlight_mode: RegionHighlightMode,
+ pub region_highlight_mode: RegionHighlightMode<'tcx>,
- pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>,
+ pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<String> + 'a>>,
+ pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<String> + 'a>>,
}
impl<'a, 'tcx, F> Deref for FmtPrinter<'a, 'tcx, F> {
@@ -1550,8 +1599,9 @@
region_index: 0,
binder_depth: 0,
printed_type_count: 0,
- region_highlight_mode: RegionHighlightMode::default(),
- name_resolver: None,
+ region_highlight_mode: RegionHighlightMode::new(tcx),
+ ty_infer_name_resolver: None,
+ const_infer_name_resolver: None,
}))
}
}
@@ -1691,7 +1741,7 @@
self.pretty_print_dyn_existential(predicates)
}
- fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
self.pretty_print_const(ct, true)
}
@@ -1784,10 +1834,11 @@
self = print_prefix(self)?;
// Don't print `'_` if there's no unerased regions.
- let print_regions = args.iter().any(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => *r != ty::ReErased,
- _ => false,
- });
+ let print_regions = self.tcx.sess.verbose()
+ || args.iter().any(|arg| match arg.unpack() {
+ GenericArgKind::Lifetime(r) => !r.is_erased(),
+ _ => false,
+ });
let args = args.iter().cloned().filter(|arg| match arg.unpack() {
GenericArgKind::Lifetime(_) => print_regions,
_ => true,
@@ -1805,8 +1856,12 @@
}
impl<'tcx, F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
- fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> {
- self.0.name_resolver.as_ref().and_then(|func| func(id))
+ fn ty_infer_name(&self, id: ty::TyVid) -> Option<String> {
+ self.0.ty_infer_name_resolver.as_ref().and_then(|func| func(id))
+ }
+
+ fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<String> {
+ self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
}
fn print_value_path(
@@ -2044,7 +2099,7 @@
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let name = &mut self.name;
let region = match *r {
- ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
+ ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)),
ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
@@ -2053,7 +2108,7 @@
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
- self.region_map.entry(br).or_insert_with(|| name(br))
+ *self.region_map.entry(br).or_insert_with(|| name(br))
}
}
}
@@ -2246,7 +2301,6 @@
T: TypeFoldable<'tcx>,
{
struct LateBoundRegionNameCollector<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
used_region_names: &'a mut FxHashSet<Symbol>,
type_collector: SsoHashSet<Ty<'tcx>>,
}
@@ -2254,13 +2308,9 @@
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
type BreakTy = ();
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
#[instrument(skip(self), level = "trace")]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- trace!("address: {:p}", r);
+ trace!("address: {:p}", r.0.0);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
self.used_region_names.insert(name);
} else if let ty::RePlaceholder(ty::PlaceholderRegion {
@@ -2288,7 +2338,6 @@
self.used_region_names.clear();
let mut collector = LateBoundRegionNameCollector {
- tcx: self.tcx,
used_region_names: &mut self.used_region_names,
type_collector: SsoHashSet::new(),
};
@@ -2358,7 +2407,7 @@
}
// HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting.
-impl fmt::Display for ty::RegionKind {
+impl<'tcx> fmt::Display for ty::Region<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ty::tls::with(|tcx| {
self.print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?;
@@ -2407,10 +2456,33 @@
}
}
+#[derive(Copy, Clone, TypeFoldable, Lift)]
+pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);
+
+impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl<'tcx> ty::TraitPredicate<'tcx> {
+ pub fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> {
+ TraitPredPrintModifiersAndPath(self)
+ }
+}
+
+impl<'tcx> ty::PolyTraitPredicate<'tcx> {
+ pub fn print_modifiers_and_trait_path(
+ self,
+ ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
+ self.map_bound(TraitPredPrintModifiersAndPath)
+ }
+}
+
forward_display_to_print! {
Ty<'tcx>,
&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
- &'tcx ty::Const<'tcx>,
+ ty::Const<'tcx>,
// HACK(eddyb) these are exhaustive instead of generic,
// because `for<'tcx>` isn't possible yet.
@@ -2421,6 +2493,7 @@
ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
ty::Binder<'tcx, ty::FnSig<'tcx>>,
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
@@ -2449,8 +2522,8 @@
}
ty::ExistentialProjection<'tcx> {
- let name = cx.tcx().associated_item(self.item_def_id).ident;
- p!(write("{} = ", name), print(self.ty))
+ let name = cx.tcx().associated_item(self.item_def_id).name;
+ p!(write("{} = ", name), print(self.term))
}
ty::ExistentialPredicate<'tcx> {
@@ -2485,6 +2558,18 @@
p!(print_def_path(self.0.def_id, &[]));
}
+ TraitPredPrintModifiersAndPath<'tcx> {
+ if let ty::BoundConstness::ConstIfConst = self.0.constness {
+ p!("~const ")
+ }
+
+ if let ty::ImplPolarity::Negative = self.0.polarity {
+ p!("!")
+ }
+
+ p!(print(self.0.trait_ref.print_only_trait_path()));
+ }
+
ty::ParamTy {
p!(write("{}", self.name))
}
@@ -2502,12 +2587,22 @@
}
ty::TraitPredicate<'tcx> {
- p!(print(self.trait_ref.self_ty()), ": ",
- print(self.trait_ref.print_only_trait_path()))
+ p!(print(self.trait_ref.self_ty()), ": ");
+ if let ty::BoundConstness::ConstIfConst = self.constness {
+ p!("~const ");
+ }
+ p!(print(self.trait_ref.print_only_trait_path()))
}
ty::ProjectionPredicate<'tcx> {
- p!(print(self.projection_ty), " == ", print(self.ty))
+ p!(print(self.projection_ty), " == ", print(self.term))
+ }
+
+ ty::Term<'tcx> {
+ match self {
+ ty::Term::Ty(ty) => p!(print(ty)),
+ ty::Term::Const(c) => p!(print(c)),
+ }
}
ty::ProjectionTy<'tcx> {
@@ -2547,7 +2642,7 @@
write("` implements the trait `{}`", kind))
}
ty::PredicateKind::ConstEvaluatable(uv) => {
- p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated")
+ p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
}
ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
@@ -2602,7 +2697,7 @@
// Iterate external crate defs but be mindful about visibility
while let Some(def) = queue.pop() {
- for child in tcx.item_children(def).iter() {
+ for child in tcx.module_children(def).iter() {
if !child.vis.is_public() {
continue;
}
@@ -2615,7 +2710,9 @@
collect_fn(&child.ident, ns, def_id);
}
- if seen_defs.insert(def_id) {
+ if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait)
+ && seen_defs.insert(def_id)
+ {
queue.push(def_id);
}
}
@@ -2715,5 +2812,5 @@
has_fn_once: bool,
fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
- return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
+ return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
}
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 3af1b3a..1688e59 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -1,7 +1,7 @@
use crate::dep_graph;
-use crate::hir::exports::Export;
use crate::infer::canonical::{self, Canonical};
use crate::lint::LintLevelMap;
+use crate::metadata::ModChild;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use crate::middle::lib_features::LibFeatures;
@@ -56,7 +56,6 @@
use rustc_attr as attr;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
-use std::collections::BTreeMap;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
@@ -107,6 +106,12 @@
#[inline(always)]
fn noop<T>(_: &T) {}
+/// Helper to ensure that queries only return `Copy` types.
+#[inline(always)]
+fn copy<T: Copy>(x: &T) -> T {
+ *x
+}
+
macro_rules! query_helper_param_ty {
(DefId) => { impl IntoQueryParam<DefId> };
($K:ty) => { $K };
@@ -244,7 +249,7 @@
let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
- let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, copy);
let lookup = match cached {
Ok(value) => return value,
@@ -348,6 +353,13 @@
}
}
+ impl<'a, P: Copy> IntoQueryParam<P> for &'a P {
+ #[inline(always)]
+ fn into_query_param(self) -> P {
+ *self
+ }
+ }
+
impl IntoQueryParam<DefId> for LocalDefId {
#[inline(always)]
fn into_query_param(self) -> DefId {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 63ed318..7c57d42 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -7,7 +7,7 @@
use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
use rustc_hir as ast;
use rustc_hir::def_id::DefId;
use rustc_span::DUMMY_SP;
@@ -89,9 +89,9 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>;
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>>;
fn binders<T>(
&mut self,
@@ -149,8 +149,8 @@
Some((ty_def_id, variances)) => {
let variance = variances[i];
let variance_info = if variance == ty::Invariant {
- let ty =
- cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+ let ty = *cached_ty
+ .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
} else {
ty::VarianceDiagInfo::default()
@@ -291,11 +291,11 @@
b.item_def_id,
)))
} else {
- let ty = relation.relate_with_variance(
+ let term = relation.relate_with_variance(
ty::Invariant,
ty::VarianceDiagInfo::default(),
- a.ty,
- b.ty,
+ a.term,
+ b.term,
)?;
let substs = relation.relate_with_variance(
ty::Invariant,
@@ -303,7 +303,7 @@
a.substs,
b.substs,
)?;
- Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
+ Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
}
}
}
@@ -545,16 +545,16 @@
/// it.
pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
-) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+) -> RelateResult<'tcx, ty::Const<'tcx>> {
debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
let tcx = relation.tcx();
// FIXME(oli-obk): once const generics can have generic types, this assertion
// will likely get triggered. Move to `normalize_erasing_regions` at that point.
- let a_ty = tcx.erase_regions(a.ty);
- let b_ty = tcx.erase_regions(b.ty);
+ let a_ty = tcx.erase_regions(a.ty());
+ let b_ty = tcx.erase_regions(b.ty());
if a_ty != b_ty {
relation.tcx().sess.delay_span_bug(
DUMMY_SP,
@@ -562,14 +562,14 @@
);
}
- let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env());
+ let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env());
let a = eagerly_eval(a);
let b = eagerly_eval(b);
// Currently, the values that can be unified are primitive types,
// and those that derive both `PartialEq` and `Eq`, corresponding
// to structural-match types.
- let is_match = match (a.val, b.val) {
+ let is_match = match (a.val(), b.val()) {
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
// The caller should handle these cases!
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
@@ -599,16 +599,16 @@
let substs = relation.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
- au.substs(tcx),
- bu.substs(tcx),
+ au.substs,
+ bu.substs,
)?;
- return Ok(tcx.mk_const(ty::Const {
+ return Ok(tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: au.def,
- substs_: Some(substs),
+ substs,
promoted: au.promoted,
}),
- ty: a.ty,
+ ty: a.ty(),
}));
}
_ => false,
@@ -621,8 +621,8 @@
a_val: ConstValue<'tcx>,
b_val: ConstValue<'tcx>,
// FIXME(oli-obk): these arguments should go away with valtrees
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
// FIXME(oli-obk): this should just be `bool` with valtrees
) -> RelateResult<'tcx, bool> {
let tcx = relation.tcx();
@@ -648,9 +648,9 @@
}
(ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. })
- if a.ty.is_ref() || b.ty.is_ref() =>
+ if a.ty().is_ref() || b.ty().is_ref() =>
{
- if a.ty.is_ref() && b.ty.is_ref() {
+ if a.ty().is_ref() && b.ty().is_ref() {
alloc_a == alloc_b
} else {
false
@@ -663,7 +663,7 @@
// Both the variant and each field have to be equal.
if a_destructured.variant == b_destructured.variant {
for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
- relation.consts(a_field, b_field)?;
+ relation.consts(*a_field, *b_field)?;
}
true
@@ -756,12 +756,12 @@
}
}
-impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> {
+impl<'tcx> Relate<'tcx> for ty::Const<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
relation.consts(a, b)
}
}
@@ -833,6 +833,20 @@
}
}
+impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: Self,
+ b: Self,
+ ) -> RelateResult<'tcx, Self> {
+ Ok(match (a, b) {
+ (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
+ (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+ _ => return Err(TypeError::Mismatch),
+ })
+ }
+}
+
impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
@@ -841,7 +855,7 @@
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
Ok(ty::ProjectionPredicate {
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
- ty: relation.relate(a.ty, b.ty)?,
+ term: relation.relate(a.term, b.term)?,
})
}
}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 98b1a8b..e4691de 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -6,8 +6,9 @@
use crate::mir::ProjectionKind;
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
-use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, 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};
@@ -47,12 +48,6 @@
}
}
-impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "UpvarBorrow({:?}, {:?})", self.kind, self.region)
- }
-}
-
impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths(|| fmt::Display::fmt(self, f))
@@ -164,7 +159,7 @@
impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty)
+ write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
}
}
@@ -191,7 +186,7 @@
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
ty::PredicateKind::ConstEvaluatable(uv) => {
- write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_)
+ write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
}
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@@ -225,7 +220,6 @@
::rustc_hir::def_id::DefId,
::rustc_hir::def_id::LocalDefId,
::rustc_hir::HirId,
- ::rustc_hir::LlvmInlineAsmInner,
::rustc_hir::MatchSource,
::rustc_hir::Mutability,
::rustc_hir::Unsafety,
@@ -260,6 +254,7 @@
crate::ty::UniverseIndex,
crate::ty::Variance,
::rustc_span::Span,
+ ::rustc_errors::ErrorReported,
}
///////////////////////////////////////////////////////////////////////////
@@ -363,6 +358,16 @@
}
}
+impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
+ type Lifted = ty::Term<'tcx>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ Some(match self {
+ Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
+ Term::Const(c) => Term::Const(tcx.lift(c)?),
+ })
+ }
+}
+
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>> {
@@ -410,8 +415,8 @@
impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
type Lifted = ty::ProjectionPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
- tcx.lift((self.projection_ty, self.ty))
- .map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty })
+ tcx.lift((self.projection_ty, self.term))
+ .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
}
}
@@ -420,7 +425,7 @@
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
substs,
- ty: tcx.lift(self.ty).expect("type must lift when substs do"),
+ term: tcx.lift(self.term).expect("type must lift when substs do"),
item_def_id: self.item_def_id,
})
}
@@ -659,14 +664,6 @@
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
-//
-// Ideally, each type should invoke `folder.fold_foo(self)` and
-// nothing else. In some cases, though, we haven't gotten around to
-// adding methods on the `folder` yet, and thus the folding is
-// hard-coded here. This is less-flexible, because folders cannot
-// override the behavior, but there are a lot of random types and one
-// can easily refactor the folding into the TypeFolder trait as
-// needed.
/// AdtDefs are basically the same as a DefId.
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
@@ -1074,7 +1071,7 @@
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- visitor.visit_ty(self)
+ visitor.visit_ty(*self)
}
}
@@ -1108,12 +1105,12 @@
self,
folder: &mut F,
) -> Result<Self, F::Error> {
- let new = self.inner.kind.try_fold_with(folder)?;
+ let new = self.kind().try_fold_with(folder)?;
Ok(folder.tcx().reuse_or_mk_predicate(self, new))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.inner.kind.visit_with(visitor)
+ self.kind().visit_with(visitor)
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1121,11 +1118,11 @@
}
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
- self.inner.outer_exclusive_binder > binder
+ self.outer_exclusive_binder() > binder
}
fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
- self.inner.flags.intersects(flags)
+ self.flags().intersects(flags)
}
}
@@ -1155,15 +1152,15 @@
}
}
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
- let ty = self.ty.try_fold_with(folder)?;
- let val = self.val.try_fold_with(folder)?;
- if ty != self.ty || val != self.val {
- Ok(folder.tcx().mk_const(ty::Const { ty, val }))
+ let ty = self.ty().try_fold_with(folder)?;
+ let val = self.val().try_fold_with(folder)?;
+ if ty != self.ty() || val != self.val() {
+ Ok(folder.tcx().mk_const(ty::ConstS { ty, val }))
} else {
Ok(self)
}
@@ -1174,12 +1171,12 @@
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.ty.visit_with(visitor)?;
- self.val.visit_with(visitor)
+ self.ty().visit_with(visitor)?;
+ self.val().visit_with(visitor)
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- visitor.visit_const(self)
+ visitor.visit_const(*self)
}
}
@@ -1232,7 +1229,7 @@
) -> Result<Self, F::Error> {
Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
+ substs: self.substs.try_fold_with(folder)?,
promoted: self.promoted,
})
}
@@ -1242,14 +1239,7 @@
}
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
- }
+ self.substs.visit_with(visitor)
}
}
@@ -1260,7 +1250,7 @@
) -> Result<Self, F::Error> {
Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
+ substs: self.substs.try_fold_with(folder)?,
promoted: self.promoted,
})
}
@@ -1270,13 +1260,16 @@
}
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
- }
+ self.substs.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
}
}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index c24a1d8..7c6d6ea 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -8,10 +8,13 @@
use crate::ty::fold::ValidateBoundVars;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::InferTy::{self, *};
-use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
-use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
+use crate::ty::{
+ self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor,
+};
+use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
use polonius_engine::Atom;
use rustc_data_structures::captures::Captures;
+use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
@@ -21,8 +24,9 @@
use rustc_target::spec::abi;
use std::borrow::Cow;
use std::cmp::Ordering;
+use std::fmt;
use std::marker::PhantomData;
-use std::ops::Range;
+use std::ops::{ControlFlow, Deref, Range};
use ty::util::IntTypeExt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
@@ -74,10 +78,10 @@
}
}
-/// Defines the kinds of types.
+/// Defines the kinds of types used by the type system.
///
-/// N.B., if you change this, you'll probably want to change the corresponding
-/// AST structure in `rustc_ast/src/ast.rs` as well.
+/// Types written by the user start out as [hir::TyKind](rustc_hir::TyKind) and get
+/// converted to this representation using `AstConv::ast_ty_to_ty`.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
#[derive(HashStable)]
#[rustc_diagnostic_item = "TyKind"]
@@ -100,10 +104,11 @@
/// Algebraic data types (ADT). For example: structures, enumerations and unions.
///
- /// InternalSubsts here, possibly against intuition, *may* contain `Param`s.
- /// That is, even after substitution it is possible that there are type
- /// variables. This happens when the `Adt` corresponds to an ADT
- /// definition and not a concrete use of it.
+ /// For example, the type `List<i32>` would be represented using the `AdtDef`
+ /// for `struct List<T>` and the substs `[i32]`.
+ ///
+ /// Note that generic parameters in fields only get lazily substituted
+ /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
Adt(&'tcx AdtDef, SubstsRef<'tcx>),
/// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
@@ -112,8 +117,8 @@
/// The pointee of a string slice. Written as `str`.
Str,
- /// An array with the given length. Written as `[T; n]`.
- Array(Ty<'tcx>, &'tcx ty::Const<'tcx>),
+ /// An array with the given length. Written as `[T; N]`.
+ Array(Ty<'tcx>, ty::Const<'tcx>),
/// The pointee of an array slice. Written as `[T]`.
Slice(Ty<'tcx>),
@@ -126,11 +131,12 @@
Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
/// The anonymous type of a function declaration/definition. Each
- /// function has a unique type, which is output (for a function
- /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
+ /// function has a unique type.
+ ///
+ /// For the function `fn foo() -> i32 { 3 }` this type would be
+ /// shown to the user as `fn() -> i32 {foo}`.
///
/// For example the type of `bar` here:
- ///
/// ```rust
/// fn foo() -> i32 { 1 }
/// let bar = foo; // bar: fn() -> i32 {foo}
@@ -139,6 +145,9 @@
/// A pointer to a function. Written as `fn() -> i32`.
///
+ /// Note that both functions and closures start out as either
+ /// [FnDef] or [Closure] which can be then be coerced to this variant.
+ ///
/// For example the type of `bar` here:
///
/// ```rust
@@ -150,23 +159,48 @@
/// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
- /// The anonymous type of a closure. Used to represent the type of
- /// `|a| a`.
+ /// The anonymous type of a closure. Used to represent the type of `|a| a`.
+ ///
+ /// Closure substs contain both the - potentially substituted - generic parameters
+ /// of its parent and some synthetic parameters. See the documentation for
+ /// [ClosureSubsts] for more details.
Closure(DefId, SubstsRef<'tcx>),
/// The anonymous type of a generator. Used to represent the type of
/// `|a| yield a`.
+ ///
+ /// For more info about generator substs, visit the documentation for
+ /// [GeneratorSubsts].
Generator(DefId, SubstsRef<'tcx>, hir::Movability),
/// A type representing the types stored inside a generator.
- /// This should only appear in GeneratorInteriors.
+ /// This should only appear as part of the [GeneratorSubsts].
+ ///
+ /// Note that the captured variables for generators are stored separately
+ /// using a tuple in the same way as for closures.
+ ///
+ /// Unlike upvars, the witness can reference lifetimes from
+ /// inside of the generator itself. To deal with them in
+ /// the type of the generator, we convert them to higher ranked
+ /// lifetimes bound by the witness itself.
+ ///
+ /// Looking at the following example, the witness for this generator
+ /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+ ///
+ /// ```rust
+ /// |a| {
+ /// let x = &vec![3];
+ /// yield a;
+ /// yield x[0];
+ /// }
+ /// ```
GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>),
/// The never type `!`.
Never,
/// A tuple type. For example, `(i32, bool)`.
- /// Use `TyS::tuple_fields` to iterate over the field types.
+ /// Use `Ty::tuple_fields` to iterate over the field types.
Tuple(SubstsRef<'tcx>),
/// The projection of an associated type. For example,
@@ -174,23 +208,44 @@
Projection(ProjectionTy<'tcx>),
/// Opaque (`impl Trait`) type found in a return type.
+ ///
/// The `DefId` comes either from
/// * the `impl Trait` ast::Ty node,
/// * or the `type Foo = impl Trait` declaration
- /// The substitutions are for the generics of the function in question.
- /// After typeck, the concrete type can be found in the `types` map.
+ ///
+ /// For RPIT the substitutions are for the generics of the function,
+ /// while for TAIT it is used for the generic parameters of the alias.
+ ///
+ /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
Opaque(DefId, SubstsRef<'tcx>),
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
Param(ParamTy),
- /// Bound type variable, used only when preparing a trait query.
+ /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
+ ///
+ /// For canonical queries, we replace inference variables with bound variables,
+ /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
+ /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
+ /// back to inference variables in a new inference context when inside of the query.
+ ///
+ /// See the `rustc-dev-guide` for more details about
+ /// [higher-ranked trait bounds][1] and [canonical queries][2].
+ ///
+ /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+ /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
Bound(ty::DebruijnIndex, BoundTy),
- /// A placeholder type - universally quantified higher-ranked type.
+ /// A placeholder type, used during higher ranked subtyping to instantiate
+ /// bound variables.
Placeholder(ty::PlaceholderType),
/// A type variable used during type checking.
+ ///
+ /// Similar to placeholders, inference variables also live in a universe to
+ /// correctly deal with higher ranked types. Though unlike placeholders,
+ /// that universe is stored in the `InferCtxt` instead of directly
+ /// inside of the type.
Infer(InferTy),
/// A placeholder for a type which could not be computed; this is
@@ -231,7 +286,7 @@
/// in scope on the function that defined the closure,
/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
/// is rather hackily encoded via a scalar type. See
-/// `TyS::to_opt_closure_kind` for details.
+/// `Ty::to_opt_closure_kind` for details.
/// - CS represents the *closure signature*, representing as a `fn()`
/// type. For example, `fn(u32, u32) -> u32` would mean that the closure
/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
@@ -1340,7 +1395,24 @@
}
}
-pub type Region<'tcx> = &'tcx RegionKind;
+/// Use this rather than `TyKind`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>);
+
+impl<'tcx> Deref for Region<'tcx> {
+ type Target = RegionKind;
+
+ fn deref(&self) -> &RegionKind {
+ &self.0.0
+ }
+}
+
+impl<'tcx> fmt::Debug for Region<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.kind())
+ }
+}
/// Representation of regions. Note that the NLL checker uses a distinct
/// representation of regions. For this reason, it internally replaces all the
@@ -1348,6 +1420,9 @@
/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
/// module for more information.
///
+/// Note: operations are on the wrapper `Region` type, which is interned,
+/// rather than this type.
+///
/// ## The Region lattice within a given function
///
/// In general, the region lattice looks like
@@ -1464,11 +1539,11 @@
/// Static data that has an "infinite" lifetime. Top in the region lattice.
ReStatic,
- /// A region variable. Should not exist after typeck.
+ /// A region variable. Should not exist outside of type inference.
ReVar(RegionVid),
/// A placeholder region -- basically, the higher-ranked version of `ReFree`.
- /// Should not exist after typeck.
+ /// Should not exist outside of type inference.
RePlaceholder(ty::PlaceholderRegion),
/// Empty lifetime is for data that is never accessed. We tag the
@@ -1540,7 +1615,7 @@
pub struct ExistentialProjection<'tcx> {
pub item_def_id: DefId,
pub substs: SubstsRef<'tcx>,
- pub ty: Ty<'tcx>,
+ pub term: Term<'tcx>,
}
pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
@@ -1570,7 +1645,7 @@
item_def_id: self.item_def_id,
substs: tcx.mk_substs_trait(self_ty, self.substs),
},
- ty: self.ty,
+ term: self.term,
}
}
@@ -1584,7 +1659,7 @@
Self {
item_def_id: projection_predicate.projection_ty.item_def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
- ty: projection_predicate.ty,
+ term: projection_predicate.term,
}
}
}
@@ -1604,64 +1679,83 @@
}
/// Region utilities
-impl RegionKind {
+impl<'tcx> Region<'tcx> {
+ pub fn kind(self) -> RegionKind {
+ *self.0.0
+ }
+
/// Is this region named by the user?
- pub fn has_name(&self) -> bool {
+ pub fn has_name(self) -> bool {
match *self {
- RegionKind::ReEarlyBound(ebr) => ebr.has_name(),
- RegionKind::ReLateBound(_, br) => br.kind.is_named(),
- RegionKind::ReFree(fr) => fr.bound_region.is_named(),
- RegionKind::ReStatic => true,
- RegionKind::ReVar(..) => false,
- RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
- RegionKind::ReEmpty(_) => false,
- RegionKind::ReErased => false,
+ ty::ReEarlyBound(ebr) => ebr.has_name(),
+ ty::ReLateBound(_, br) => br.kind.is_named(),
+ ty::ReFree(fr) => fr.bound_region.is_named(),
+ ty::ReStatic => true,
+ ty::ReVar(..) => false,
+ ty::RePlaceholder(placeholder) => placeholder.name.is_named(),
+ ty::ReEmpty(_) => false,
+ ty::ReErased => false,
}
}
#[inline]
- pub fn is_late_bound(&self) -> bool {
+ pub fn is_static(self) -> bool {
+ matches!(*self, ty::ReStatic)
+ }
+
+ #[inline]
+ pub fn is_erased(self) -> bool {
+ matches!(*self, ty::ReErased)
+ }
+
+ #[inline]
+ pub fn is_late_bound(self) -> bool {
matches!(*self, ty::ReLateBound(..))
}
#[inline]
- pub fn is_placeholder(&self) -> bool {
+ pub fn is_placeholder(self) -> bool {
matches!(*self, ty::RePlaceholder(..))
}
#[inline]
- pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
+ pub fn is_empty(self) -> bool {
+ matches!(*self, ty::ReEmpty(..))
+ }
+
+ #[inline]
+ pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
match *self {
ty::ReLateBound(debruijn, _) => debruijn >= index,
_ => false,
}
}
- pub fn type_flags(&self) -> TypeFlags {
+ pub fn type_flags(self) -> TypeFlags {
let mut flags = TypeFlags::empty();
match *self {
ty::ReVar(..) => {
- flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER;
}
ty::RePlaceholder(..) => {
- flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
}
ty::ReEarlyBound(..) => {
- flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
- flags = flags | TypeFlags::HAS_KNOWN_RE_PARAM;
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_RE_PARAM;
}
ty::ReFree { .. } => {
- flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
}
ty::ReEmpty(_) | ty::ReStatic => {
- flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
ty::ReLateBound(..) => {
flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
@@ -1695,8 +1789,8 @@
/// of the impl, and for all the other highlighted regions, it
/// would return the `DefId` of the function. In other cases (not shown), this
/// function might return the `DefId` of a closure.
- pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId {
- match self {
+ pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
+ match *self {
ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
ty::ReFree(fr) => fr.scope,
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
@@ -1705,19 +1799,19 @@
}
/// Type utilities
-impl<'tcx> TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
#[inline(always)]
- pub fn kind(&self) -> &TyKind<'tcx> {
- &self.kind
+ pub fn kind(self) -> &'tcx TyKind<'tcx> {
+ &self.0.0.kind
}
#[inline(always)]
- pub fn flags(&self) -> TypeFlags {
- self.flags
+ pub fn flags(self) -> TypeFlags {
+ self.0.0.flags
}
#[inline]
- pub fn is_unit(&self) -> bool {
+ pub fn is_unit(self) -> bool {
match self.kind() {
Tuple(ref tys) => tys.is_empty(),
_ => false,
@@ -1725,32 +1819,32 @@
}
#[inline]
- pub fn is_never(&self) -> bool {
+ pub fn is_never(self) -> bool {
matches!(self.kind(), Never)
}
#[inline]
- pub fn is_primitive(&self) -> bool {
+ pub fn is_primitive(self) -> bool {
self.kind().is_primitive()
}
#[inline]
- pub fn is_adt(&self) -> bool {
+ pub fn is_adt(self) -> bool {
matches!(self.kind(), Adt(..))
}
#[inline]
- pub fn is_ref(&self) -> bool {
+ pub fn is_ref(self) -> bool {
matches!(self.kind(), Ref(..))
}
#[inline]
- pub fn is_ty_var(&self) -> bool {
+ pub fn is_ty_var(self) -> bool {
matches!(self.kind(), Infer(TyVar(_)))
}
#[inline]
- pub fn ty_vid(&self) -> Option<ty::TyVid> {
+ pub fn ty_vid(self) -> Option<ty::TyVid> {
match self.kind() {
&Infer(TyVar(vid)) => Some(vid),
_ => None,
@@ -1758,28 +1852,28 @@
}
#[inline]
- pub fn is_ty_infer(&self) -> bool {
+ pub fn is_ty_infer(self) -> bool {
matches!(self.kind(), Infer(_))
}
#[inline]
- pub fn is_phantom_data(&self) -> bool {
+ pub fn is_phantom_data(self) -> bool {
if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false }
}
#[inline]
- pub fn is_bool(&self) -> bool {
+ pub fn is_bool(self) -> bool {
*self.kind() == Bool
}
/// Returns `true` if this type is a `str`.
#[inline]
- pub fn is_str(&self) -> bool {
+ pub fn is_str(self) -> bool {
*self.kind() == Str
}
#[inline]
- pub fn is_param(&self, index: u32) -> bool {
+ pub fn is_param(self, index: u32) -> bool {
match self.kind() {
ty::Param(ref data) => data.index == index,
_ => false,
@@ -1787,7 +1881,7 @@
}
#[inline]
- pub fn is_slice(&self) -> bool {
+ pub fn is_slice(self) -> bool {
match self.kind() {
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str),
_ => false,
@@ -1795,27 +1889,27 @@
}
#[inline]
- pub fn is_array(&self) -> bool {
+ pub fn is_array(self) -> bool {
matches!(self.kind(), Array(..))
}
#[inline]
- pub fn is_simd(&self) -> bool {
+ pub fn is_simd(self) -> bool {
match self.kind() {
Adt(def, _) => def.repr.simd(),
_ => false,
}
}
- pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind() {
- Array(ty, _) | Slice(ty) => ty,
- Str => tcx.mk_mach_uint(ty::UintTy::U8),
+ Array(ty, _) | Slice(ty) => *ty,
+ Str => tcx.types.u8,
_ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
}
}
- pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
+ pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
match self.kind() {
Adt(def, substs) => {
assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type");
@@ -1830,7 +1924,7 @@
// The way we evaluate the `N` in `[T; N]` here only works since we use
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
// if we use it in generic code. See the `simd-array-trait` ui test.
- (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty)
+ (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty)
}
// Otherwise, the fields of this Adt are the SIMD components (and we assume they
// all have the same type).
@@ -1842,12 +1936,12 @@
}
#[inline]
- pub fn is_region_ptr(&self) -> bool {
+ pub fn is_region_ptr(self) -> bool {
matches!(self.kind(), Ref(..))
}
#[inline]
- pub fn is_mutable_ptr(&self) -> bool {
+ pub fn is_mutable_ptr(self) -> bool {
matches!(
self.kind(),
RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
@@ -1857,7 +1951,7 @@
/// Get the mutability of the reference or `None` when not a reference
#[inline]
- pub fn ref_mutability(&self) -> Option<hir::Mutability> {
+ pub fn ref_mutability(self) -> Option<hir::Mutability> {
match self.kind() {
Ref(_, _, mutability) => Some(*mutability),
_ => None,
@@ -1865,18 +1959,18 @@
}
#[inline]
- pub fn is_unsafe_ptr(&self) -> bool {
+ pub fn is_unsafe_ptr(self) -> bool {
matches!(self.kind(), RawPtr(_))
}
/// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
#[inline]
- pub fn is_any_ptr(&self) -> bool {
+ pub fn is_any_ptr(self) -> bool {
self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr()
}
#[inline]
- pub fn is_box(&self) -> bool {
+ pub fn is_box(self) -> bool {
match self.kind() {
Adt(def, _) => def.is_box(),
_ => false,
@@ -1884,7 +1978,7 @@
}
/// Panics if called on any type other than `Box<T>`.
- pub fn boxed_ty(&self) -> Ty<'tcx> {
+ pub fn boxed_ty(self) -> Ty<'tcx> {
match self.kind() {
Adt(def, substs) if def.is_box() => substs.type_at(0),
_ => bug!("`boxed_ty` is called on non-box type {:?}", self),
@@ -1895,7 +1989,7 @@
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
/// contents are abstract to rustc.)
#[inline]
- pub fn is_scalar(&self) -> bool {
+ pub fn is_scalar(self) -> bool {
matches!(
self.kind(),
Bool | Char
@@ -1911,99 +2005,117 @@
/// Returns `true` if this type is a floating point type.
#[inline]
- pub fn is_floating_point(&self) -> bool {
+ pub fn is_floating_point(self) -> bool {
matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
}
#[inline]
- pub fn is_trait(&self) -> bool {
+ pub fn is_trait(self) -> bool {
matches!(self.kind(), Dynamic(..))
}
#[inline]
- pub fn is_enum(&self) -> bool {
+ pub fn is_enum(self) -> bool {
matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
}
#[inline]
- pub fn is_union(&self) -> bool {
+ pub fn is_union(self) -> bool {
matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
}
#[inline]
- pub fn is_closure(&self) -> bool {
+ pub fn is_closure(self) -> bool {
matches!(self.kind(), Closure(..))
}
#[inline]
- pub fn is_generator(&self) -> bool {
+ pub fn is_generator(self) -> bool {
matches!(self.kind(), Generator(..))
}
#[inline]
- pub fn is_integral(&self) -> bool {
+ pub fn is_integral(self) -> bool {
matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
}
#[inline]
- pub fn is_fresh_ty(&self) -> bool {
+ pub fn is_fresh_ty(self) -> bool {
matches!(self.kind(), Infer(FreshTy(_)))
}
#[inline]
- pub fn is_fresh(&self) -> bool {
+ pub fn is_fresh(self) -> bool {
matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
}
#[inline]
- pub fn is_char(&self) -> bool {
+ pub fn is_char(self) -> bool {
matches!(self.kind(), Char)
}
#[inline]
- pub fn is_numeric(&self) -> bool {
+ pub fn is_numeric(self) -> bool {
self.is_integral() || self.is_floating_point()
}
#[inline]
- pub fn is_signed(&self) -> bool {
+ pub fn is_signed(self) -> bool {
matches!(self.kind(), Int(_))
}
#[inline]
- pub fn is_ptr_sized_integral(&self) -> bool {
+ pub fn is_ptr_sized_integral(self) -> bool {
matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
}
#[inline]
- pub fn has_concrete_skeleton(&self) -> bool {
+ pub fn has_concrete_skeleton(self) -> bool {
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
}
+ /// Checks whether a type recursively contains another type
+ ///
+ /// Example: `Option<()>` contains `()`
+ pub fn contains(self, other: Ty<'tcx>) -> bool {
+ struct ContainsTyVisitor<'tcx>(Ty<'tcx>);
+
+ impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) }
+ }
+ }
+
+ let cf = self.visit_with(&mut ContainsTyVisitor(other));
+ cf.is_break()
+ }
+
/// Returns the type and mutability of `*ty`.
///
/// The parameter `explicit` indicates if this is an *explicit* dereference.
/// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
- pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
+ pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
match self.kind() {
Adt(def, _) if def.is_box() => {
Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not })
}
- Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }),
+ Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
RawPtr(mt) if explicit => Some(*mt),
_ => None,
}
}
/// Returns the type of `ty[i]`.
- pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
+ pub fn builtin_index(self) -> Option<Ty<'tcx>> {
match self.kind() {
- Array(ty, _) | Slice(ty) => Some(ty),
+ Array(ty, _) | Slice(ty) => Some(*ty),
_ => None,
}
}
- pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
+ pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
match self.kind() {
FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs),
FnPtr(f) => *f,
@@ -2019,22 +2131,22 @@
}
#[inline]
- pub fn is_fn(&self) -> bool {
+ pub fn is_fn(self) -> bool {
matches!(self.kind(), FnDef(..) | FnPtr(_))
}
#[inline]
- pub fn is_fn_ptr(&self) -> bool {
+ pub fn is_fn_ptr(self) -> bool {
matches!(self.kind(), FnPtr(_))
}
#[inline]
- pub fn is_impl_trait(&self) -> bool {
+ pub fn is_impl_trait(self) -> bool {
matches!(self.kind(), Opaque(..))
}
#[inline]
- pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> {
+ pub fn ty_adt_def(self) -> Option<&'tcx AdtDef> {
match self.kind() {
Adt(adt, _) => Some(adt),
_ => None,
@@ -2043,7 +2155,7 @@
/// Iterates over tuple fields.
/// Panics when called on anything but a tuple.
- pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
+ pub fn tuple_fields(self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
match self.kind() {
Tuple(substs) => substs.iter().map(|field| field.expect_ty()),
_ => bug!("tuple_fields called on non-tuple"),
@@ -2052,7 +2164,7 @@
/// Get the `i`-th element of a tuple.
/// Panics when called on anything but a tuple.
- pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> {
+ pub fn tuple_element_ty(self, i: usize) -> Option<Ty<'tcx>> {
match self.kind() {
Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()),
_ => bug!("tuple_fields called on non-tuple"),
@@ -2063,7 +2175,7 @@
//
// FIXME: This requires the optimized MIR in the case of generators.
#[inline]
- pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
+ pub fn variant_range(self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
match self.kind() {
TyKind::Adt(adt, _) => Some(adt.variant_range()),
TyKind::Generator(def_id, substs, _) => {
@@ -2079,7 +2191,7 @@
// FIXME: This requires the optimized MIR in the case of generators.
#[inline]
pub fn discriminant_for_variant(
- &self,
+ self,
tcx: TyCtxt<'tcx>,
variant_index: VariantIdx,
) -> Option<Discr<'tcx>> {
@@ -2100,7 +2212,7 @@
}
/// Returns the type of the discriminant of this type.
- pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind() {
ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
@@ -2143,9 +2255,12 @@
}
/// Returns the type of metadata for (potentially fat) pointers to this type.
- pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
- // FIXME: should this normalize?
- let tail = tcx.struct_tail_without_normalization(self);
+ pub fn ptr_metadata_ty(
+ self,
+ tcx: TyCtxt<'tcx>,
+ normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ ) -> Ty<'tcx> {
+ let tail = tcx.struct_tail_with_normalize(self, normalize);
match tail.kind() {
// Sized types
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -2202,7 +2317,7 @@
/// to represent the closure kind, because it has not yet been
/// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`)
/// is complete, that type variable will be unified.
- pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
+ pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
match self.kind() {
Int(int_ty) => match int_ty {
ty::IntTy::I8 => Some(ty::ClosureKind::Fn),
@@ -2231,7 +2346,7 @@
/// bound such as `[_]: Copy`. A function with such a bound obviously never
/// can be called, but that doesn't mean it shouldn't typecheck. This is why
/// this method doesn't return `Option<bool>`.
- pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
+ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Uint(_)
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index a711811..7dccef5 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -6,6 +6,7 @@
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
+use rustc_data_structures::intern::Interned;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_serialize::{self, Decodable, Encodable};
@@ -25,10 +26,13 @@
/// 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.
+///
+/// Note: the `PartialEq`, `Eq` and `Hash` derives are only valid because `Ty`,
+/// `Region` and `Const` are all interned.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct GenericArg<'tcx> {
ptr: NonZeroUsize,
- marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::Const<'tcx>)>,
+ marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
}
const TAG_MASK: usize = 0b11;
@@ -40,26 +44,27 @@
pub enum GenericArgKind<'tcx> {
Lifetime(ty::Region<'tcx>),
Type(Ty<'tcx>),
- Const(&'tcx ty::Const<'tcx>),
+ Const(ty::Const<'tcx>),
}
impl<'tcx> GenericArgKind<'tcx> {
+ #[inline]
fn pack(self) -> GenericArg<'tcx> {
let (tag, ptr) = match self {
GenericArgKind::Lifetime(lt) => {
// Ensure we can use the tag bits.
- assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0);
- (REGION_TAG, lt as *const _ as usize)
+ assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0);
+ (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize)
}
GenericArgKind::Type(ty) => {
// Ensure we can use the tag bits.
- assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
- (TYPE_TAG, ty as *const _ as usize)
+ assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0);
+ (TYPE_TAG, ty.0.0 as *const ty::TyS<'tcx> as usize)
}
GenericArgKind::Const(ct) => {
// Ensure we can use the tag bits.
- assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0);
- (CONST_TAG, ct as *const _ as usize)
+ assert_eq!(mem::align_of_val(ct.0.0) & TAG_MASK, 0);
+ (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
}
};
@@ -90,19 +95,22 @@
}
impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> {
+ #[inline]
fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> {
GenericArgKind::Lifetime(r).pack()
}
}
impl<'tcx> From<Ty<'tcx>> for GenericArg<'tcx> {
+ #[inline]
fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> {
GenericArgKind::Type(ty).pack()
}
}
-impl<'tcx> From<&'tcx ty::Const<'tcx>> for GenericArg<'tcx> {
- fn from(c: &'tcx ty::Const<'tcx>) -> GenericArg<'tcx> {
+impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> {
+ #[inline]
+ fn from(c: ty::Const<'tcx>) -> GenericArg<'tcx> {
GenericArgKind::Const(c).pack()
}
}
@@ -111,11 +119,20 @@
#[inline]
pub fn unpack(self) -> GenericArgKind<'tcx> {
let ptr = self.ptr.get();
+ // SAFETY: use of `Interned::new_unchecked` here is ok because these
+ // pointers were originally created from `Interned` types in `pack()`,
+ // and this is just going in the other direction.
unsafe {
match ptr & TAG_MASK {
- REGION_TAG => GenericArgKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
- TYPE_TAG => GenericArgKind::Type(&*((ptr & !TAG_MASK) as *const _)),
- CONST_TAG => GenericArgKind::Const(&*((ptr & !TAG_MASK) as *const _)),
+ REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const ty::RegionKind),
+ ))),
+ TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const ty::TyS<'tcx>),
+ ))),
+ CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+ ))),
_ => intrinsics::unreachable(),
}
}
@@ -132,7 +149,7 @@
}
/// Unpack the `GenericArg` as a const when it is known certainly to be a const.
- pub fn expect_const(self) -> &'tcx ty::Const<'tcx> {
+ pub fn expect_const(self) -> ty::Const<'tcx> {
match self.unpack() {
GenericArgKind::Const(c) => c,
_ => bug!("expected a const, but found another kind"),
@@ -180,8 +197,8 @@
}
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> {
- fn decode(d: &mut D) -> Result<GenericArg<'tcx>, D::Error> {
- Ok(GenericArgKind::decode(d)?.pack())
+ fn decode(d: &mut D) -> GenericArg<'tcx> {
+ GenericArgKind::decode(d).pack()
}
}
@@ -275,10 +292,6 @@
}
}
- pub fn is_noop(&self) -> bool {
- self.is_empty()
- }
-
#[inline]
pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
self.iter()
@@ -293,7 +306,7 @@
}
#[inline]
- pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::Const<'tcx>> + 'a {
+ pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'a {
self.iter().filter_map(|k| {
if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None }
})
@@ -328,7 +341,7 @@
}
#[inline]
- pub fn const_at(&self, i: usize) -> &'tcx ty::Const<'tcx> {
+ pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
if let GenericArgKind::Const(ct) = self[i].unpack() {
ct
} else {
@@ -400,15 +413,7 @@
}
}
0 => Ok(self),
- _ => {
- let params: SmallVec<[_; 8]> =
- self.iter().map(|k| k.try_fold_with(folder)).collect::<Result<_, _>>()?;
- if params[..] == self[..] {
- Ok(self)
- } else {
- Ok(folder.tcx().intern_substs(¶ms))
- }
- }
+ _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_substs(v)),
}
}
@@ -505,7 +510,7 @@
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.potentially_needs_subst() {
+ if !t.needs_subst() {
return t;
}
@@ -515,8 +520,8 @@
}
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ty::ConstKind::Param(p) = c.val {
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Param(p) = c.val() {
self.const_for_param(p, c)
} else {
c.super_fold_with(self)
@@ -565,11 +570,7 @@
self.shift_vars_through_binders(ty)
}
- fn const_for_param(
- &self,
- p: ParamConst,
- source_ct: &'tcx ty::Const<'tcx>,
- ) -> &'tcx ty::Const<'tcx> {
+ fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
// Look up the const in the substitutions. It really should be in there.
let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack());
let ct = match opt_ct {
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 34d059f..8f4cc18 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,7 +1,7 @@
use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
use crate::ty::fold::TypeFoldable;
-use crate::ty::{Ty, TyCtxt};
+use crate::ty::{Ident, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::definitions::DefPathHash;
@@ -44,6 +44,10 @@
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
/// recomputed all the time.
pub def_path_hash: DefPathHash,
+
+ /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which
+ /// must be implemented.
+ pub must_implement_one_of: Option<Box<[Ident]>>,
}
/// Whether this trait is treated specially by the standard library
@@ -87,6 +91,7 @@
skip_array_during_method_dispatch: bool,
specialization_kind: TraitSpecializationKind,
def_path_hash: DefPathHash,
+ must_implement_one_of: Option<Box<[Ident]>>,
) -> TraitDef {
TraitDef {
def_id,
@@ -97,6 +102,7 @@
skip_array_during_method_dispatch,
specialization_kind,
def_path_hash,
+ must_implement_one_of,
}
}
@@ -138,6 +144,21 @@
});
}
+ pub fn non_blanket_impls_for_ty(
+ self,
+ def_id: DefId,
+ self_ty: Ty<'tcx>,
+ ) -> impl Iterator<Item = DefId> + 'tcx {
+ let impls = self.trait_impls_of(def_id);
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::No) {
+ if let Some(impls) = impls.non_blanket_impls.get(&simp) {
+ return impls.iter().copied();
+ }
+ }
+
+ [].iter().copied()
+ }
+
/// Applies function to every impl that could possibly match the self type `self_ty` and returns
/// the first non-none value.
pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
@@ -166,9 +187,7 @@
// whose outer level is not a parameter or projection. Especially for things like
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
- if let Some(simp) =
- fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No)
- {
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes) {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls {
if let result @ Some(_) = f(impl_def_id) {
@@ -191,7 +210,7 @@
pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
- blanket_impls.iter().chain(non_blanket_impls.iter().map(|(_, v)| v).flatten()).cloned()
+ blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned()
}
}
@@ -228,7 +247,7 @@
}
if let Some(simplified_self_ty) =
- fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No, StripReferences::No)
+ fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No)
{
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
} else {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 6690655..92d9cb2 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -5,16 +5,19 @@
use crate::ty::layout::IntegerExt;
use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
-use crate::ty::TyKind::*;
-use crate::ty::{self, DebruijnIndex, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{
+ self, Const, DebruijnIndex, DefIdTree, List, ReEarlyBound, Region, Ty, TyCtxt, TyKind::*,
+ TypeFoldable,
+};
use rustc_apfloat::Float as _;
use rustc_ast as ast;
use rustc_attr::{self as attr, SignedInt, UnsignedInt};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_query_system::ich::NodeIdHashingMode;
@@ -143,6 +146,37 @@
hasher.finish()
}
+ pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
+ match res {
+ Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {
+ Some(self.parent(def_id).and_then(|def_id| self.parent(def_id)).unwrap())
+ }
+ Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
+ Some(self.parent(def_id).unwrap())
+ }
+ // Other `DefKind`s don't have generics and would ICE when calling
+ // `generics_of`.
+ Res::Def(
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Trait
+ | DefKind::OpaqueTy
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::TraitAlias
+ | DefKind::AssocTy
+ | DefKind::Fn
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::Impl,
+ def_id,
+ ) => Some(def_id),
+ Res::Err => None,
+ _ => None,
+ }
+ }
+
pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
if let ty::Adt(def, substs) = *ty.kind() {
for field in def.all_fields() {
@@ -192,7 +226,7 @@
pub fn struct_tail_with_normalize(
self,
mut ty: Ty<'tcx>,
- normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>,
+ mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Ty<'tcx> {
let recursion_limit = self.recursion_limit();
for iteration in 0.. {
@@ -389,15 +423,17 @@
let result = iter::zip(item_substs, impl_substs)
.filter(|&(_, k)| {
match k.unpack() {
- GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => {
+ GenericArgKind::Lifetime(Region(Interned(ReEarlyBound(ref ebr), _))) => {
!impl_generics.region_param(ebr, self).pure_wrt_drop
}
- GenericArgKind::Type(&ty::TyS { kind: ty::Param(ref pt), .. }) => {
- !impl_generics.type_param(pt, self).pure_wrt_drop
- }
- GenericArgKind::Const(&ty::Const {
- val: ty::ConstKind::Param(ref pc), ..
- }) => !impl_generics.const_param(pc, self).pure_wrt_drop,
+ GenericArgKind::Type(Ty(Interned(
+ ty::TyS { kind: ty::Param(ref pt), .. },
+ _,
+ ))) => !impl_generics.type_param(pt, self).pure_wrt_drop,
+ GenericArgKind::Const(Const(Interned(
+ ty::ConstS { val: ty::ConstKind::Param(ref pc), .. },
+ _,
+ ))) => !impl_generics.const_param(pc, self).pure_wrt_drop,
GenericArgKind::Lifetime(_)
| GenericArgKind::Type(_)
| GenericArgKind::Const(_) => {
@@ -577,7 +613,7 @@
let substs = substs.fold_with(self);
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
- Some(expanded_ty) => expanded_ty,
+ Some(expanded_ty) => *expanded_ty,
None => {
let generic_ty = self.tcx.type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx, substs);
@@ -606,7 +642,7 @@
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Opaque(def_id, substs) = t.kind {
+ if let ty::Opaque(def_id, substs) = *t.kind() {
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
} else if t.has_opaque_types() {
t.super_fold_with(self)
@@ -616,10 +652,10 @@
}
}
-impl<'tcx> ty::TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
/// Returns the maximum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
- pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
+ pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
let val = match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
@@ -634,12 +670,12 @@
}),
_ => None,
};
- val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+ val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
/// Returns the minimum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
- pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
+ pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
let val = match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
@@ -653,7 +689,7 @@
}),
_ => None,
};
- val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+ val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
/// Checks whether values of this type `T` are *moved* or *copied*
@@ -664,7 +700,7 @@
/// full requirements for the `Copy` trait (cc #29149) -- this
/// winds up being reported as an error during NLL borrow check.
pub fn is_copy_modulo_regions(
- &'tcx self,
+ self,
tcx_at: TyCtxtAt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
@@ -677,7 +713,7 @@
/// over-approximation in generic contexts, where one can have
/// strange rules like `<T as Foo<'static>>::Bar: Sized` that
/// actually carry lifetime requirements.
- pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self))
}
@@ -688,7 +724,7 @@
/// optimization as well as the rules around static values. Note
/// that the `Freeze` trait is not exposed to end users and is
/// effectively an implementation detail.
- pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
}
@@ -696,7 +732,7 @@
///
/// Returning true means the type is known to be `Freeze`. Returning
/// `false` means nothing -- could be `Freeze`, might not be.
- fn is_trivially_freeze(&self) -> bool {
+ fn is_trivially_freeze(self) -> bool {
match self.kind() {
ty::Int(_)
| ty::Uint(_)
@@ -710,7 +746,7 @@
| ty::FnDef(..)
| ty::Error(_)
| ty::FnPtr(_) => true,
- ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze),
+ ty::Tuple(_) => self.tuple_fields().all(|f| Self::is_trivially_freeze(f)),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
ty::Adt(..)
| ty::Bound(..)
@@ -728,7 +764,7 @@
}
/// Checks whether values of this type `T` implement the `Unpin` trait.
- pub fn is_unpin(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
}
@@ -736,7 +772,7 @@
///
/// Returning true means the type is known to be `Unpin`. Returning
/// `false` means nothing -- could be `Unpin`, might not be.
- fn is_trivially_unpin(&self) -> bool {
+ fn is_trivially_unpin(self) -> bool {
match self.kind() {
ty::Int(_)
| ty::Uint(_)
@@ -750,7 +786,7 @@
| ty::FnDef(..)
| ty::Error(_)
| ty::FnPtr(_) => true,
- ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_unpin),
+ ty::Tuple(_) => self.tuple_fields().all(|f| Self::is_trivially_unpin(f)),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
ty::Adt(..)
| ty::Bound(..)
@@ -776,7 +812,7 @@
///
/// Note that this method is used to check eligible types in unions.
#[inline]
- pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ pub fn needs_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
// Avoid querying in simple cases.
match needs_drop_components(self, &tcx.data_layout) {
Err(AlwaysRequiresDrop) => true,
@@ -809,11 +845,7 @@
/// Note that this method is used to check for change in drop order for
/// 2229 drop reorder migration analysis.
#[inline]
- pub fn has_significant_drop(
- &'tcx self,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> bool {
+ pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
// Avoid querying in simple cases.
match needs_drop_components(self, &tcx.data_layout) {
Err(AlwaysRequiresDrop) => true,
@@ -858,7 +890,7 @@
/// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way
/// down, you will need to use a type visitor.
#[inline]
- pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool {
+ pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
// Look for an impl of both `PartialStructuralEq` and `StructuralEq`.
Adt(..) => tcx.has_structural_eq_impls(self),
@@ -893,19 +925,6 @@
}
}
- pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
- match (&a.kind(), &b.kind()) {
- (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => {
- if did_a != did_b {
- return false;
- }
-
- substs_a.types().zip(substs_b.types()).all(|(a, b)| Self::same_type(a, b))
- }
- _ => a == b,
- }
- }
-
/// Peel off all reference types in this type until there are none left.
///
/// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`.
@@ -916,16 +935,16 @@
/// - `&'a mut u8` -> `u8`
/// - `&'a &'b u8` -> `u8`
/// - `&'a *const &'b u8 -> *const &'b u8`
- pub fn peel_refs(&'tcx self) -> Ty<'tcx> {
+ pub fn peel_refs(self) -> Ty<'tcx> {
let mut ty = self;
while let Ref(_, inner_ty, _) = ty.kind() {
- ty = inner_ty;
+ ty = *inner_ty;
}
ty
}
- pub fn outer_exclusive_binder(&'tcx self) -> DebruijnIndex {
- self.outer_exclusive_binder
+ pub fn outer_exclusive_binder(self) -> DebruijnIndex {
+ self.0.outer_exclusive_binder
}
}
@@ -1006,11 +1025,11 @@
ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
- ty::Slice(ty) => needs_drop_components(ty, target_layout),
+ ty::Slice(ty) => needs_drop_components(*ty, target_layout),
ty::Array(elem_ty, size) => {
- match needs_drop_components(elem_ty, target_layout) {
+ match needs_drop_components(*elem_ty, target_layout) {
Ok(v) if v.is_empty() => Ok(v),
- res => match size.val.try_to_bits(target_layout.pointer_size) {
+ res => match size.val().try_to_bits(target_layout.pointer_size) {
// Arrays of size zero don't need drop, even if their element
// type does.
Some(0) => Ok(SmallVec::new()),
@@ -1041,6 +1060,42 @@
}
}
+pub fn is_trivially_const_drop<'tcx>(ty: Ty<'tcx>) -> bool {
+ match *ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Str
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Foreign(_) => true,
+
+ ty::Opaque(..)
+ | ty::Dynamic(..)
+ | ty::Error(_)
+ | ty::Bound(..)
+ | ty::Param(_)
+ | ty::Placeholder(_)
+ | ty::Projection(_)
+ | ty::Infer(_) => false,
+
+ // Not trivial because they have components, and instead of looking inside,
+ // we'll just perform trait selection.
+ ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false,
+
+ ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
+
+ ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty.expect_ty())),
+ }
+}
+
// Does the equivalent of
// ```
// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index ba5775f..ab70c15 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -2,7 +2,7 @@
//! WARNING: this does not keep track of the region depth.
use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, TyCtxt};
+use crate::ty::{self, Ty};
use rustc_data_structures::sso::SsoHashSet;
use smallvec::{self, SmallVec};
@@ -11,7 +11,6 @@
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>>,
@@ -26,13 +25,8 @@
/// It maintains a set of visited types and
/// skips any types that are already there.
impl<'tcx> TypeWalker<'tcx> {
- 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(),
- }
+ pub fn new(root: GenericArg<'tcx>) -> Self {
+ Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
}
/// Skips the subtree corresponding to the last type
@@ -61,7 +55,7 @@
let next = self.stack.pop()?;
self.last_subtree = self.stack.len();
if self.visited.insert(next) {
- push_inner(self.expose_default_const_substs, &mut self.stack, next);
+ push_inner(&mut self.stack, next);
debug!("next: stack={:?}", self.stack);
return Some(next);
}
@@ -80,8 +74,8 @@
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
- pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
- TypeWalker::new(Some(tcx), self)
+ pub fn walk(self) -> TypeWalker<'tcx> {
+ TypeWalker::new(self)
}
/// Iterator that walks the immediate children of `self`. Hence
@@ -93,21 +87,16 @@
/// 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(Some(tcx), &mut stack, self);
+ push_inner(&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())
- }
-
+impl<'tcx> Ty<'tcx> {
/// 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
@@ -118,8 +107,8 @@
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
- pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
- TypeWalker::new(Some(tcx), self.into())
+ pub fn walk(self) -> TypeWalker<'tcx> {
+ TypeWalker::new(self.into())
}
}
@@ -129,11 +118,7 @@
/// 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>,
-) {
+fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
match parent.unpack() {
GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
ty::Bool
@@ -172,7 +157,7 @@
stack.extend(obj.iter().rev().flat_map(|predicate| {
let (substs, opt_ty) = match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
- ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
+ ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)),
ty::ExistentialPredicate::AutoTrait(_) =>
// Empty iterator
{
@@ -180,7 +165,10 @@
}
};
- substs.iter().rev().chain(opt_ty.map(|ty| ty.into()))
+ substs.iter().rev().chain(opt_ty.map(|term| match term {
+ ty::Term::Ty(ty) => ty.into(),
+ ty::Term::Const(ct) => ct.into(),
+ }))
}));
}
ty::Adt(_, substs)
@@ -201,8 +189,8 @@
},
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Const(parent_ct) => {
- stack.push(parent_ct.ty.into());
- match parent_ct.val {
+ stack.push(parent_ct.ty().into());
+ match parent_ct.val() {
ty::ConstKind::Infer(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Placeholder(_)
@@ -211,11 +199,7 @@
| ty::ConstKind::Error(_) => {}
ty::ConstKind::Unevaluated(ct) => {
- 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());
- }
+ stack.extend(ct.substs.iter().rev());
}
}
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 5e305eb..0c0b0f2 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -1,6 +1,7 @@
//! See docs in build/expr/mod.rs
use crate::build::Builder;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -23,11 +24,15 @@
inferred_ty: ty,
})
});
- assert_eq!(literal.ty, ty);
+ assert_eq!(literal.ty(), ty);
Constant { span, user_ty, literal: literal.into() }
}
- ExprKind::StaticRef { literal, .. } => {
- Constant { span, user_ty: None, literal: literal.into() }
+ ExprKind::StaticRef { alloc_id, ty, .. } => {
+ let const_val =
+ ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx));
+ let literal = ConstantKind::Val(const_val, ty);
+
+ Constant { span, user_ty: None, literal }
}
ExprKind::ConstBlock { value } => {
Constant { span: span, user_ty: None, literal: value.into() }
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 c6a34ec..1e94c41 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -217,10 +217,6 @@
ty::ClosureKind::FnOnce => {}
}
- // We won't be building MIR if the closure wasn't local
- let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
- let closure_span = tcx.hir().span(closure_hir_id);
-
let Some((capture_index, capture)) =
find_capture_matching_projections(
typeck_results,
@@ -228,6 +224,7 @@
closure_def_id,
&from_builder.projection,
) else {
+ let closure_span = tcx.def_span(closure_def_id);
if !enable_precise_capture(tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
@@ -244,6 +241,8 @@
return Err(from_builder);
};
+ // We won't be building MIR if the closure wasn't local
+ let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
let closure_ty = typeck_results.node_type(closure_hir_id);
let substs = match closure_ty.kind() {
@@ -266,7 +265,7 @@
// we need to deref it
upvar_resolved_place_builder = match capture.info.capture_kind {
ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(),
- ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder,
+ ty::UpvarCapture::ByValue => upvar_resolved_place_builder,
};
let next_projection = capture.place.projections.len();
@@ -336,10 +335,7 @@
}
crate fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Self {
- self.project(PlaceElem::Downcast(
- Some(adt_def.variants[variant_index].ident.name),
- variant_index,
- ))
+ self.project(PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index))
}
fn index(self, index: Local) -> Self {
@@ -573,7 +569,6 @@
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
- | ExprKind::LlvmInlineAsm { .. }
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => {
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 9a86d46..1dc4925 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -350,7 +350,6 @@
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
| ExprKind::InlineAsm { .. }
- | ExprKind::LlvmInlineAsm { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
// these do not have corresponding `Rvalue` variants,
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index fcda52e..d31f6ed 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -67,8 +67,7 @@
| ExprKind::Repeat { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
- | ExprKind::ThreadLocalRef(_)
- | ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+ | ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
Some(Category::Constant)
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index d9896ff..c706e6e 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -90,17 +90,8 @@
};
let join_block = this.cfg.start_new_block();
- this.cfg.terminate(
- then_blk,
- source_info,
- TerminatorKind::Goto { target: join_block },
- );
- this.cfg.terminate(
- else_blk,
- source_info,
- TerminatorKind::Goto { target: join_block },
- );
-
+ this.cfg.goto(then_blk, source_info, join_block);
+ this.cfg.goto(else_blk, source_info, join_block);
join_block.unit()
}
ExprKind::Let { expr, ref pat } => {
@@ -109,8 +100,6 @@
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,
@@ -133,6 +122,7 @@
},
);
+ let join_block = this.cfg.start_new_block();
this.cfg.goto(true_block, source_info, join_block);
this.cfg.goto(false_block, source_info, join_block);
join_block.unit()
@@ -358,7 +348,7 @@
let place_builder = place_builder.clone();
this.consume_by_copy_or_move(
place_builder
- .field(n, ty)
+ .field(n, *ty)
.into_place(this.tcx, this.typeck_results),
)
}
@@ -477,9 +467,7 @@
}
// These cases don't actually need a destination
- ExprKind::Assign { .. }
- | ExprKind::AssignOp { .. }
- | ExprKind::LlvmInlineAsm { .. } => {
+ ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
unpack!(block = this.stmt_expr(block, expr, None));
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
block.unit()
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 4245535..7419c5b 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -101,38 +101,6 @@
BreakableTarget::Return,
source_info,
),
- ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => {
- debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
- this.block_context.push(BlockFrame::SubExpr);
- let outputs = outputs
- .into_iter()
- .copied()
- .map(|output| unpack!(block = this.as_place(block, &this.thir[output])))
- .collect::<Vec<_>>()
- .into_boxed_slice();
- let inputs = inputs
- .into_iter()
- .copied()
- .map(|input| {
- let input = &this.thir[input];
- (input.span, unpack!(block = this.as_local_operand(block, &input)))
- })
- .collect::<Vec<_>>()
- .into_boxed_slice();
- this.cfg.push(
- block,
- Statement {
- source_info,
- kind: StatementKind::LlvmInlineAsm(Box::new(LlvmInlineAsm {
- asm: asm.clone(),
- outputs,
- inputs,
- })),
- },
- );
- this.block_context.pop();
- block.unit()
- }
_ => {
assert!(
statement_scope.is_some(),
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index e3a05e0..ec8cb30 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -47,6 +47,25 @@
let expr_span = expr.span;
match expr.kind {
+ ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
+ let lhs_then_block = unpack!(this.then_else_break(
+ block,
+ &this.thir[lhs],
+ temp_scope_override,
+ break_scope,
+ variable_scope_span,
+ ));
+
+ let rhs_then_block = unpack!(this.then_else_break(
+ lhs_then_block,
+ &this.thir[rhs],
+ temp_scope_override,
+ break_scope,
+ variable_scope_span,
+ ));
+
+ rhs_then_block.unit()
+ }
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| {
@@ -245,7 +264,7 @@
// The set of places that we are creating fake borrows of. If there are
// no match guards then we don't need any fake borrows, so don't track
// them.
- let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None };
+ let mut fake_borrows = match_has_guard.then(FxHashSet::default);
let mut otherwise = None;
@@ -583,33 +602,30 @@
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
- if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
- )))) = self.local_decls[local].local_info
- {
- // `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
- // a scrutinee place. `scrutinee_place_builder` will fail for destructured
- // assignments. This is because a closure only captures the precise places
- // that it will read and as a result a closure may not capture the entire
- // tuple/struct and rather have individual places that will be read in the
- // final MIR.
- // Example:
- // ```
- // let foo = (0, 1);
- // let c = || {
- // let (v1, v2) = foo;
- // };
- // ```
- if let Ok(match_pair_resolved) =
- initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
- {
- let place =
- match_pair_resolved.into_place(self.tcx, self.typeck_results);
- *match_place = Some(place);
- }
- } else {
+ )))) = self.local_decls[local].local_info else {
bug!("Let binding to non-user variable.")
+ };
+ // `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
+ // a scrutinee place. `scrutinee_place_builder` will fail for destructured
+ // assignments. This is because a closure only captures the precise places
+ // that it will read and as a result a closure may not capture the entire
+ // tuple/struct and rather have individual places that will be read in the
+ // final MIR.
+ // Example:
+ // ```
+ // let foo = (0, 1);
+ // let c = || {
+ // let (v1, v2) = foo;
+ // };
+ // ```
+ if let Ok(match_pair_resolved) =
+ initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
+ *match_place = Some(place);
}
}
// All of the subcandidates should bind the same locals, so we
@@ -948,13 +964,13 @@
///
/// For `bool` we always generate two edges, one for `true` and one for
/// `false`.
- options: FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
+ options: FxIndexMap<ty::Const<'tcx>, u128>,
},
/// Test for equality with value, possibly after an unsizing coercion to
/// `ty`,
Eq {
- value: &'tcx ty::Const<'tcx>,
+ value: ty::Const<'tcx>,
// Integer types are handled by `SwitchInt`, and constants with ADT
// types are converted back into patterns, so this can only be `&str`,
// `&[T]`, `f32` or `f64`.
@@ -1328,23 +1344,22 @@
let mut otherwise = None;
for match_pair in match_pairs {
- if let PatKind::Or { ref pats } = *match_pair.pattern.kind {
- let or_span = match_pair.pattern.span;
- let place = match_pair.place;
-
- first_candidate.visit_leaves(|leaf_candidate| {
- self.test_or_pattern(
- leaf_candidate,
- &mut otherwise,
- pats,
- or_span,
- place.clone(),
- fake_borrows,
- );
- });
- } else {
+ let PatKind::Or { ref pats } = &*match_pair.pattern.kind else {
bug!("Or-patterns should have been sorted to the end");
- }
+ };
+ let or_span = match_pair.pattern.span;
+ let place = match_pair.place;
+
+ first_candidate.visit_leaves(|leaf_candidate| {
+ self.test_or_pattern(
+ leaf_candidate,
+ &mut otherwise,
+ pats,
+ or_span,
+ place.clone(),
+ fake_borrows,
+ );
+ });
}
let remainder_start = otherwise.unwrap_or_else(|| self.cfg.start_new_block());
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 4ce26cc..4f9a2c0 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -210,7 +210,7 @@
}
PatKind::Range(PatRange { lo, hi, end }) => {
- let (range, bias) = match *lo.ty.kind() {
+ let (range, bias) = match *lo.ty().kind() {
ty::Char => {
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
}
@@ -228,7 +228,9 @@
_ => (None, 0),
};
if let Some((min, max, sz)) = range {
- if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
+ if let (Some(lo), Some(hi)) =
+ (lo.val().try_to_bits(sz), hi.val().try_to_bits(sz))
+ {
// We want to compare ranges numerically, but the order of the bitwise
// representation of signed integers does not match their numeric order.
// Thus, to correct the ordering, we need to shift the range of signed
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index a01df23..ce84877 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -59,8 +59,8 @@
},
PatKind::Range(range) => {
- assert_eq!(range.lo.ty, match_pair.pattern.ty);
- assert_eq!(range.hi.ty, match_pair.pattern.ty);
+ assert_eq!(range.lo.ty(), match_pair.pattern.ty);
+ assert_eq!(range.hi.ty(), match_pair.pattern.ty);
Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
}
@@ -86,13 +86,10 @@
test_place: &PlaceBuilder<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
- options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
+ options: &mut FxIndexMap<ty::Const<'tcx>, u128>,
) -> bool {
- let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
- Some(match_pair) => match_pair,
- _ => {
- return false;
- }
+ let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else {
+ return false;
};
match *match_pair.pattern.kind {
@@ -230,16 +227,15 @@
let target_blocks = make_target_blocks(self);
let terminator = if *switch_ty.kind() == ty::Bool {
assert!(!options.is_empty() && options.len() <= 2);
- if let [first_bb, second_bb] = *target_blocks {
- let (true_bb, false_bb) = match options[0] {
- 1 => (first_bb, second_bb),
- 0 => (second_bb, first_bb),
- v => span_bug!(test.span, "expected boolean value but got {:?}", v),
- };
- TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb)
- } else {
+ let [first_bb, second_bb] = *target_blocks else {
bug!("`TestKind::SwitchInt` on `bool` should have two targets")
- }
+ };
+ let (true_bb, false_bb) = match options[0] {
+ 1 => (first_bb, second_bb),
+ 0 => (second_bb, first_bb),
+ v => span_bug!(test.span, "expected boolean value but got {:?}", v),
+ };
+ TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb)
} else {
// The switch may be inexhaustive so we have a catch all block
debug_assert_eq!(options.len() + 1, target_blocks.len());
@@ -270,7 +266,7 @@
ty,
);
} else if let [success, fail] = *make_target_blocks(self) {
- assert_eq!(value.ty, ty);
+ assert_eq!(value.ty(), ty);
let expect = self.literal_operand(test.span, value);
let val = Operand::Copy(place);
self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
@@ -279,7 +275,7 @@
}
}
- TestKind::Range(PatRange { ref lo, ref hi, ref end }) => {
+ TestKind::Range(PatRange { lo, hi, ref end }) => {
let lower_bound_success = self.cfg.start_new_block();
let target_blocks = make_target_blocks(self);
@@ -288,24 +284,23 @@
let hi = self.literal_operand(test.span, hi);
let val = Operand::Copy(place);
- if let [success, fail] = *target_blocks {
- self.compare(
- block,
- lower_bound_success,
- fail,
- source_info,
- BinOp::Le,
- lo,
- val.clone(),
- );
- let op = match *end {
- RangeEnd::Included => BinOp::Le,
- RangeEnd::Excluded => BinOp::Lt,
- };
- self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
- } else {
+ let [success, fail] = *target_blocks else {
bug!("`TestKind::Range` should have two target blocks");
- }
+ };
+ self.compare(
+ block,
+ lower_bound_success,
+ fail,
+ source_info,
+ BinOp::Le,
+ lo,
+ val.clone(),
+ );
+ let op = match *end {
+ RangeEnd::Included => BinOp::Le,
+ RangeEnd::Excluded => BinOp::Lt,
+ };
+ self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
}
TestKind::Len { len, op } => {
@@ -320,21 +315,20 @@
// expected = <N>
let expected = self.push_usize(block, source_info, len);
- if let [true_bb, false_bb] = *target_blocks {
- // result = actual == expected OR result = actual < expected
- // branch based on result
- self.compare(
- block,
- true_bb,
- false_bb,
- source_info,
- op,
- Operand::Move(actual),
- Operand::Move(expected),
- );
- } else {
+ let [true_bb, false_bb] = *target_blocks else {
bug!("`TestKind::Len` should have two target blocks");
- }
+ };
+ // result = actual == expected OR result = actual < expected
+ // branch based on result
+ self.compare(
+ block,
+ true_bb,
+ false_bb,
+ source_info,
+ op,
+ Operand::Move(actual),
+ Operand::Move(expected),
+ );
}
}
}
@@ -375,7 +369,7 @@
block: BasicBlock,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
source_info: SourceInfo,
- value: &'tcx ty::Const<'tcx>,
+ value: ty::Const<'tcx>,
place: Place<'tcx>,
mut ty: Ty<'tcx>,
) {
@@ -396,14 +390,14 @@
_ => None,
};
let opt_ref_ty = unsize(ty);
- let opt_ref_test_ty = unsize(value.ty);
+ let opt_ref_test_ty = unsize(value.ty());
match (opt_ref_ty, opt_ref_test_ty) {
// nothing to do, neither is an array
(None, None) => {}
(Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
let tcx = self.tcx;
// make both a slice
- ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
+ ty = tcx.mk_imm_ref(*region, tcx.mk_slice(*elem_ty));
if opt_ref_ty.is_some() {
let temp = self.temp(ty, source_info.span);
self.cfg.push_assign(
@@ -462,16 +456,15 @@
);
self.diverge_from(block);
- if let [success_block, fail_block] = *make_target_blocks(self) {
- // check the result
- self.cfg.terminate(
- eq_block,
- source_info,
- TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block),
- );
- } else {
+ let [success_block, fail_block] = *make_target_blocks(self) else {
bug!("`TestKind::Eq` should have two target blocks")
- }
+ };
+ // check the result
+ self.cfg.terminate(
+ eq_block,
+ source_info,
+ TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block),
+ );
}
/// Given that we are performing `test` against `test_place`, this job
@@ -653,7 +646,7 @@
let tcx = self.tcx;
- let test_ty = test.lo.ty;
+ let test_ty = test.lo.ty();
let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?;
let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?;
@@ -754,10 +747,8 @@
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
- let elem = ProjectionElem::Downcast(
- Some(adt_def.variants[variant_index].ident.name),
- variant_index,
- );
+ let elem =
+ ProjectionElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index);
let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
@@ -773,17 +764,13 @@
span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
}
- fn const_range_contains(
- &self,
- range: PatRange<'tcx>,
- value: &'tcx ty::Const<'tcx>,
- ) -> Option<bool> {
+ fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) -> Option<bool> {
use std::cmp::Ordering::*;
let tcx = self.tcx;
- let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?;
- let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?;
+ let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty())?;
+ let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty())?;
match (b, range.end) {
(Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
@@ -794,7 +781,7 @@
fn values_not_contained_in_range(
&self,
range: PatRange<'tcx>,
- options: &FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
+ options: &FxIndexMap<ty::Const<'tcx>, u128>,
) -> Option<bool> {
for &val in options.keys() {
if self.const_range_contains(range, val)? {
@@ -840,7 +827,7 @@
method_name: Symbol,
self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>],
-) -> &'tcx ty::Const<'tcx> {
+) -> ty::Const<'tcx> {
let substs = tcx.mk_substs_trait(self_ty, params);
// The unhygienic comparison here is acceptable because this is only
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index 78047da..fd59144 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -25,11 +25,7 @@
/// Convenience function for creating a literal operand, one
/// without any user type annotation.
- crate fn literal_operand(
- &mut self,
- span: Span,
- literal: &'tcx ty::Const<'tcx>,
- ) -> Operand<'tcx> {
+ crate fn literal_operand(&mut self, span: Span, literal: ty::Const<'tcx>) -> Operand<'tcx> {
let literal = literal.into();
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 cb94e75..fb40361 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -104,8 +104,8 @@
let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
tcx.infer_ctxt().enter(|infcx| {
- let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
- build::construct_error(&infcx, def, id, body_id, body_owner_kind)
+ let body = if let Some(error_reported) = typeck_results.tainted_by_errors {
+ build::construct_error(&infcx, def, id, body_id, body_owner_kind, error_reported)
} else if body_owner_kind.is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
@@ -244,10 +244,10 @@
// The exception is `body.user_type_annotations`, which is used unmodified
// by borrow checking.
debug_assert!(
- !(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)),
+ !(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()),
"Unexpected free regions in MIR: {:?}",
body,
);
@@ -715,6 +715,7 @@
hir_id: hir::HirId,
body_id: hir::BodyId,
body_owner_kind: hir::BodyOwnerKind,
+ err: ErrorReported,
) -> Body<'tcx> {
let tcx = infcx.tcx;
let span = tcx.hir().span(hir_id);
@@ -760,7 +761,6 @@
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,
@@ -770,6 +770,7 @@
vec![],
span,
generator_kind,
+ Some(err),
);
body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty));
body
@@ -849,7 +850,6 @@
}
Body::new(
- self.tcx,
MirSource::item(self.def_id),
self.cfg.basic_blocks,
self.source_scopes,
@@ -859,6 +859,7 @@
self.var_debug_info,
self.fn_span,
self.generator_kind,
+ self.typeck_results.tainted_by_errors,
)
}
@@ -902,7 +903,7 @@
let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
if let ty::Ref(_, ty, _) = closure_ty.kind() {
closure_env_projs.push(ProjectionElem::Deref);
- closure_ty = ty;
+ closure_ty = *ty;
}
let upvar_substs = match closure_ty.kind() {
ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
@@ -930,14 +931,14 @@
let mut projs = closure_env_projs.clone();
projs.push(ProjectionElem::Field(Field::new(i), ty));
match capture {
- ty::UpvarCapture::ByValue(_) => {}
+ ty::UpvarCapture::ByValue => {}
ty::UpvarCapture::ByRef(..) => {
projs.push(ProjectionElem::Deref);
}
};
self.var_debug_info.push(VarDebugInfo {
- name: sym,
+ name: *sym,
source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
value: VarDebugInfoContents::Place(Place {
local: ty::CAPTURE_STRUCT_LOCAL,
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index fc46c54..84d6c1d 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -498,7 +498,7 @@
///
/// 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
+ /// 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.
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 7940bd1..8ca2449 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -329,7 +329,6 @@
| ExprKind::Box { .. }
| ExprKind::If { .. }
| ExprKind::InlineAsm { .. }
- | ExprKind::LlvmInlineAsm { .. }
| ExprKind::LogicalOp { .. }
| ExprKind::Use { .. } => {
// We don't need to save the old value and restore it
@@ -377,7 +376,7 @@
self.requires_unsafe(expr.span, DerefOfRawPointer);
}
}
- ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
+ ExprKind::InlineAsm { .. } => {
self.requires_unsafe(expr.span, UseOfInlineAssembly);
}
ExprKind::Adt(box Adt {
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 38bb00f..12ea740 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -9,6 +9,7 @@
#![feature(once_cell)]
#![feature(min_specialization)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index e4c2d2d..bccff37 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -11,9 +11,8 @@
crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let def_id = body.source.def_id().expect_local();
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() {
+ if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() {
if let FnKind::Closure = fn_kind {
// closures can't recur, so they don't matter.
return;
@@ -34,6 +33,9 @@
if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
return;
}
+ if vis.reachable_recursive_calls.is_empty() {
+ return;
+ }
vis.reachable_recursive_calls.sort();
@@ -64,8 +66,14 @@
impl<'mir, 'tcx> Search<'mir, 'tcx> {
/// Returns `true` if `func` refers to the function we are searching in.
- fn is_recursive_call(&self, func: &Operand<'tcx>) -> bool {
+ fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool {
let Search { tcx, body, trait_substs, .. } = *self;
+ // Resolving function type to a specific instance that is being called is expensive. To
+ // avoid the cost we check the number of arguments first, which is sufficient to reject
+ // most of calls as non-recursive.
+ if args.len() != body.arg_count {
+ return false;
+ }
let caller = body.source.def_id();
let param_env = tcx.param_env(caller);
@@ -139,8 +147,8 @@
fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
// When we examine a node for the last time, remember it if it is a recursive call.
let terminator = self.body[bb].terminator();
- if let TerminatorKind::Call { func, .. } = &terminator.kind {
- if self.is_recursive_call(func) {
+ if let TerminatorKind::Call { func, args, .. } = &terminator.kind {
+ if self.is_recursive_call(func, args) {
self.reachable_recursive_calls.push(terminator.source_info.span);
}
}
@@ -149,13 +157,14 @@
}
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
+ let terminator = self.body[bb].terminator();
+ if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 {
+ return true;
+ }
// Don't traverse successors of recursive calls or false CFG edges.
match self.body[bb].terminator().kind {
- TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func),
-
- TerminatorKind::FalseUnwind { unwind: Some(imaginary_target), .. }
- | TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
-
+ TerminatorKind::Call { ref func, ref args, .. } => self.is_recursive_call(func, args),
+ TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
_ => false,
}
}
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 9b54db0..ec2ff3c 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -10,7 +10,7 @@
crate fn lit_to_const<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
-) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+) -> Result<ty::Const<'tcx>, LitToConstError> {
let LitToConstInput { lit, ty, neg } = lit_input;
let trunc = |n| {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index bdde6b4..829dec7 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -8,7 +8,6 @@
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
-use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
@@ -163,9 +162,9 @@
let kind = match expr.kind {
// Here comes the interesting stuff:
- hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => {
+ hir::ExprKind::MethodCall(segment, ref args, fn_span) => {
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
- let expr = self.method_callee(expr, method_span, None);
+ let expr = self.method_callee(expr, segment.ident.span, None);
// When we apply adjustments to the receiver, use the span of
// the overall method call for better diagnostics. args[0]
// is guaranteed to exist, since a method call always has a receiver.
@@ -315,7 +314,6 @@
lhs: self.mirror_expr(lhs),
rhs: self.mirror_expr(rhs),
},
-
_ => {
let op = bin_op(op.node);
ExprKind::Binary {
@@ -570,12 +568,6 @@
line_spans: asm.line_spans,
},
- hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
- asm: &asm.inner,
- outputs: self.mirror_exprs(asm.outputs_exprs),
- inputs: self.mirror_exprs(asm.inputs_exprs),
- },
-
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_inline_const(self.tcx, anon_const_def_id);
@@ -590,7 +582,7 @@
_ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
};
- ExprKind::Repeat { value: self.mirror_expr(v), count }
+ ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
}
hir::ExprKind::Ret(ref v) => {
ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) }
@@ -715,7 +707,7 @@
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
let substs = InternalSubsts::identity_for_item(self.tcx(), did);
- let lhs = ty::Const {
+ let lhs = ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
ty::WithOptConstParam::unknown(did),
substs,
@@ -897,7 +889,7 @@
let name = self.tcx.hir().name(hir_id);
let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
ExprKind::Literal {
- literal: self.tcx.mk_const(ty::Const {
+ literal: self.tcx.mk_const(ty::ConstS {
val,
ty: self.typeck_results().node_type(expr.hir_id),
}),
@@ -910,7 +902,7 @@
let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
ExprKind::Literal {
- literal: self.tcx.mk_const(ty::Const {
+ literal: self.tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
ty::WithOptConstParam::unknown(def_id),
substs,
@@ -950,15 +942,8 @@
let kind = if self.tcx.is_thread_local_static(id) {
ExprKind::ThreadLocalRef(id)
} else {
- let ptr = self.tcx.create_static_alloc(id);
- ExprKind::StaticRef {
- literal: ty::Const::from_scalar(
- self.tcx,
- Scalar::from_pointer(ptr.into(), &self.tcx),
- ty,
- ),
- def_id: id,
- }
+ let alloc_id = self.tcx.create_static_alloc(id);
+ ExprKind::StaticRef { alloc_id, ty, def_id: id }
};
ExprKind::Deref {
arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
@@ -1108,9 +1093,9 @@
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
match upvar_capture {
- ty::UpvarCapture::ByValue(_) => captured_place_expr,
+ ty::UpvarCapture::ByValue => captured_place_expr,
ty::UpvarCapture::ByRef(upvar_borrow) => {
- let borrow_kind = match upvar_borrow.kind {
+ let borrow_kind = match upvar_borrow {
ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 38a4676..a65a3ed 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -79,7 +79,7 @@
ty: Ty<'tcx>,
sp: Span,
neg: bool,
- ) -> &'tcx ty::Const<'tcx> {
+ ) -> ty::Const<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
match self.tcx.at(sp).lit_to_const(LitToConstInput { lit, ty, neg }) {
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 7a4fd6f..d357ac6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -10,13 +10,14 @@
use rustc_hir as hir;
use rustc_hir::def::*;
use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{HirId, Pat};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_session::lint::builtin::{
BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
};
use rustc_session::Session;
+use rustc_span::source_map::Spanned;
use rustc_span::{DesugaringKind, ExpnKind, Span};
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -54,12 +55,6 @@
}
impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
match &ex.kind {
@@ -327,7 +322,7 @@
if let ty::Adt(edef, _) = pat_ty.kind() {
if edef.is_enum()
&& edef.variants.iter().any(|variant| {
- variant.ident == ident && variant.ctor_kind == CtorKind::Const
+ variant.ident(cx.tcx) == ident && variant.ctor_kind == CtorKind::Const
})
{
let variant_count = edef.variants.len();
@@ -451,6 +446,10 @@
pat: &'p DeconstructedPat<'p, 'tcx>,
span: Span,
) {
+ if is_let_chain(cx.tcx, pat_id) {
+ return;
+ }
+
let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
@@ -557,7 +556,7 @@
}
}
if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
- if cx.tcx.is_ty_uninhabited_from(cx.module, sub_ty, cx.param_env) {
+ if cx.tcx.is_ty_uninhabited_from(cx.module, *sub_ty, cx.param_env) {
err.note("references are always considered inhabited");
}
}
@@ -627,7 +626,7 @@
continue;
}
}
- let sp = def.variants[*variant_index].ident.span;
+ let sp = def.variants[*variant_index].ident(cx.tcx).span;
if covered.contains(&sp) {
// Don't point at variants that have already been covered due to other patterns to avoid
// visual clutter.
@@ -770,8 +769,11 @@
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) {
+ let parent_node = hir.get(parent);
+
+ match parent_node {
hir::Node::Arm(hir::Arm {
guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
..
@@ -786,6 +788,7 @@
}
_ => {}
}
+
let parent_parent = hir.get_parent_node(parent);
let parent_parent_node = hir.get(parent_parent);
@@ -798,12 +801,30 @@
..
}) = 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
+ return LetSource::WhileLet;
}
+
+ if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node {
+ return LetSource::IfLet;
+ }
+
+ LetSource::GenericLet
+}
+
+// Since this function is called within a let context, it is reasonable to assume that any parent
+// `&&` infers a let chain
+fn is_let_chain(tcx: TyCtxt<'_>, pat_id: HirId) -> bool {
+ let hir = tcx.hir();
+ let parent = hir.get_parent_node(pat_id);
+ let parent_parent = hir.get_parent_node(parent);
+ matches!(
+ hir.get(parent_parent),
+ hir::Node::Expr(
+ hir::Expr {
+ kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, ..),
+ ..
+ },
+ ..
+ )
+ )
}
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 dd16e3c..7db71ed 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
@@ -22,7 +22,7 @@
#[instrument(level = "debug", skip(self))]
pub(super) fn const_to_pat(
&self,
- cv: &'tcx ty::Const<'tcx>,
+ cv: ty::Const<'tcx>,
id: hir::HirId,
span: Span,
mir_structural_match_violation: bool,
@@ -120,45 +120,39 @@
}
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
- traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty).map(
- |non_sm_ty| {
- with_no_trimmed_paths(|| match non_sm_ty {
- traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt),
- traits::NonStructuralMatchTy::Dynamic => {
- "trait objects cannot be used in patterns".to_string()
- }
- traits::NonStructuralMatchTy::Opaque => {
- "opaque types cannot be used in patterns".to_string()
- }
- traits::NonStructuralMatchTy::Closure => {
- "closures cannot be used in patterns".to_string()
- }
- traits::NonStructuralMatchTy::Generator => {
- "generators cannot be used in patterns".to_string()
- }
- traits::NonStructuralMatchTy::Param => {
- bug!("use of a constant whose type is a parameter inside a pattern")
- }
- traits::NonStructuralMatchTy::Projection => {
- bug!("use of a constant whose type is a projection inside a pattern")
- }
- traits::NonStructuralMatchTy::Foreign => {
- bug!("use of a value of a foreign type inside a pattern")
- }
- })
- },
- )
+ traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
+ with_no_trimmed_paths(|| match non_sm_ty {
+ traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt),
+ traits::NonStructuralMatchTy::Dynamic => {
+ "trait objects cannot be used in patterns".to_string()
+ }
+ traits::NonStructuralMatchTy::Opaque => {
+ "opaque types cannot be used in patterns".to_string()
+ }
+ traits::NonStructuralMatchTy::Closure => {
+ "closures cannot be used in patterns".to_string()
+ }
+ traits::NonStructuralMatchTy::Generator => {
+ "generators cannot be used in patterns".to_string()
+ }
+ traits::NonStructuralMatchTy::Param => {
+ bug!("use of a constant whose type is a parameter inside a pattern")
+ }
+ traits::NonStructuralMatchTy::Projection => {
+ bug!("use of a constant whose type is a projection inside a pattern")
+ }
+ traits::NonStructuralMatchTy::Foreign => {
+ bug!("use of a value of a foreign type inside a pattern")
+ }
+ })
+ })
}
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
ty.is_structural_eq_shallow(self.infcx.tcx)
}
- fn to_pat(
- &mut self,
- cv: &'tcx ty::Const<'tcx>,
- mir_structural_match_violation: bool,
- ) -> Pat<'tcx> {
+ fn to_pat(&mut self, cv: ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> {
trace!(self.treat_byte_string_as_slice);
// This method is just a wrapper handling a validity check; the heavy lifting is
// performed by the recursive `recur` method, which is not meant to be
@@ -173,10 +167,11 @@
// If we were able to successfully convert the const to some pat,
// double-check that all types in the const implement `Structural`.
- let structural = self.search_for_structural_match_violation(cv.ty);
+ let structural = self.search_for_structural_match_violation(cv.ty());
debug!(
"search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
- cv.ty, structural
+ cv.ty(),
+ structural
);
// This can occur because const qualification treats all associated constants as
@@ -191,7 +186,7 @@
}
if let Some(msg) = structural {
- if !self.type_may_have_partial_eq_impl(cv.ty) {
+ if !self.type_may_have_partial_eq_impl(cv.ty()) {
// span_fatal avoids ICE from resolution of non-existent method (rare case).
self.tcx().sess.span_fatal(self.span, &msg);
} else if mir_structural_match_violation && !self.saw_const_match_lint.get() {
@@ -240,7 +235,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(self.tcx()).any(|t| match t.unpack() {
+ || ty.walk().any(|t| match t.unpack() {
ty::subst::GenericArgKind::Lifetime(_) => false,
ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
ty::subst::GenericArgKind::Const(_) => false,
@@ -249,7 +244,7 @@
fn field_pats(
&self,
- vals: impl Iterator<Item = &'tcx ty::Const<'tcx>>,
+ vals: impl Iterator<Item = ty::Const<'tcx>>,
) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
vals.enumerate()
.map(|(idx, val)| {
@@ -262,7 +257,7 @@
// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
fn recur(
&self,
- cv: &'tcx ty::Const<'tcx>,
+ cv: ty::Const<'tcx>,
mir_structural_match_violation: bool,
) -> Result<Pat<'tcx>, FallbackToConstRef> {
let id = self.id;
@@ -270,7 +265,7 @@
let tcx = self.tcx();
let param_env = self.param_env;
- let kind = match cv.ty.kind() {
+ let kind = match cv.ty().kind() {
ty::Float(_) => {
if self.include_lint_checks {
tcx.struct_span_lint_hir(
@@ -294,14 +289,14 @@
PatKind::Wild
}
ty::Adt(..)
- if !self.type_may_have_partial_eq_impl(cv.ty)
+ if !self.type_may_have_partial_eq_impl(cv.ty())
// FIXME(#73448): Find a way to bring const qualification into parity with
// `search_for_structural_match_violation` and then remove this condition.
- && self.search_for_structural_match_violation(cv.ty).is_some() =>
+ && self.search_for_structural_match_violation(cv.ty()).is_some() =>
{
// Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
// could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
- let msg = self.search_for_structural_match_violation(cv.ty).unwrap();
+ let msg = self.search_for_structural_match_violation(cv.ty()).unwrap();
self.saw_const_match_error.set(true);
if self.include_lint_checks {
tcx.sess.span_err(self.span, &msg);
@@ -319,7 +314,7 @@
// details.
// Backwards compatibility hack because we can't cause hard errors on these
// types, so we compare them via `PartialEq::eq` at runtime.
- ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => {
+ ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => {
if self.include_lint_checks
&& !self.saw_const_match_error.get()
&& !self.saw_const_match_lint.get()
@@ -333,7 +328,8 @@
let msg = format!(
"to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
- cv.ty, cv.ty,
+ cv.ty(),
+ cv.ty(),
);
lint.build(&msg).emit()
},
@@ -344,8 +340,12 @@
// `PartialEq::eq` on it.
return Err(fallback_to_const_ref(self));
}
- ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => {
- debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty);
+ ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
+ debug!(
+ "adt_def {:?} has !type_marked_structural for cv.ty: {:?}",
+ adt_def,
+ cv.ty()
+ );
let path = tcx.def_path_str(adt_def.did);
let msg = format!(
"to use a constant of type `{}` in a pattern, \
@@ -380,7 +380,7 @@
.destructure_const(param_env.and(cv))
.fields
.iter()
- .map(|val| self.recur(val, false))
+ .map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: Vec::new(),
@@ -389,7 +389,7 @@
// These are not allowed and will error elsewhere anyway.
ty::Dynamic(..) => {
self.saw_const_match_error.set(true);
- let msg = format!("`{}` cannot be used in patterns", cv.ty);
+ let msg = format!("`{}` cannot be used in patterns", cv.ty());
if self.include_lint_checks {
tcx.sess.span_err(span, &msg);
} else {
@@ -416,13 +416,13 @@
.destructure_const(param_env.and(array))
.fields
.iter()
- .map(|val| self.recur(val, false))
+ .map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: vec![],
}),
span,
- ty: pointee_ty,
+ ty: *pointee_ty,
},
};
self.behind_reference.set(old);
@@ -442,7 +442,7 @@
.destructure_const(param_env.and(array))
.fields
.iter()
- .map(|val| self.recur(val, false))
+ .map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: vec![],
@@ -459,7 +459,7 @@
// this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
// reference. This makes the rest of the matching logic simpler as it doesn't have
// to figure out how to get a reference again.
- ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => {
+ ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => {
if self.behind_reference.get() {
if self.include_lint_checks
&& !self.saw_const_match_error.get()
@@ -546,7 +546,7 @@
}
_ => {
self.saw_const_match_error.set(true);
- let msg = format!("`{}` cannot be used in patterns", cv.ty);
+ let msg = format!("`{}` cannot be used in patterns", cv.ty());
if self.include_lint_checks {
tcx.sess.span_err(span, &msg);
} else {
@@ -562,12 +562,12 @@
&& mir_structural_match_violation
// FIXME(#73448): Find a way to bring const qualification into parity with
// `search_for_structural_match_violation` and then remove this condition.
- && self.search_for_structural_match_violation(cv.ty).is_some()
+ && self.search_for_structural_match_violation(cv.ty()).is_some()
{
self.saw_const_match_lint.set(true);
// Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
// could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
- let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace(
+ let msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace(
"in a pattern,",
"in a pattern, the constant's initializer must be trivial or",
);
@@ -579,6 +579,6 @@
);
}
- Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) })
+ Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) })
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 368e395..e4d9bd9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -136,12 +136,12 @@
fn from_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- value: &Const<'tcx>,
+ value: Const<'tcx>,
) -> Option<IntRange> {
- if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
- let ty = value.ty;
+ let ty = value.ty();
+ if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
let val = (|| {
- if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val {
+ if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val() {
// For this specific pattern we can skip a lot of effort and go
// straight to the result, after doing a bit of checking. (We
// could remove this branch and just fall through, which
@@ -630,9 +630,9 @@
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
IntRange(IntRange),
/// Ranges of floating-point literal values (`2.0..=5.2`).
- FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+ FloatRange(ty::Const<'tcx>, ty::Const<'tcx>, RangeEnd),
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
- Str(&'tcx ty::Const<'tcx>),
+ Str(ty::Const<'tcx>),
/// Array and slice patterns.
Slice(Slice),
/// Constants that must not be matched structurally. They are treated as black
@@ -815,8 +815,14 @@
FloatRange(other_from, other_to, other_end),
) => {
match (
- compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
- compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
+ compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env, pcx.ty),
+ compare_const_vals(
+ pcx.cx.tcx,
+ *self_from,
+ *other_from,
+ pcx.cx.param_env,
+ pcx.ty,
+ ),
) {
(Some(to), Some(from)) => {
(from == Ordering::Greater || from == Ordering::Equal)
@@ -828,8 +834,13 @@
}
(Str(self_val), Str(other_val)) => {
// FIXME: there's probably a more direct way of comparing for equality
- match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty)
- {
+ match compare_const_vals(
+ pcx.cx.tcx,
+ *self_val,
+ *other_val,
+ pcx.cx.param_env,
+ pcx.ty,
+ ) {
Some(comparison) => comparison == Ordering::Equal,
None => false,
}
@@ -929,7 +940,7 @@
ty::Bool => smallvec![make_range(0, 1)],
ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
let len = len.eval_usize(cx.tcx, cx.param_env) as usize;
- if len != 0 && cx.is_uninhabited(sub_ty) {
+ if len != 0 && cx.is_uninhabited(*sub_ty) {
smallvec![]
} else {
smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
@@ -937,7 +948,7 @@
}
// Treat arrays of a constant but unknown length like slices.
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
- let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
+ let kind = if cx.is_uninhabited(*sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
smallvec![Slice(Slice::new(None, kind))]
}
ty::Adt(def, substs) if def.is_enum() => {
@@ -1368,13 +1379,13 @@
}
}
PatKind::Constant { value } => {
- if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) {
+ if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, *value) {
ctor = IntRange(int_range);
fields = Fields::empty();
} else {
match pat.ty.kind() {
ty::Float(_) => {
- ctor = FloatRange(value, value, RangeEnd::Included);
+ ctor = FloatRange(*value, *value, RangeEnd::Included);
fields = Fields::empty();
}
ty::Ref(_, t, _) if t.is_str() => {
@@ -1386,7 +1397,7 @@
// fields.
// Note: `t` is `str`, not `&str`.
let subpattern =
- DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span);
+ DeconstructedPat::new(Str(*value), Fields::empty(), *t, pat.span);
ctor = Single;
fields = Fields::singleton(cx, subpattern)
}
@@ -1401,11 +1412,11 @@
}
}
&PatKind::Range(PatRange { lo, hi, end }) => {
- let ty = lo.ty;
+ let ty = lo.ty();
ctor = if let Some(int_range) = IntRange::from_range(
cx.tcx,
- lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
- hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
+ lo.eval_bits(cx.tcx, cx.param_env, lo.ty()),
+ hi.eval_bits(cx.tcx, cx.param_env, hi.ty()),
ty,
&end,
) {
@@ -1648,7 +1659,7 @@
};
if let Some(variant) = variant {
- write!(f, "{}", variant.ident)?;
+ write!(f, "{}", variant.name)?;
}
// Without `cx`, we can't know which field corresponds to which, so we can't
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 55cf807..ddf39fb 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -99,7 +99,7 @@
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
Pat {
span: pat.span,
- ty: ref_ty,
+ ty: *ref_ty,
kind: Box::new(PatKind::Deref { subpattern: pat }),
}
},
@@ -121,13 +121,13 @@
fn lower_pattern_range(
&mut self,
ty: Ty<'tcx>,
- lo: &'tcx ty::Const<'tcx>,
- hi: &'tcx ty::Const<'tcx>,
+ lo: ty::Const<'tcx>,
+ hi: ty::Const<'tcx>,
end: RangeEnd,
span: Span,
) -> PatKind<'tcx> {
- assert_eq!(lo.ty, ty);
- assert_eq!(hi.ty, ty);
+ assert_eq!(lo.ty(), ty);
+ assert_eq!(hi.ty(), ty);
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
match (end, cmp) {
// `x..y` where `x < y`.
@@ -177,16 +177,16 @@
ty: Ty<'tcx>,
lo: Option<&PatKind<'tcx>>,
hi: Option<&PatKind<'tcx>>,
- ) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> {
+ ) -> Option<(ty::Const<'tcx>, ty::Const<'tcx>)> {
match (lo, hi) {
(Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
- Some((lo, hi))
+ Some((*lo, *hi))
}
(Some(PatKind::Constant { value: lo }), None) => {
- Some((lo, ty.numeric_max_val(self.tcx)?))
+ Some((*lo, ty.numeric_max_val(self.tcx)?))
}
(None, Some(PatKind::Constant { value: hi })) => {
- Some((ty.numeric_min_val(self.tcx)?, hi))
+ Some((ty.numeric_min_val(self.tcx)?, *hi))
}
_ => None,
}
@@ -275,7 +275,7 @@
let var_ty = ty;
if let ty::BindByReference(_) = bm {
if let ty::Ref(_, rty, _) = ty.kind() {
- ty = rty;
+ ty = *rty;
} else {
bug!("`ref {}` has wrong type {}", ident, ty);
}
@@ -417,7 +417,7 @@
| DefKind::AssocTy,
_,
)
- | Res::SelfTy(..)
+ | Res::SelfTy { .. }
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
_ => {
let pattern_error = match res {
@@ -493,7 +493,7 @@
let const_ =
ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id));
- let pattern = self.const_to_pat(&const_, id, span, mir_structural_match_violation);
+ let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
if !is_associated_const {
return pattern;
@@ -514,7 +514,7 @@
user_ty_span: span,
},
}),
- ty: const_.ty,
+ ty: const_.ty(),
}
} else {
pattern
@@ -546,7 +546,7 @@
// Evaluate early like we do in `lower_path`.
let value = value.eval(self.tcx, self.param_env);
- match value.val {
+ match value.val() {
ConstKind::Param(_) => {
self.errors.push(PatternError::ConstParamInPattern(span));
return PatKind::Wild;
@@ -744,8 +744,8 @@
crate fn compare_const_vals<'tcx>(
tcx: TyCtxt<'tcx>,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Option<Ordering> {
@@ -756,13 +756,13 @@
let fallback = || from_bool(a == b);
// Use the fallback if any type differs
- if a.ty != b.ty || a.ty != ty {
+ if a.ty() != b.ty() || a.ty() != ty {
return fallback();
}
// Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
// are just integer addresses).
- if a.val == b.val {
+ if a.val() == b.val() {
return from_bool(true);
}
@@ -797,7 +797,7 @@
if let (
ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
- ) = (a.val, b.val)
+ ) = (a.val(), b.val())
{
let a_bytes = get_slice_bytes(&tcx, a_val);
let b_bytes = get_slice_bytes(&tcx, b_val);
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 11856f6..3e1013b 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -8,7 +8,7 @@
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
-use std::fmt;
+use std::{fmt, iter};
/// The value of an inserted drop flag.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -329,8 +329,7 @@
mut succ: BasicBlock,
fields: &[(Place<'tcx>, Option<D::Path>)],
) -> Vec<BasicBlock> {
- Some(succ)
- .into_iter()
+ iter::once(succ)
.chain(fields.iter().rev().zip(unwind_ladder).map(|(&(place, path), &unwind_succ)| {
succ = self.drop_subpath(place, path, succ, unwind_succ);
succ
@@ -491,7 +490,7 @@
if let Some(variant_path) = subpath {
let base_place = tcx.mk_place_elem(
self.place,
- ProjectionElem::Downcast(Some(variant.ident.name), variant_index),
+ ProjectionElem::Downcast(Some(variant.name), variant_index),
);
let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs);
values.push(discr.val);
@@ -881,9 +880,9 @@
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
ty::Array(ety, size) => {
let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env());
- self.open_drop_for_array(ety, size)
+ self.open_drop_for_array(*ety, size)
}
- ty::Slice(ety) => self.open_drop_for_array(ety, None),
+ ty::Slice(ety) => self.open_drop_for_array(*ety, None),
_ => bug!("open drop from non-ADT `{:?}`", ty),
}
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 65c388f..4871320 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -176,7 +176,6 @@
// All other contexts are uses...
PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
- | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
| MutatingUseContext::Retag,
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 896377f..60cde65 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -134,11 +134,6 @@
| StatementKind::SetDiscriminant { box place, .. } => {
trans.gen(place.local);
}
- StatementKind::LlvmInlineAsm(asm) => {
- for place in &*asm.outputs {
- trans.gen(place.local);
- }
- }
// Nothing to do for these. Match exhaustively so this fails to compile when new
// variants are added.
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 2e00b4f..26bbc34 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -4,7 +4,6 @@
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
-use std::iter;
use std::mem;
use super::abs_domain::Lift;
@@ -293,16 +292,6 @@
StatementKind::FakeRead(box (_, place)) => {
self.create_move_path(*place);
}
- StatementKind::LlvmInlineAsm(ref asm) => {
- for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
- if !kind.is_indirect {
- self.gather_init(output.as_ref(), InitKind::Deep);
- }
- }
- for (_, input) in asm.inputs.iter() {
- self.gather_operand(input);
- }
- }
StatementKind::StorageLive(_) => {}
StatementKind::StorageDead(local) => {
self.gather_move(Place::from(*local));
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index e85d74e..7b000e2 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -7,7 +7,7 @@
doctest = false
[dependencies]
-itertools = "0.9"
+itertools = "0.10"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index a40c4d1..fd93744 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -104,10 +104,6 @@
// safe (at least as emitted during MIR construction)
}
- StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
- UnsafetyViolationKind::General,
- UnsafetyViolationDetails::UseOfInlineAssembly,
- ),
StatementKind::CopyNonOverlapping(..) => unreachable!(),
}
self.super_statement(statement, location);
@@ -208,7 +204,6 @@
MutatingUseContext::Store
| MutatingUseContext::Drop
| MutatingUseContext::AsmOutput
- | MutatingUseContext::LlvmAsmOutput
)
);
// If this is just an assignment, determine if the assigned type needs dropping.
@@ -398,12 +393,6 @@
}
impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
-
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
intravisit::walk_block(self, block);
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index e3ff6ad..5810ce6 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -76,10 +76,8 @@
}
let def_id = body.source.def_id().expect_local();
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
- let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
- let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst;
+ let is_fn_like = tcx.hir().get_by_def_id(def_id).fn_kind().is_some();
+ let is_assoc_const = tcx.def_kind(def_id) == DefKind::AssocConst;
// Only run const prop on functions, methods, closures and associated constants
if !is_fn_like && !is_assoc_const {
@@ -126,7 +124,7 @@
.predicates_of(def_id.to_def_id())
.predicates
.iter()
- .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None });
+ .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
if traits::impossible_predicates(
tcx,
traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
@@ -138,7 +136,6 @@
trace!("ConstProp starting for {:?}", def_id);
let dummy_body = &Body::new(
- tcx,
body.source,
body.basic_blocks().clone(),
body.source_scopes.clone(),
@@ -148,6 +145,7 @@
Default::default(),
body.span,
body.generator_kind(),
+ body.tainted_by_errors,
);
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
@@ -475,7 +473,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.definitely_needs_subst(self.tcx) {
+ if c.needs_subst() {
return None;
}
@@ -486,18 +484,18 @@
let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
if let Some(lint_root) = self.lint_root(source_info) {
let lint_only = match c.literal {
- ConstantKind::Ty(ct) => match ct.val {
+ ConstantKind::Ty(ct) => match ct.val() {
// 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.definitely_needs_subst(*tcx),
+ _ => c.literal.needs_subst(),
},
- ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx),
+ ConstantKind::Val(_, ty) => ty.needs_subst(),
};
if lint_only {
// Out of backwards compatibility we cannot report hard errors in unused
@@ -728,7 +726,7 @@
}
// FIXME we need to revisit this for #67176
- if rvalue.definitely_needs_subst(self.tcx) {
+ if rvalue.needs_subst() {
return None;
}
@@ -803,7 +801,7 @@
) {
if let Rvalue::Use(Operand::Constant(c)) = rval {
match c.literal {
- ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {}
+ ConstantKind::Ty(c) if matches!(c.val(), ConstKind::Unevaluated(..)) => {}
_ => {
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
return;
@@ -843,7 +841,7 @@
// Found a value represented as a pair. For now only do const-prop if the type
// of `rvalue` is also a tuple with two scalars.
// FIXME: enable the general case stated above ^.
- let ty = &value.layout.ty;
+ let ty = value.layout.ty;
// Only do it for tuples
if let ty::Tuple(substs) = ty.kind() {
// Only do it if tuple is also a pair with two scalars
@@ -877,7 +875,7 @@
literal: self
.ecx
.tcx
- .mk_const(ty::Const {
+ .mk_const(ty::ConstS {
ty,
val: ty::ConstKind::Value(ConstValue::ByRef {
alloc,
@@ -1035,8 +1033,7 @@
// These could be propagated with a smarter analysis or just some careful thinking about
// whether they'd be fine right now.
- MutatingUse(MutatingUseContext::LlvmAsmOutput)
- | MutatingUse(MutatingUseContext::Yield)
+ MutatingUse(MutatingUseContext::Yield)
| MutatingUse(MutatingUseContext::Drop)
| MutatingUse(MutatingUseContext::Retag)
// These can't ever be propagated under any scheme, as we can't reason about indirect
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index c61ee6f..62e060c 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -3,7 +3,7 @@
//!
//! To enable coverage, include the rustc command line option:
//!
-//! * `-Z instrument-coverage`
+//! * `-C instrument-coverage`
//!
//! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview
//! ------------------------------------------------------------------------------------
@@ -111,6 +111,7 @@
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan;
+use itertools::Itertools;
use rustc_middle::mir::create_dump_file;
use rustc_middle::mir::generic_graphviz::GraphvizWriter;
use rustc_middle::mir::spanview::{self, SpanViewable};
@@ -739,7 +740,6 @@
)
}
})
- .collect::<Vec<_>>()
.join("\n ")
));
}
@@ -768,7 +768,6 @@
.map(|expression| {
format!("Intermediate {}", debug_counters.format_counter(expression))
})
- .collect::<Vec<_>>()
.join("\n"),
);
}
@@ -783,7 +782,6 @@
covspan.format(tcx, mir_body)
)
})
- .collect::<Vec<_>>()
.join("\n"),
);
}
@@ -793,7 +791,6 @@
dependency_counters
.iter()
.map(|counter| debug_counters.format_counter(counter))
- .collect::<Vec<_>>()
.join(" \n"),
));
}
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index a25402a..57862b6 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,5 +1,6 @@
use super::Error;
+use itertools::Itertools;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::dominators::{self, Dominators};
use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
@@ -418,18 +419,11 @@
pub fn take_edge_counters(
&mut self,
) -> Option<impl Iterator<Item = (BasicCoverageBlock, CoverageKind)>> {
- self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter()))
+ self.edge_from_bcbs.take().map(|m| m.into_iter())
}
pub fn id(&self) -> String {
- format!(
- "@{}",
- self.basic_blocks
- .iter()
- .map(|bb| bb.index().to_string())
- .collect::<Vec<_>>()
- .join(ID_SEPARATOR)
- )
+ format!("@{}", self.basic_blocks.iter().map(|bb| bb.index().to_string()).join(ID_SEPARATOR))
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index b009e2f..2bb9f48f 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -66,8 +66,8 @@
return;
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local());
- let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
+ let is_fn_like =
+ tcx.hir().get_by_def_id(mir_source.def_id().expect_local()).fn_kind().is_some();
// Only instrument functions, methods, and closures (not constants since they are evaluated
// at compile time by Miri).
@@ -579,7 +579,7 @@
let mut hcx = tcx.create_no_span_stable_hashing_context();
let mut stable_hasher = StableHasher::new();
let owner = hir_body.id().hir_id.owner;
- let bodies = &tcx.hir_owner_nodes(owner).as_ref().unwrap().bodies;
+ let bodies = &tcx.hir_owner_nodes(owner).unwrap().bodies;
hcx.with_hir_bodies(false, owner, bodies, |hcx| {
hir_body.value.hash_stable(hcx, &mut stable_hasher)
});
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 1721fb5..da92190 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -9,7 +9,6 @@
/// A `query` provider for retrieving coverage information injected into MIR.
pub(crate) fn provide(providers: &mut Providers) {
providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id);
- providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id);
providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
}
@@ -137,30 +136,11 @@
coverage_visitor.info
}
-fn covered_file_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
- if tcx.is_mir_available(def_id) {
- let body = mir_body(tcx, def_id);
- for bb_data in body.basic_blocks().iter() {
- for statement in bb_data.statements.iter() {
- if let StatementKind::Coverage(box ref coverage) = statement.kind {
- if let Some(code_region) = coverage.code_region.as_ref() {
- if is_inlined(body, statement) {
- continue;
- }
- return Some(code_region.file_name);
- }
- }
- }
- }
- }
- return None;
-}
-
fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
let body = mir_body(tcx, def_id);
body.basic_blocks()
.iter()
- .map(|data| {
+ .flat_map(|data| {
data.statements.iter().filter_map(|statement| match statement.kind {
StatementKind::Coverage(box ref coverage) => {
if is_inlined(body, statement) {
@@ -172,7 +152,6 @@
_ => None,
})
})
- .flatten()
.collect()
}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index b5356a8..d1cb282 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,6 +1,7 @@
use super::debug::term_type;
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
+use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes;
use rustc_middle::mir::spanview::source_range_no_file;
use rustc_middle::mir::{
@@ -27,7 +28,7 @@
let stmt = &mir_body[bb].statements[stmt_index];
format!(
"{}: @{}[{}]: {:?}",
- source_range_no_file(tcx, &span),
+ source_range_no_file(tcx, span),
bb.index(),
stmt_index,
stmt
@@ -37,7 +38,7 @@
let term = mir_body[bb].terminator();
format!(
"{}: @{}.{}: {:?}",
- source_range_no_file(tcx, &span),
+ source_range_no_file(tcx, span),
bb.index(),
term_type(&term.kind),
term.kind
@@ -154,7 +155,7 @@
pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String {
format!(
"{}\n {}",
- source_range_no_file(tcx, &self.span),
+ source_range_no_file(tcx, self.span),
self.format_coverage_statements(tcx, mir_body).replace('\n', "\n "),
)
}
@@ -169,11 +170,7 @@
CoverageStatement::Statement(bb, _, index) => (bb, index),
CoverageStatement::Terminator(bb, _) => (bb, usize::MAX),
});
- sorted_coverage_statements
- .iter()
- .map(|covstmt| covstmt.format(tcx, mir_body))
- .collect::<Vec<_>>()
- .join("\n")
+ sorted_coverage_statements.iter().map(|covstmt| covstmt.format(tcx, mir_body)).join("\n")
}
/// If the span is part of a macro, returns the macro name symbol.
@@ -835,7 +832,6 @@
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Assign(_)
| StatementKind::SetDiscriminant { .. }
- | StatementKind::LlvmInlineAsm(_)
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _) => {
Some(statement.source_info.span)
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index b9c79d4..d787443 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -31,29 +31,18 @@
use coverage_test_macros::let_bcb;
+use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::graph::WithSuccessors;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags};
+use rustc_middle::ty::{self, BOOL_TY};
use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
// All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
const TEMP_BLOCK: BasicBlock = BasicBlock::MAX;
-fn dummy_ty() -> &'static TyS<'static> {
- thread_local! {
- 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)
-}
-
struct MockBlocks<'tcx> {
blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
dummy_place: Place<'tcx>,
@@ -165,7 +154,7 @@
fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
let switchint_kind = TerminatorKind::SwitchInt {
discr: Operand::Move(Place::from(self.new_temp())),
- switch_ty: dummy_ty(),
+ switch_ty: BOOL_TY, // just a dummy value
targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
};
self.add_block_from(some_from_block, switchint_kind)
@@ -232,11 +221,9 @@
mir_body
.successors(bb)
.map(|successor| { format!(" {:?} -> {:?};", bb, successor) })
- .collect::<Vec<_>>()
.join("\n")
)
})
- .collect::<Vec<_>>()
.join("\n")
);
}
@@ -262,11 +249,9 @@
basic_coverage_blocks
.successors(bcb)
.map(|successor| { format!(" {:?} -> {:?};", bcb, successor) })
- .collect::<Vec<_>>()
.join("\n")
)
})
- .collect::<Vec<_>>()
.join("\n")
);
}
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 2b38246..237ead5 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -222,9 +222,11 @@
impl UnifyKey for UnifyLocal {
type Value = ();
+ #[inline]
fn index(&self) -> u32 {
self.0.as_u32()
}
+ #[inline]
fn from_index(u: u32) -> Self {
Self(Local::from_u32(u))
}
@@ -534,25 +536,6 @@
// eliminate the resulting self-assignments automatically.
StatementKind::Assign(_) => {}
- StatementKind::LlvmInlineAsm(asm) => {
- // Inputs and outputs must not overlap.
- for (_, input) in &*asm.inputs {
- if let Some(in_place) = input.place() {
- if !in_place.is_indirect() {
- for out_place in &*asm.outputs {
- if !out_place.is_indirect() && !in_place.is_indirect() {
- self.record_local_conflict(
- in_place.local,
- out_place.local,
- "aliasing llvm_asm! operands",
- );
- }
- }
- }
- }
- }
- }
-
StatementKind::SetDiscriminant { .. }
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index ac88060..ba234dc 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -1,12 +1,12 @@
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::*;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use std::fmt::Debug;
use super::simplify::simplify_cfg;
/// This pass optimizes something like
-/// ```text
+/// ```ignore (syntax-highlighting-only)
/// let x: Option<()>;
/// let y: Option<()>;
/// match (x,y) {
@@ -15,144 +15,201 @@
/// }
/// ```
/// into something like
-/// ```text
+/// ```ignore (syntax-highlighting-only)
/// let x: Option<()>;
/// let y: Option<()>;
-/// let discriminant_x = // get discriminant of x
-/// let discriminant_y = // get discriminant of y
-/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0}
+/// let discriminant_x = std::mem::discriminant(x);
+/// let discriminant_y = std::mem::discriminant(y);
+/// if discriminant_x == discriminant_y {
+/// match x {
+/// Some(_) => 0,
+/// _ => 1, // <----
+/// } // | Actually the same bb
+/// } else { // |
+/// 1 // <--------------
+/// }
/// ```
+///
+/// Specifically, it looks for instances of control flow like this:
+/// ```text
+///
+/// =================
+/// | BB1 |
+/// |---------------| ============================
+/// | ... | /------> | BBC |
+/// |---------------| | |--------------------------|
+/// | switchInt(Q) | | | _cl = discriminant(P) |
+/// | c | --------/ |--------------------------|
+/// | d | -------\ | switchInt(_cl) |
+/// | ... | | | c | ---> BBC.2
+/// | otherwise | --\ | /--- | otherwise |
+/// ================= | | | ============================
+/// | | |
+/// ================= | | |
+/// | BBU | <-| | | ============================
+/// |---------------| | \-------> | BBD |
+/// |---------------| | | |--------------------------|
+/// | unreachable | | | | _dl = discriminant(P) |
+/// ================= | | |--------------------------|
+/// | | | switchInt(_dl) |
+/// ================= | | | d | ---> BBD.2
+/// | BB9 | <--------------- | otherwise |
+/// |---------------| ============================
+/// | ... |
+/// =================
+/// ```
+/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the
+/// code:
+/// - `BB1` is `parent` and `BBC, BBD` are children
+/// - `P` is `child_place`
+/// - `child_ty` is the type of `_cl`.
+/// - `Q` is `parent_op`.
+/// - `parent_ty` is the type of `Q`.
+/// - `BB9` is `destination`
+/// All this is then transformed into:
+/// ```text
+///
+/// =======================
+/// | BB1 |
+/// |---------------------| ============================
+/// | ... | /------> | BBEq |
+/// | _s = discriminant(P)| | |--------------------------|
+/// | _t = Ne(Q, _s) | | |--------------------------|
+/// |---------------------| | | switchInt(Q) |
+/// | switchInt(_t) | | | c | ---> BBC.2
+/// | false | --------/ | d | ---> BBD.2
+/// | otherwise | ---------------- | otherwise |
+/// ======================= | ============================
+/// |
+/// ================= |
+/// | BB9 | <-----------/
+/// |---------------|
+/// | ... |
+/// =================
+/// ```
+///
+/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`.
+/// The filter on which `P` are allowed (together with discussion of its correctness) is found in
+/// `may_hoist`.
pub struct EarlyOtherwiseBranch;
impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
- // FIXME(#78496)
- sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+ sess.mir_opt_level() >= 2
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running EarlyOtherwiseBranch on {:?}", body.source);
- // we are only interested in this bb if the terminator is a switchInt
- let bbs_with_switch =
- body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
+ let mut should_cleanup = false;
- let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
- .flat_map(|(bb_idx, bb)| {
- let switch = bb.terminator();
- let helper = Helper { body, tcx };
- let infos = helper.go(bb, switch)?;
- Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
- })
- .collect();
+ // Also consider newly generated bbs in the same pass
+ for i in 0..body.basic_blocks().len() {
+ let bbs = body.basic_blocks();
+ let parent = BasicBlock::from_usize(i);
+ let Some(opt_data) = evaluate_candidate(tcx, body, parent) else {
+ continue
+ };
- let should_cleanup = !opts_to_apply.is_empty();
-
- for opt_to_apply in opts_to_apply {
- if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) {
+ if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_data)) {
break;
}
- trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);
+ trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_data);
- let statements_before =
- body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
- let end_of_block_location = Location {
- block: opt_to_apply.basic_block_first_switch,
- statement_index: statements_before,
+ should_cleanup = true;
+
+ let TerminatorKind::SwitchInt {
+ discr: parent_op,
+ switch_ty: parent_ty,
+ targets: parent_targets
+ } = &bbs[parent].terminator().kind else {
+ unreachable!()
};
+ // Always correct since we can only switch on `Copy` types
+ let parent_op = match parent_op {
+ Operand::Move(x) => Operand::Copy(*x),
+ Operand::Copy(x) => Operand::Copy(*x),
+ Operand::Constant(x) => Operand::Constant(x.clone()),
+ };
+ let statements_before = bbs[parent].statements.len();
+ let parent_end = Location { block: parent, statement_index: statements_before };
let mut patch = MirPatch::new(body);
- // create temp to store second discriminant in
- let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
- let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
- let second_discriminant_temp = patch.new_temp(discr_type, discr_span);
+ // create temp to store second discriminant in, `_s` in example above
+ let second_discriminant_temp =
+ patch.new_temp(opt_data.child_ty, opt_data.child_source.span);
- patch.add_statement(
- end_of_block_location,
- StatementKind::StorageLive(second_discriminant_temp),
- );
+ patch.add_statement(parent_end, StatementKind::StorageLive(second_discriminant_temp));
// create assignment of discriminant
- let place_of_adt_to_get_discriminant_of =
- opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
patch.add_assign(
- end_of_block_location,
+ parent_end,
Place::from(second_discriminant_temp),
- Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
+ Rvalue::Discriminant(opt_data.child_place),
);
- // create temp to store NotEqual comparison between the two discriminants
- let not_equal = BinOp::Ne;
- let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
- let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
- patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));
+ // create temp to store inequality comparison between the two discriminants, `_t` in
+ // example above
+ let nequal = BinOp::Ne;
+ let comp_res_type = nequal.ty(tcx, *parent_ty, opt_data.child_ty);
+ let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
+ patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
- // create NotEqual comparison between the two discriminants
- let first_descriminant_place =
- opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
- let not_equal_rvalue = Rvalue::BinaryOp(
- not_equal,
- Box::new((
- Operand::Copy(Place::from(second_discriminant_temp)),
- Operand::Copy(first_descriminant_place),
- )),
+ // create inequality comparison between the two discriminants
+ let comp_rvalue = Rvalue::BinaryOp(
+ nequal,
+ Box::new((parent_op.clone(), Operand::Move(Place::from(second_discriminant_temp)))),
);
patch.add_statement(
- end_of_block_location,
- StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))),
+ parent_end,
+ StatementKind::Assign(Box::new((Place::from(comp_temp), comp_rvalue))),
);
- let new_targets = opt_to_apply
- .infos
- .iter()
- .flat_map(|x| x.second_switch_info.targets_with_values.iter())
- .cloned();
+ let eq_new_targets = parent_targets.iter().map(|(value, child)| {
+ let TerminatorKind::SwitchInt{ targets, .. } = &bbs[child].terminator().kind else {
+ unreachable!()
+ };
+ (value, targets.target_for_value(value))
+ });
+ let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination);
- let targets = SwitchTargets::new(
- new_targets,
- opt_to_apply.infos[0].first_switch_info.otherwise_bb,
- );
-
- // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
- let new_switch_data = BasicBlockData::new(Some(Terminator {
- source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
+ // Create `bbEq` in example above
+ let eq_switch = BasicBlockData::new(Some(Terminator {
+ source_info: bbs[parent].terminator().source_info,
kind: TerminatorKind::SwitchInt {
- // the first and second discriminants are equal, so just pick one
- discr: Operand::Copy(first_descriminant_place),
- switch_ty: discr_type,
- targets,
+ // switch on the first discriminant, so we can mark the second one as dead
+ discr: parent_op,
+ switch_ty: opt_data.child_ty,
+ targets: eq_targets,
},
}));
- let new_switch_bb = patch.new_block(new_switch_data);
+ let eq_bb = patch.new_block(eq_switch);
- // switch on the NotEqual. If true, then jump to the `otherwise` case.
- // If false, then jump to a basic block that then jumps to the correct disciminant case
- let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
- let false_case = new_switch_bb;
+ // Jump to it on the basis of the inequality comparison
+ let true_case = opt_data.destination;
+ let false_case = eq_bb;
patch.patch_terminator(
- opt_to_apply.basic_block_first_switch,
+ parent,
TerminatorKind::if_(
tcx,
- Operand::Move(Place::from(not_equal_temp)),
+ Operand::Move(Place::from(comp_temp)),
true_case,
false_case,
),
);
// generate StorageDead for the second_discriminant_temp not in use anymore
- patch.add_statement(
- end_of_block_location,
- StatementKind::StorageDead(second_discriminant_temp),
- );
+ patch.add_statement(parent_end, StatementKind::StorageDead(second_discriminant_temp));
- // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch
+ // Generate a StorageDead for comp_temp in each of the targets, since we moved it into
+ // the switch
for bb in [false_case, true_case].iter() {
patch.add_statement(
Location { block: *bb, statement_index: 0 },
- StatementKind::StorageDead(not_equal_temp),
+ StatementKind::StorageDead(comp_temp),
);
}
@@ -167,201 +224,177 @@
}
}
-fn is_switch(terminator: &Terminator<'_>) -> bool {
- matches!(terminator.kind, TerminatorKind::SwitchInt { .. })
+/// Returns true if computing the discriminant of `place` may be hoisted out of the branch
+fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool {
+ for (place, proj) in place.iter_projections() {
+ match proj {
+ // Dereferencing in the computation of `place` might cause issues from one of two
+ // cateogires. First, the referrent might be invalid. We protect against this by
+ // dereferencing references only (not pointers). Second, the use of a reference may
+ // invalidate other references that are used later (for aliasing reasons). Consider
+ // where such an invalidated reference may appear:
+ // - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so
+ // cannot contain referenced data.
+ // - In `BBU`: Not possible since that block contains only the `unreachable` terminator
+ // - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to
+ // reaching that block in the input to our transformation, and so any data
+ // invalidated by that computation could not have been used there.
+ // - In `BB9`: Not possible since control flow might have reached `BB9` via the
+ // `otherwise` branch in `BBC, BBD` in the input to our transformation, which would
+ // have invalidated the data when computing `discriminant(P)`
+ // So dereferencing here is correct.
+ ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() {
+ ty::Ref(..) => {}
+ _ => return false,
+ },
+ // Field projections are always valid
+ ProjectionElem::Field(..) => {}
+ // We cannot allow
+ // downcasts either, since the correctness of the downcast may depend on the parent
+ // branch being taken. An easy example of this is
+ // ```
+ // Q = discriminant(_3)
+ // P = (_3 as Variant)
+ // ```
+ // However, checking if the child and parent place are the same and only erroring then
+ // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may
+ // be replaced by another optimization pass with any other condition that can be proven
+ // equivalent.
+ ProjectionElem::Downcast(..) => {
+ return false;
+ }
+ // We cannot allow indexing since the index may be out of bounds.
+ _ => {
+ return false;
+ }
+ }
+ }
+ true
}
-struct Helper<'a, 'tcx> {
- body: &'a Body<'tcx>,
+#[derive(Debug)]
+struct OptimizationData<'tcx> {
+ destination: BasicBlock,
+ child_place: Place<'tcx>,
+ child_ty: Ty<'tcx>,
+ child_source: SourceInfo,
+}
+
+fn evaluate_candidate<'tcx>(
tcx: TyCtxt<'tcx>,
-}
+ body: &Body<'tcx>,
+ parent: BasicBlock,
+) -> Option<OptimizationData<'tcx>> {
+ let bbs = body.basic_blocks();
+ let TerminatorKind::SwitchInt {
+ targets,
+ switch_ty: parent_ty,
+ ..
+ } = &bbs[parent].terminator().kind else {
+ return None
+ };
+ let parent_dest = {
+ let poss = targets.otherwise();
+ // If the fallthrough on the parent is trivially unreachable, we can let the
+ // children choose the destination
+ if bbs[poss].statements.len() == 0
+ && bbs[poss].terminator().kind == TerminatorKind::Unreachable
+ {
+ None
+ } else {
+ Some(poss)
+ }
+ };
+ let Some((_, child)) = targets.iter().next() else {
+ return None
+ };
+ let child_terminator = &bbs[child].terminator();
+ let TerminatorKind::SwitchInt {
+ switch_ty: child_ty,
+ targets: child_targets,
+ ..
+ } = &child_terminator.kind else {
+ return None
+ };
+ if child_ty != parent_ty {
+ return None;
+ }
+ let Some(StatementKind::Assign(boxed))
+ = &bbs[child].statements.first().map(|x| &x.kind) else {
+ return None;
+ };
+ let (_, Rvalue::Discriminant(child_place)) = &**boxed else {
+ return None;
+ };
+ let destination = parent_dest.unwrap_or(child_targets.otherwise());
-#[derive(Debug, Clone)]
-struct SwitchDiscriminantInfo<'tcx> {
- /// Type of the discriminant being switched on
- discr_ty: Ty<'tcx>,
- /// The basic block that the otherwise branch points to
- otherwise_bb: BasicBlock,
- /// Target along with the value being branched from. Otherwise is not included
- targets_with_values: Vec<(u128, BasicBlock)>,
- discr_source_info: SourceInfo,
- /// The place of the discriminant used in the switch
- discr_used_in_switch: Place<'tcx>,
- /// The place of the adt that has its discriminant read
- place_of_adt_discr_read: Place<'tcx>,
- /// The type of the adt that has its discriminant read
- type_adt_matched_on: Ty<'tcx>,
-}
+ // Verify that the optimization is legal in general
+ // We can hoist evaluating the child discriminant out of the branch
+ if !may_hoist(tcx, body, *child_place) {
+ return None;
+ }
-#[derive(Debug)]
-struct OptimizationToApply<'tcx> {
- infos: Vec<OptimizationInfo<'tcx>>,
- /// Basic block of the original first switch
- basic_block_first_switch: BasicBlock,
-}
-
-#[derive(Debug)]
-struct OptimizationInfo<'tcx> {
- /// Info about the first switch and discriminant
- first_switch_info: SwitchDiscriminantInfo<'tcx>,
- /// Info about the second switch and discriminant
- second_switch_info: SwitchDiscriminantInfo<'tcx>,
-}
-
-impl<'tcx> Helper<'_, 'tcx> {
- pub fn go(
- &self,
- bb: &BasicBlockData<'tcx>,
- switch: &Terminator<'tcx>,
- ) -> Option<Vec<OptimizationInfo<'tcx>>> {
- // try to find the statement that defines the discriminant that is used for the switch
- let discr = self.find_switch_discriminant_info(bb, switch)?;
-
- // go through each target, finding a discriminant read, and a switch
- let results = discr
- .targets_with_values
- .iter()
- .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value));
-
- // if the optimization did not apply for one of the targets, then abort
- if results.clone().any(|x| x.is_none()) || results.len() == 0 {
- trace!("NO: not all of the targets matched the pattern for optimization");
+ // Verify that the optimization is legal for each branch
+ for (value, child) in targets.iter() {
+ if !verify_candidate_branch(&bbs[child], value, *child_place, destination) {
return None;
}
-
- Some(results.flatten().collect())
}
+ Some(OptimizationData {
+ destination,
+ child_place: *child_place,
+ child_ty: *child_ty,
+ child_source: child_terminator.source_info,
+ })
+}
- fn find_discriminant_switch_pairing(
- &self,
- discr_info: &SwitchDiscriminantInfo<'tcx>,
- target: BasicBlock,
- value: u128,
- ) -> Option<OptimizationInfo<'tcx>> {
- let bb = &self.body.basic_blocks()[target];
- // find switch
- let terminator = bb.terminator();
- if is_switch(terminator) {
- let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;
-
- // the types of the two adts matched on have to be equalfor this optimization to apply
- if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
- trace!(
- "NO: types do not match. LHS: {:?}, RHS: {:?}",
- discr_info.type_adt_matched_on,
- this_bb_discr_info.type_adt_matched_on
- );
- return None;
- }
-
- // the otherwise branch of the two switches have to point to the same bb
- if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
- trace!("NO: otherwise target is not the same");
- return None;
- }
-
- // check that the value being matched on is the same. The
- if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) {
- trace!("NO: values being matched on are not the same");
- return None;
- }
-
- // only allow optimization if the left and right of the tuple being matched are the same variants.
- // so the following should not optimize
- // ```rust
- // let x: Option<()>;
- // let y: Option<()>;
- // match (x,y) {
- // (Some(_), None) => {},
- // _ => {}
- // }
- // ```
- // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
- if !(this_bb_discr_info.targets_with_values.len() == 1
- && this_bb_discr_info.targets_with_values[0].0 == value)
- {
- trace!(
- "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
- );
- return None;
- }
-
- // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially.
- // for example, this should not be optimized:
- //
- // ```rust
- // enum E<'a> { Empty, Some(&'a E<'a>), }
- // let Some(Some(_)) = e;
- // ```
- //
- // ```mir
- // bb0: {
- // _2 = discriminant(*_1)
- // switchInt(_2) -> [...]
- // }
- // bb1: {
- // _3 = discriminant(*(((*_1) as Some).0: &E))
- // switchInt(_3) -> [...]
- // }
- // ```
- let discr_place = discr_info.place_of_adt_discr_read;
- let this_discr_place = this_bb_discr_info.place_of_adt_discr_read;
- if discr_place.local == this_discr_place.local
- && this_discr_place.projection.starts_with(discr_place.projection)
- {
- trace!("NO: one target is the projection of another");
- return None;
- }
-
- // if we reach this point, the optimization applies, and we should be able to optimize this case
- // store the info that is needed to apply the optimization
-
- Some(OptimizationInfo {
- first_switch_info: discr_info.clone(),
- second_switch_info: this_bb_discr_info,
- })
- } else {
- None
- }
+fn verify_candidate_branch<'tcx>(
+ branch: &BasicBlockData<'tcx>,
+ value: u128,
+ place: Place<'tcx>,
+ destination: BasicBlock,
+) -> bool {
+ // In order for the optimization to be correct, the branch must...
+ // ...have exactly one statement
+ if branch.statements.len() != 1 {
+ return false;
}
-
- fn find_switch_discriminant_info(
- &self,
- bb: &BasicBlockData<'tcx>,
- switch: &Terminator<'tcx>,
- ) -> Option<SwitchDiscriminantInfo<'tcx>> {
- match &switch.kind {
- TerminatorKind::SwitchInt { discr, targets, .. } => {
- let discr_local = discr.place()?.as_local()?;
- // the declaration of the discriminant read. Place of this read is being used in the switch
- let discr_decl = &self.body.local_decls()[discr_local];
- let discr_ty = discr_decl.ty;
- // the otherwise target lies as the last element
- let otherwise_bb = targets.otherwise();
- let targets_with_values = targets.iter().collect();
-
- // find the place of the adt where the discriminant is being read from
- // assume this is the last statement of the block
- let place_of_adt_discr_read = match bb.statements.last()?.kind {
- StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
- Some(adt_place)
- }
- _ => None,
- }?;
-
- let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;
-
- Some(SwitchDiscriminantInfo {
- discr_used_in_switch: discr.place()?,
- discr_ty,
- otherwise_bb,
- targets_with_values,
- discr_source_info: discr_decl.source_info,
- place_of_adt_discr_read,
- type_adt_matched_on,
- })
- }
- _ => unreachable!("must only be passed terminator that is a switch"),
- }
+ // ...assign the descriminant of `place` in that statement
+ let StatementKind::Assign(boxed) = &branch.statements[0].kind else {
+ return false
+ };
+ let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else {
+ return false
+ };
+ if *from_place != place {
+ return false;
}
+ // ...make that assignment to a local
+ if discr_place.projection.len() != 0 {
+ return false;
+ }
+ // ...terminate on a `SwitchInt` that invalidates that local
+ let TerminatorKind::SwitchInt{ discr: switch_op, targets, .. } = &branch.terminator().kind else {
+ return false
+ };
+ if *switch_op != Operand::Move(*discr_place) {
+ return false;
+ }
+ // ...fall through to `destination` if the switch misses
+ if destination != targets.otherwise() {
+ return false;
+ }
+ // ...have a branch for value `value`
+ let mut iter = targets.iter();
+ let Some((target_value, _)) = iter.next() else {
+ return false;
+ };
+ if target_value != value {
+ return false;
+ }
+ // ...and have no more branches
+ if let Some(_) = iter.next() {
+ return false;
+ }
+ return true;
}
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 05834b4..2ed14b9 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -1,3 +1,4 @@
+use itertools::Itertools;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::Visitor;
@@ -5,7 +6,7 @@
use rustc_middle::ty::{
self,
subst::{GenericArgKind, Subst, SubstsRef},
- PredicateKind, Ty, TyCtxt, TyS,
+ PredicateKind, Ty, TyCtxt,
};
use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
use rustc_span::{symbol::sym, Span};
@@ -42,54 +43,28 @@
} = &terminator.kind
{
let source_info = *self.body.source_info(location);
- // Only handle function calls outside macros
- if !source_info.span.from_expansion() {
- let func_ty = func.ty(self.body, self.tcx);
- if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() {
- // 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(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)
- {
- let span = self.nth_arg_span(&args, 0);
- self.emit_lint(fn_id, fn_substs, source_info, span);
- }
+ let func_ty = func.ty(self.body, self.tcx);
+ if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() {
+ // 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() {
+ if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
+ if let Some((fn_id, fn_substs)) =
+ FunctionItemRefChecker::is_fn_ref(inner_ty)
+ {
+ let span = self.nth_arg_span(&args, 0);
+ self.emit_lint(fn_id, fn_substs, source_info, span);
}
}
- } else {
- self.check_bound_args(def_id, substs_ref, &args, source_info);
}
+ } else {
+ self.check_bound_args(def_id, substs_ref, &args, source_info);
}
}
}
self.super_terminator(terminator, location);
}
-
- /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These
- /// cases are handled as operands instead of call terminators to avoid any dependence on
- /// unstable, internal formatting details like whether `fmt` is called directly or not.
- fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
- let source_info = *self.body.source_info(location);
- if source_info.span.from_expansion() {
- let op_ty = operand.ty(self.body, self.tcx);
- if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() {
- if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) {
- let param_ty = substs_ref.type_at(0);
- if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) {
- // The operand's ctxt wouldn't display the lint since it's inside a macro so
- // we have to use the callsite's ctxt.
- let callsite_ctxt = source_info.span.source_callsite().ctxt();
- let span = source_info.span.with_ctxt(callsite_ctxt);
- self.emit_lint(fn_id, fn_substs, source_info, span);
- }
- }
- }
- }
- self.super_operand(operand, location);
- }
}
impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
@@ -110,16 +85,22 @@
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(self.tcx) {
+ for generic_inner_ty in arg_def.walk() {
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) {
+ if inner_ty == bound_ty {
// Do a substitution using the parameters from the callsite
let subst_ty = inner_ty.subst(self.tcx, substs_ref);
if let Some((fn_id, fn_substs)) =
FunctionItemRefChecker::is_fn_ref(subst_ty)
{
- let span = self.nth_arg_span(args, arg_num);
+ let mut span = self.nth_arg_span(args, arg_num);
+ if span.from_expansion() {
+ // The operand's ctxt wouldn't display the lint since it's inside a macro so
+ // we have to use the callsite's ctxt.
+ let callsite_ctxt = span.source_callsite().ctxt();
+ span = span.with_ctxt(callsite_ctxt);
+ }
self.emit_lint(fn_id, fn_substs, source_info, span);
}
}
@@ -197,7 +178,7 @@
let ident = self.tcx.item_name(fn_id).to_ident_string();
let ty_params = fn_substs.types().map(|ty| format!("{}", ty));
let const_params = fn_substs.consts().map(|c| format!("{}", c));
- let params = ty_params.chain(const_params).collect::<Vec<String>>().join(", ");
+ let params = ty_params.chain(const_params).join(", ");
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index bc9a104..05de524 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -726,9 +726,13 @@
saved_locals: &GeneratorSavedLocals,
) {
let did = body.source.def_id();
- let allowed_upvars = tcx.erase_regions(upvars);
+ let param_env = tcx.param_env(did);
+
+ let allowed_upvars = tcx.normalize_erasing_regions(param_env, upvars);
let allowed = match witness.kind() {
- &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s),
+ &ty::GeneratorWitness(interior_tys) => {
+ tcx.normalize_erasing_late_bound_regions(param_env, interior_tys)
+ }
_ => {
tcx.sess.delay_span_bug(
body.span,
@@ -738,8 +742,6 @@
}
};
- let param_env = tcx.param_env(did);
-
for (local, decl) in body.local_decls.iter_enumerated() {
// Ignore locals which are internal or not saved between yields.
if !saved_locals.contains(local) || decl.internal {
@@ -1239,9 +1241,7 @@
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let yield_ty = if let Some(yield_ty) = body.yield_ty() {
- yield_ty
- } else {
+ let Some(yield_ty) = body.yield_ty() else {
// This only applies to generators
return;
};
@@ -1447,9 +1447,6 @@
self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
}
- // FIXME: Does `llvm_asm!` have any aliasing requirements?
- StatementKind::LlvmInlineAsm(_) => {}
-
StatementKind::FakeRead(..)
| StatementKind::SetDiscriminant { .. }
| StatementKind::StorageLive(_)
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index e1f30fe..55ce591 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -7,6 +7,7 @@
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
@@ -75,10 +76,18 @@
return false;
}
+ let param_env = tcx.param_env_reveal_all_normalized(def_id);
+ let param_env = rustc_trait_selection::traits::normalize_param_env_or_error(
+ tcx,
+ def_id,
+ param_env,
+ ObligationCause::misc(body.span, hir_id),
+ );
+
let mut this = Inliner {
tcx,
- param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
- codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
+ param_env,
+ codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
hir_id,
history: Vec::new(),
changed: false,
@@ -625,7 +634,7 @@
caller_body.required_consts.extend(
callee_body.required_consts.iter().copied().filter(|&ct| {
match ct.literal.const_for_ty() {
- Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)),
+ Some(ct) => matches!(ct.val(), ConstKind::Unevaluated(_)),
None => true,
}
}),
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 747e760..44ded16 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/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.definitely_needs_subst(tcx) {
+ if callee.needs_subst() {
continue;
}
}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 638baa0..e7d5bab 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -10,6 +10,7 @@
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
@@ -18,11 +19,11 @@
use required_consts::RequiredConstsVisitor;
use rustc_const_eval::util;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::steal::Steal;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
@@ -42,7 +43,8 @@
mod check_const_item_mutation;
mod check_packed_ref;
pub mod check_unsafety;
-mod cleanup_post_borrowck;
+// This pass is public to allow external drivers to perform MIR cleanup
+pub mod cleanup_post_borrowck;
mod const_debuginfo;
mod const_goto;
mod const_prop;
@@ -64,7 +66,8 @@
mod multiple_return_terminators;
mod normalize_array_len;
mod nrvo;
-mod remove_false_edges;
+// This pass is public to allow external drivers to perform MIR cleanup
+pub mod remove_false_edges;
mod remove_noop_landing_pads;
mod remove_storage_markers;
mod remove_uninit_drops;
@@ -74,7 +77,8 @@
mod reveal_all;
mod separate_const_switch;
mod shim;
-mod simplify;
+// This pass is public to allow external drivers to perform MIR cleanup
+pub mod simplify;
mod simplify_branches;
mod simplify_comparison_integral;
mod simplify_try;
@@ -136,8 +140,8 @@
/// Finds the full set of `DefId`s within the current crate that have
/// MIR associated with them.
-fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
- let mut set = FxHashSet::default();
+fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
+ let mut set = FxIndexSet::default();
// All body-owners have MIR associated with them.
set.extend(tcx.hir().body_owners());
@@ -146,7 +150,7 @@
// they don't have a BodyId, so we need to build them separately.
struct GatherCtors<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- set: &'a mut FxHashSet<LocalDefId>,
+ set: &'a mut FxIndexSet<LocalDefId>,
}
impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> {
fn visit_variant_data(
@@ -162,10 +166,6 @@
}
intravisit::walk_struct_def(self, v)
}
- type Map = intravisit::ErasedMap<'tcx>;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
}
tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
@@ -252,8 +252,11 @@
// Ensure that we compute the `mir_const_qualif` for constants at
// this point, before we steal the mir-const result.
// Also this means promotion can rely on all const checks having been done.
- let _ = tcx.mir_const_qualif_opt_const_arg(def);
+ let const_qualifs = tcx.mir_const_qualif_opt_const_arg(def);
let mut body = tcx.mir_const(def).steal();
+ if let Some(error_reported) = const_qualifs.tainted_by_errors {
+ body.tainted_by_errors = Some(error_reported);
+ }
let mut required_consts = Vec::new();
let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
@@ -342,7 +345,7 @@
}
}
- debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE");
+ debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
body
}
@@ -358,16 +361,9 @@
return tcx.mir_drops_elaborated_and_const_checked(def);
}
- // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to
- // execute before we can steal.
- if let Some(param_did) = def.const_param_did {
- tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
- } else {
- tcx.ensure().mir_borrowck(def.did);
- }
+ let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
+ let is_fn_like = tcx.hir().get_by_def_id(def.did).fn_kind().is_some();
if is_fn_like {
let did = def.did.to_def_id();
let def = ty::WithOptConstParam::unknown(did);
@@ -380,6 +376,9 @@
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
+ if let Some(error_reported) = mir_borrowck.tainted_by_errors {
+ body.tainted_by_errors = Some(error_reported);
+ }
// IMPORTANT
pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
@@ -530,7 +529,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(tcx), "Free regions in optimized MIR");
+ debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
body
}
@@ -545,19 +544,17 @@
return tcx.arena.alloc(IndexVec::new());
}
- if let Some(param_did) = def.const_param_did {
- tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
- } else {
- tcx.ensure().mir_borrowck(def.did);
- }
- let (_, promoted) = tcx.mir_promoted(def);
- let mut promoted = promoted.steal();
+ let tainted_by_errors = tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors;
+ let mut promoted = tcx.mir_promoted(def).1.steal();
for body in &mut promoted {
+ if let Some(error_reported) = tainted_by_errors {
+ body.tainted_by_errors = Some(error_reported);
+ }
run_post_borrowck_cleanup_passes(tcx, body);
}
- debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR");
+ debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
tcx.arena.alloc(promoted)
}
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index e4ac57a..cdfd49e 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -3,10 +3,11 @@
use crate::MirPass;
use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::intern::Interned;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, ReErased, Region, TyCtxt};
const MAX_NUM_BLOCKS: usize = 800;
const MAX_NUM_LOCALS: usize = 3000;
@@ -211,12 +212,7 @@
let Some(local) = place.as_local() else { return };
match operand {
Operand::Copy(place) | Operand::Move(place) => {
- let operand_local =
- if let Some(local) = place.local_or_deref_local() {
- local
- } else {
- return;
- };
+ let Some(operand_local) = place.local_or_deref_local() else { return; };
if !interesting_locals.contains(operand_local) {
return;
}
@@ -231,11 +227,15 @@
// current way of patching doesn't allow to work with `mut`
(
ty::Ref(
- ty::RegionKind::ReErased,
+ Region(Interned(ReErased, _)),
operand_ty,
Mutability::Not,
),
- ty::Ref(ty::RegionKind::ReErased, cast_ty, Mutability::Not),
+ ty::Ref(
+ Region(Interned(ReErased, _)),
+ cast_ty,
+ Mutability::Not,
+ ),
) => {
match (operand_ty.kind(), cast_ty.kind()) {
// current way of patching doesn't allow to work with `mut`
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 2a73e34..77fb092 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -50,7 +50,6 @@
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
- | StatementKind::LlvmInlineAsm { .. }
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag { .. } => {
return false;
diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
index 80c87ca..1c48efd 100644
--- a/compiler/rustc_mir_transform/src/required_consts.rs
+++ b/compiler/rustc_mir_transform/src/required_consts.rs
@@ -15,7 +15,7 @@
impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
if let Some(ct) = constant.literal.const_for_ty() {
- if let ConstKind::Unevaluated(_) = ct.val {
+ if let ConstKind::Unevaluated(_) = ct.val() {
self.required_consts.push(*constant);
}
}
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index ee66179..8ea550f 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -39,6 +39,6 @@
// We have to use `try_normalize_erasing_regions` here, since it's
// possible that we visit impossible-to-satisfy where clauses here,
// see #91745
- *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(ty);
+ *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(*ty);
}
}
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 612fce7..d265720 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -239,10 +239,6 @@
}
}
- // 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(_)
@@ -320,10 +316,6 @@
| 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
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 58996dc..b8feeb9 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -68,7 +68,7 @@
ty::InstanceDef::DropGlue(def_id, ty) => {
// FIXME(#91576): Drop shims for generators aren't subject to the MIR passes at the end
// of this function. Is this intentional?
- if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(ty::TyS::kind) {
+ if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) {
let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap();
let body = body.clone().subst(tcx, substs);
debug!("make_shim({:?}) = {:?}", instance, body);
@@ -137,7 +137,7 @@
span: Span,
) -> IndexVec<Local, LocalDecl<'tcx>> {
iter::once(LocalDecl::new(sig.output(), span))
- .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable()))
+ .chain(sig.inputs().iter().map(|ity| LocalDecl::new(*ity, span).immutable()))
.collect()
}
@@ -171,7 +171,7 @@
let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty));
let mut body =
- new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
+ new_body(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.
@@ -210,7 +210,6 @@
}
fn new_body<'tcx>(
- tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
@@ -218,7 +217,6 @@
span: Span,
) -> Body<'tcx> {
Body::new(
- tcx,
source,
basic_blocks,
IndexVec::from_elem_n(
@@ -237,6 +235,8 @@
vec![],
span,
None,
+ // FIXME(compiler-errors): is this correct?
+ None,
)
}
@@ -362,14 +362,7 @@
self.def_id,
self.sig.inputs_and_output[0],
));
- new_body(
- self.tcx,
- source,
- self.blocks,
- self.local_decls,
- self.sig.inputs().len(),
- self.span,
- )
+ new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
}
fn source_info(&self) -> SourceInfo {
@@ -719,14 +712,8 @@
block(&mut blocks, vec![], TerminatorKind::Resume, true);
}
- let mut body = new_body(
- tcx,
- MirSource::from_instance(instance),
- blocks,
- local_decls,
- sig.inputs().len(),
- span,
- );
+ let mut body =
+ new_body(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()));
@@ -791,7 +778,6 @@
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_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 7992124..4651e1f 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -303,7 +303,7 @@
/// evaluation: `if false { ... }`.
///
/// Those statements are bypassed by redirecting paths in the CFG around the
-/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// `dead blocks`; but with `-C instrument-coverage`, the dead blocks usually
/// include `Coverage` statements representing the Rust source code regions to
/// be counted at runtime. Without these `Coverage` statements, the regions are
/// lost, and the Rust source code will show no coverage information.
@@ -483,8 +483,7 @@
impl<'tcx> Visitor<'tcx> for UsedLocals {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind {
- StatementKind::LlvmInlineAsm(..)
- | StatementKind::CopyNonOverlapping(..)
+ StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag(..)
| StatementKind::Coverage(..)
| StatementKind::FakeRead(..)
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index 7761d40..d5507fc 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -631,10 +631,6 @@
.filter(|(_, bb)| {
// Reaching `unreachable` is UB so assume it doesn't happen.
bb.terminator().kind != TerminatorKind::Unreachable
- // But `asm!(...)` could abort the program,
- // so we cannot assume that the `unreachable` terminator itself is reachable.
- // FIXME(Centril): use a normalization pass instead of a check.
- || bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..)))
})
.peekable();
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 77bc209..cda9ba9 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -3,8 +3,7 @@
use crate::MirPass;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_middle::mir::{
- BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
- TerminatorKind,
+ BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind,
};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{Ty, TyCtxt};
@@ -56,7 +55,10 @@
match &layout.variants {
Variants::Single { index } => {
let mut res = FxHashSet::default();
- res.insert(index.as_u32() as u128);
+ res.insert(
+ ty.discriminant_for_variant(tcx, *index)
+ .map_or(index.as_u32() as u128, |discr| discr.val),
+ );
res
}
Variants::Multiple { variants, .. } => variants
@@ -75,16 +77,9 @@
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if body.source.promoted.is_some() {
- return;
- }
-
trace!("UninhabitedEnumBranching starting for {:?}", body.source);
- let basic_block_count = body.basic_blocks().len();
-
- for bb in 0..basic_block_count {
- let bb = BasicBlock::from_usize(bb);
+ for bb in body.basic_blocks().indices() {
trace!("processing block {:?}", bb);
let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 9e755ab..f916ca3 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -23,23 +23,14 @@
for (bb, bb_data) in traversal::postorder(body) {
let terminator = bb_data.terminator();
- // HACK: If the block contains any asm statement it is not regarded as unreachable.
- // This is a temporary solution that handles possibly diverging asm statements.
- // Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
- let asm_stmt_in_block = || {
- bb_data.statements.iter().any(|stmt: &Statement<'_>| {
- matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
- })
- };
-
- if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
+ if terminator.kind == TerminatorKind::Unreachable {
unreachable_blocks.insert(bb);
} else {
let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
if let Some(terminator_kind) = terminator_kind_opt {
- if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
+ if terminator_kind == TerminatorKind::Unreachable {
unreachable_blocks.insert(bb);
}
replacements.insert(bb, terminator_kind);
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index b70c24b..72c1b3f 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -573,7 +573,7 @@
let type_length = instance
.substs
.iter()
- .flat_map(|arg| arg.walk(tcx))
+ .flat_map(|arg| arg.walk())
.filter(|arg| match arg.unpack() {
GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
GenericArgKind::Lifetime(_) => false,
@@ -709,7 +709,7 @@
let literal = self.monomorphize(constant.literal);
let val = match literal {
mir::ConstantKind::Val(val, _) => val,
- mir::ConstantKind::Ty(ct) => match ct.val {
+ mir::ConstantKind::Ty(ct) => match ct.val() {
ty::ConstKind::Value(val) => val,
ty::ConstKind::Unevaluated(ct) => {
let param_env = ty::ParamEnv::reveal_all();
@@ -731,13 +731,13 @@
self.visit_ty(literal.ty(), TyContext::Location(location));
}
- fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
- debug!("visiting const {:?} @ {:?}", *constant, location);
+ fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) {
+ debug!("visiting const {:?} @ {:?}", constant, location);
- let substituted_constant = self.monomorphize(*constant);
+ let substituted_constant = self.monomorphize(constant);
let param_env = ty::ParamEnv::reveal_all();
- match substituted_constant.val {
+ match substituted_constant.val() {
ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
ty::ConstKind::Unevaluated(unevaluated) => {
match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
@@ -807,10 +807,18 @@
self.output.push(create_fn_mono_item(tcx, instance, source));
}
}
+ mir::TerminatorKind::Abort { .. } => {
+ let instance = Instance::mono(
+ tcx,
+ tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)),
+ );
+ if should_codegen_locally(tcx, &instance) {
+ self.output.push(create_fn_mono_item(tcx, instance, source));
+ }
+ }
mir::TerminatorKind::Goto { .. }
| mir::TerminatorKind::SwitchInt { .. }
| mir::TerminatorKind::Resume
- | mir::TerminatorKind::Abort
| mir::TerminatorKind::Return
| mir::TerminatorKind::Unreachable => {}
mir::TerminatorKind::GeneratorDrop
@@ -939,9 +947,7 @@
/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
/// can just link to the upstream crate and therefore don't need a mono item.
fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
- let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() {
- def_id
- } else {
+ let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
return true;
};
@@ -1034,7 +1040,7 @@
match (&source_ty.kind(), &target_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, .. })) => {
- ptr_vtable(a, b)
+ ptr_vtable(*a, *b)
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
@@ -1310,10 +1316,9 @@
if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
- let overridden_methods: FxHashSet<_> =
- impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
+ let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
for method in tcx.provided_trait_methods(trait_ref.def_id) {
- if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) {
+ if overridden_methods.contains_key(&method.def_id) {
continue;
}
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 21ac174..bbc65b0 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -4,6 +4,7 @@
#![feature(control_flow_enum)]
#![feature(let_else)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 516c9a9..681271b 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -303,9 +303,7 @@
// When polymorphization is enabled, methods which do not depend on their generic
// parameters, but the self-type of their impl block do will fail to normalize.
- if !tcx.sess.opts.debugging_opts.polymorphize
- || !instance.definitely_needs_subst(tcx)
- {
+ if !tcx.sess.opts.debugging_opts.polymorphize || !instance.needs_subst() {
// This is a method within an impl, find out what the self-type is:
let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
instance.substs,
diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
index dc22ffc6..b8684a0 100644
--- a/compiler/rustc_monomorphize/src/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -201,6 +201,38 @@
partitioner.internalize_symbols(cx, &mut post_inlining);
}
+ let instrument_dead_code =
+ tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions();
+
+ if instrument_dead_code {
+ assert!(
+ post_inlining.codegen_units.len() > 0,
+ "There must be at least one CGU that code coverage data can be generated in."
+ );
+
+ // Find the smallest CGU that has exported symbols and put the dead
+ // function stubs in that CGU. We look for exported symbols to increase
+ // the likelihood the linker won't throw away the dead functions.
+ // FIXME(#92165): In order to truly resolve this, we need to make sure
+ // the object file (CGU) containing the dead function stubs is included
+ // in the final binary. This will probably require forcing these
+ // function symbols to be included via `-u` or `/include` linker args.
+ let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect();
+ cgus.sort_by_key(|cgu| cgu.size_estimate());
+
+ let dead_code_cgu =
+ if let Some(cgu) = cgus.into_iter().rev().find(|cgu| {
+ cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)
+ }) {
+ cgu
+ } else {
+ // If there are no CGUs that have externally linked items,
+ // then we just pick the first CGU as a fallback.
+ &mut post_inlining.codegen_units[0]
+ };
+ dead_code_cgu.make_code_coverage_dead_code_cgu();
+ }
+
// Finally, sort by codegen unit name, so that we get deterministic results.
let PostInliningPartitioning {
codegen_units: mut result,
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 5950806..48b6951 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -267,7 +267,7 @@
self.super_local_decl(local, local_decl);
}
- fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) {
+ fn visit_const(&mut self, c: Const<'tcx>, _: Location) {
c.visit_with(self);
}
@@ -277,22 +277,19 @@
}
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
#[instrument(level = "debug", skip(self))]
- fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.potentially_has_param_types_or_consts() {
+ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if !c.has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
- match c.val {
+ match c.val() {
ty::ConstKind::Param(param) => {
debug!(?param);
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 =>
@@ -306,7 +303,7 @@
ty::ConstKind::Unevaluated(uv)
if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
{
- self.visit_child_body(uv.def.did, uv.substs(self.tcx));
+ self.visit_child_body(uv.def.did, uv.substs);
ControlFlow::CONTINUE
}
_ => c.super_visit_with(self),
@@ -315,7 +312,7 @@
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.potentially_has_param_types_or_consts() {
+ if !ty.has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
@@ -343,25 +340,20 @@
}
/// Visitor used to check if a generic parameter is used.
-struct HasUsedGenericParams<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
+struct HasUsedGenericParams<'a> {
unused_parameters: &'a FiniteBitSet<u32>,
}
-impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
+impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
type BreakTy = ();
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
#[instrument(level = "debug", skip(self))]
- fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.potentially_has_param_types_or_consts() {
+ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if !c.has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
- match c.val {
+ match c.val() {
ty::ConstKind::Param(param) => {
if self.unused_parameters.contains(param.index).unwrap_or(false) {
ControlFlow::CONTINUE
@@ -375,7 +367,7 @@
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.potentially_has_param_types_or_consts() {
+ if !ty.has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index 6084cdd..04baa01 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -8,13 +8,11 @@
/// During the same compile all closures dump the information in the same file
/// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked.
crate fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) {
- let mut file = if let Ok(file) = OpenOptions::new()
+ let Ok(mut file) = OpenOptions::new()
.create(true)
.append(true)
.open(&format!("closure_profile_{}.csv", std::process::id()))
- {
- file
- } else {
+ else {
eprintln!("Cound't open file for writing closure profile");
return;
};
@@ -49,8 +47,7 @@
.map(|l| format!("{:?}", l.size.bytes()))
.unwrap_or_else(|e| format!("Failed {:?}", e));
- let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
- let closure_span = tcx.hir().span(closure_hir_id);
+ let closure_span = tcx.def_span(closure_def_id);
let src_file = tcx.sess.source_map().span_to_filename(closure_span);
let line_nos = tcx
.sess
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 1a62096..4cdd83c 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -158,9 +158,7 @@
Some(match token {
rustc_lexer::TokenKind::LineComment { doc_style } => {
// Skip non-doc comments
- let doc_style = if let Some(doc_style) = doc_style {
- doc_style
- } else {
+ let Some(doc_style) = doc_style else {
self.lint_unicode_text_flow(start);
return None;
};
@@ -185,9 +183,7 @@
}
// Skip non-doc comments
- let doc_style = if let Some(doc_style) = doc_style {
- doc_style
- } else {
+ let Some(doc_style) = doc_style else {
self.lint_unicode_text_flow(start);
return None;
};
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 7f68112..a41956c 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -185,6 +185,15 @@
version control settings",
);
} else {
+ if !mode.is_bytes() {
+ diag.span_suggestion(
+ span_with_quotes,
+ "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
+ format!("r\"{}\"", lit),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
diag.help(
"for more information, visit \
<https://static.rust-lang.org/doc/master/reference.html#literals>",
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 2b1b2f3..eb0d1a1 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -4,6 +4,7 @@
#![feature(crate_visibility_modifier)]
#![feature(if_let_guard)]
#![feature(box_patterns)]
+#![feature(let_else)]
#![recursion_limit = "256"]
#[macro_use]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 9677e76..3d382e5 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1,5 +1,5 @@
use super::pat::Expected;
-use super::ty::AllowPlus;
+use super::ty::{AllowPlus, RecoverQuestionMark};
use super::{
BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep,
TokenExpectType, TokenType,
@@ -27,7 +27,7 @@
use tracing::{debug, trace};
const TURBOFISH_SUGGESTION_STR: &str =
- "use `::<...>` instead of `<...>` to specify type or const arguments";
+ "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident) -> Param {
@@ -192,10 +192,10 @@
if ident.is_raw_guess()
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
{
- err.span_suggestion(
- ident.span,
- "you can escape reserved keywords to use them as identifiers",
- format!("r#{}", ident.name),
+ err.span_suggestion_verbose(
+ ident.span.shrink_to_lo(),
+ &format!("escape `{}` to use it as an identifier", ident.name),
+ "r#".to_owned(),
Applicability::MaybeIncorrect,
);
}
@@ -550,8 +550,8 @@
/// a diagnostic to suggest removing them.
///
/// ```ignore (diagnostic)
- /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
- /// ^^ help: remove extra angle brackets
+ /// let _ = [1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+ /// ^^ help: remove extra angle brackets
/// ```
///
/// If `true` is returned, then trailing brackets were recovered, tokens were consumed
@@ -731,20 +731,21 @@
match x {
Ok((_, _, false)) => {
if self.eat(&token::Gt) {
+ e.span_suggestion_verbose(
+ binop.span.shrink_to_lo(),
+ TURBOFISH_SUGGESTION_STR,
+ "::".to_string(),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
match self.parse_expr() {
Ok(_) => {
- e.span_suggestion_verbose(
- binop.span.shrink_to_lo(),
- TURBOFISH_SUGGESTION_STR,
- "::".to_string(),
- Applicability::MaybeIncorrect,
- );
- e.emit();
*expr =
self.mk_expr_err(expr.span.to(self.prev_token.span));
return Ok(());
}
Err(mut err) => {
+ *expr = self.mk_expr_err(expr.span);
err.cancel();
}
}
@@ -1032,6 +1033,34 @@
}
}
+ /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
+ pub(super) fn maybe_recover_from_question_mark(
+ &mut self,
+ ty: P<Ty>,
+ recover_question_mark: RecoverQuestionMark,
+ ) -> P<Ty> {
+ if let RecoverQuestionMark::No = recover_question_mark {
+ return ty;
+ }
+ if self.token == token::Question {
+ self.bump();
+ self.struct_span_err(self.prev_token.span, "invalid `?` in type")
+ .span_label(self.prev_token.span, "`?` is only allowed on expressions, not types")
+ .multipart_suggestion(
+ "if you meant to express that the type might not contain a value, use the `Option` wrapper type",
+ vec![
+ (ty.span.shrink_to_lo(), "Option<".to_string()),
+ (self.prev_token.span, ">".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
+ } else {
+ ty
+ }
+ }
+
pub(super) fn maybe_recover_from_bad_type_plus(
&mut self,
allow_plus: AllowPlus,
@@ -2127,7 +2156,7 @@
| PatKind::TupleStruct(qself @ None, path, _)
| PatKind::Path(qself @ None, path) => match &first_pat.kind {
PatKind::Ident(_, ident, _) => {
- path.segments.insert(0, PathSegment::from_ident(ident.clone()));
+ path.segments.insert(0, PathSegment::from_ident(*ident));
path.span = new_span;
show_sugg = true;
first_pat = pat;
@@ -2154,8 +2183,8 @@
Path {
span: new_span,
segments: vec![
- PathSegment::from_ident(old_ident.clone()),
- PathSegment::from_ident(ident.clone()),
+ PathSegment::from_ident(*old_ident),
+ PathSegment::from_ident(*ident),
],
tokens: None,
},
@@ -2165,7 +2194,7 @@
}
PatKind::Path(old_qself, old_path) => {
let mut segments = old_path.segments.clone();
- segments.push(PathSegment::from_ident(ident.clone()));
+ segments.push(PathSegment::from_ident(*ident));
let path = PatKind::Path(
old_qself.clone(),
Path { span: new_span, segments, tokens: None },
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index f706a98..e9aa4ad 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -682,7 +682,7 @@
// Save the state of the parser before parsing type normally, in case there is a
// LessThan comparison after this cast.
let parser_snapshot_before_type = self.clone();
- let cast_expr = match self.parse_ty_no_plus() {
+ let cast_expr = match self.parse_as_cast_ty() {
Ok(rhs) => mk_expr(self, lhs, rhs),
Err(mut type_err) => {
// Rewind to before attempting to parse the type with generics, to recover
@@ -808,7 +808,7 @@
"casts cannot be followed by {}",
match with_postfix.kind {
ExprKind::Index(_, _) => "indexing",
- ExprKind::Try(_) => "?",
+ ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_, _, _) => "a method call",
ExprKind::Call(_, _) => "a function call",
@@ -1443,7 +1443,7 @@
&mut self,
label: Label,
attrs: AttrVec,
- consume_colon: bool,
+ mut consume_colon: bool,
) -> PResult<'a, P<Expr>> {
let lo = label.ident.span;
let label = Some(label);
@@ -1456,6 +1456,12 @@
self.parse_loop_expr(label, lo, attrs)
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
+ } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
+ // We're probably inside of a `Path<'a>` that needs a turbofish
+ let msg = "expected `while`, `for`, `loop` or `{` after a label";
+ self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
+ consume_colon = false;
+ Ok(self.mk_expr_err(lo))
} else {
let msg = "expected `while`, `for`, `loop` or `{` after a label";
self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
@@ -1694,6 +1700,19 @@
s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
}
+ // Try to lowercase the prefix if it's a valid base prefix.
+ fn fix_base_capitalisation(s: &str) -> Option<String> {
+ if let Some(stripped) = s.strip_prefix('B') {
+ Some(format!("0b{stripped}"))
+ } else if let Some(stripped) = s.strip_prefix('O') {
+ Some(format!("0o{stripped}"))
+ } else if let Some(stripped) = s.strip_prefix('X') {
+ Some(format!("0x{stripped}"))
+ } else {
+ None
+ }
+ }
+
let token::Lit { kind, suffix, .. } = lit;
match err {
// `NotLiteral` is not an error by itself, so we don't report
@@ -1718,6 +1737,18 @@
self.struct_span_err(span, &msg)
.help("valid widths are 8, 16, 32, 64 and 128")
.emit();
+ } else if let Some(fixed) = fix_base_capitalisation(suf) {
+ let msg = "invalid base prefix for number literal";
+
+ self.struct_span_err(span, &msg)
+ .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")
+ .span_suggestion(
+ span,
+ "try making the prefix lowercase",
+ fixed,
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
} else {
let msg = format!("invalid suffix `{}` for number literal", suf);
self.struct_span_err(span, &msg)
@@ -2377,6 +2408,17 @@
}
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
+ fn check_let_expr(expr: &Expr) -> (bool, bool) {
+ match expr.kind {
+ ExprKind::Binary(_, ref lhs, ref rhs) => {
+ let lhs_rslt = check_let_expr(lhs);
+ let rhs_rslt = check_let_expr(rhs);
+ (lhs_rslt.0 || rhs_rslt.0, false)
+ }
+ ExprKind::Let(..) => (true, true),
+ _ => (false, true),
+ }
+ }
let attrs = self.parse_outer_attributes()?;
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
@@ -2384,9 +2426,12 @@
let guard = if this.eat_keyword(kw::If) {
let if_span = this.prev_token.span;
let cond = this.parse_expr()?;
- if let ExprKind::Let(..) = cond.kind {
- // Remove the last feature gating of a `let` expression since it's stable.
- this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+ let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
+ if has_let_expr {
+ if does_not_have_bin_op {
+ // Remove the last feature gating of a `let` expression since it's stable.
+ this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+ }
let span = if_span.to(cond.span);
this.sess.gated_spans.gate(sym::if_let_guard, span);
}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 419ea9c..4b57aa1 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -4,7 +4,7 @@
use rustc_ast::{
self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
};
-use rustc_errors::PResult;
+use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::kw;
impl<'a> Parser<'a> {
@@ -256,7 +256,21 @@
break;
}
- if !self.eat(&token::Comma) {
+ let prev_token = self.prev_token.span;
+ let ate_comma = self.eat(&token::Comma);
+
+ if self.eat_keyword_noexpect(kw::Where) {
+ let msg = "cannot define duplicate `where` clauses on an item";
+ let mut err = self.struct_span_err(self.token.span, msg);
+ err.span_label(lo, "previous `where` clause starts here");
+ err.span_suggestion_verbose(
+ prev_token.shrink_to_hi().to(self.prev_token.span),
+ "consider joining the two `where` clauses into one",
+ ",".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ } else if !ate_comma {
break;
}
}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ade441b..93f5d79 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -423,7 +423,7 @@
// Maybe the user misspelled `macro_rules` (issue #91227)
if self.token.is_ident()
&& path.segments.len() == 1
- && lev_distance("macro_rules", &path.segments[0].ident.to_string()) <= 3
+ && lev_distance("macro_rules", &path.segments[0].ident.to_string(), 3).is_some()
{
err.span_suggestion(
path.span,
@@ -1221,7 +1221,7 @@
let struct_def = if this.check(&token::OpenDelim(token::Brace)) {
// Parse a struct variant.
- let (fields, recovered) = this.parse_record_struct_body("struct")?;
+ let (fields, recovered) = this.parse_record_struct_body("struct", false)?;
VariantData::Struct(fields, recovered)
} else if this.check(&token::OpenDelim(token::Paren)) {
VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
@@ -1275,7 +1275,8 @@
VariantData::Unit(DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
- let (fields, recovered) = self.parse_record_struct_body("struct")?;
+ let (fields, recovered) =
+ self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
VariantData::Struct(fields, recovered)
}
// No `where` so: `struct Foo<T>;`
@@ -1283,7 +1284,8 @@
VariantData::Unit(DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(token::Brace) {
- let (fields, recovered) = self.parse_record_struct_body("struct")?;
+ let (fields, recovered) =
+ self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
VariantData::Struct(fields, recovered)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(token::Paren) {
@@ -1313,10 +1315,12 @@
let vdata = if self.token.is_keyword(kw::Where) {
generics.where_clause = self.parse_where_clause()?;
- let (fields, recovered) = self.parse_record_struct_body("union")?;
+ let (fields, recovered) =
+ self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
VariantData::Struct(fields, recovered)
} else if self.token == token::OpenDelim(token::Brace) {
- let (fields, recovered) = self.parse_record_struct_body("union")?;
+ let (fields, recovered) =
+ self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
VariantData::Struct(fields, recovered)
} else {
let token_str = super::token_descr(&self.token);
@@ -1332,6 +1336,7 @@
fn parse_record_struct_body(
&mut self,
adt_ty: &str,
+ parsed_where: bool,
) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
let mut fields = Vec::new();
let mut recovered = false;
@@ -1353,9 +1358,19 @@
self.eat(&token::CloseDelim(token::Brace));
} else {
let token_str = super::token_descr(&self.token);
- let msg = &format!("expected `where`, or `{{` after struct name, found {}", token_str);
+ let msg = &format!(
+ "expected {}`{{` after struct name, found {}",
+ if parsed_where { "" } else { "`where`, or " },
+ token_str
+ );
let mut err = self.struct_span_err(self.token.span, msg);
- err.span_label(self.token.span, "expected `where`, or `{` after struct name");
+ err.span_label(
+ self.token.span,
+ format!(
+ "expected {}`{{` after struct name",
+ if parsed_where { "" } else { "`where`, or " }
+ ),
+ );
return Err(err);
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 72e6f8a..d9ec618 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -140,7 +140,7 @@
}
NonterminalKind::Ty => {
- token::NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty())?)
+ token::NtTy(self.collect_tokens_no_attrs(|this| this.parse_no_question_mark_recover())?)
}
// this could be handled like a token, since it is one
NonterminalKind::Ident
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 7f8fadb..4850211 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -4,8 +4,8 @@
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
use rustc_ast::{
- self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
- AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
+ AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf,
};
use rustc_errors::{pluralize, Applicability, PResult};
@@ -139,22 +139,46 @@
style: PathStyle,
ty_generics: Option<&Generics>,
) -> PResult<'a, Path> {
- maybe_whole!(self, NtPath, |path| {
+ let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| {
+ // Ensure generic arguments don't end up in attribute paths, such as:
+ //
+ // macro_rules! m {
+ // ($p:path) => { #[$p] struct S; }
+ // }
+ //
+ // m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
+ //
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
- self.struct_span_err(
- path.segments
- .iter()
- .filter_map(|segment| segment.args.as_ref())
- .map(|arg| arg.span())
- .collect::<Vec<_>>(),
- "unexpected generic arguments in path",
- )
- .emit();
+ parser
+ .struct_span_err(
+ path.segments
+ .iter()
+ .filter_map(|segment| segment.args.as_ref())
+ .map(|arg| arg.span())
+ .collect::<Vec<_>>(),
+ "unexpected generic arguments in path",
+ )
+ .emit();
}
+ };
+
+ maybe_whole!(self, NtPath, |path| {
+ reject_generics_if_mod_style(self, &path);
path
});
+ if let token::Interpolated(nt) = &self.token.kind {
+ if let token::NtTy(ty) = &**nt {
+ if let ast::TyKind::Path(None, path) = &ty.kind {
+ let path = path.clone();
+ self.bump();
+ reject_generics_if_mod_style(self, &path);
+ return Ok(path);
+ }
+ }
+ }
+
let lo = self.token.span;
let mut segments = Vec::new();
let mod_sep_ctxt = self.token.span.ctxt();
@@ -469,12 +493,9 @@
// Parse associated type constraint bound.
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
- AssocTyConstraintKind::Bound { bounds }
+ AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
- // Parse associated type equality constraint
-
- let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
- AssocTyConstraintKind::Equality { ty }
+ self.parse_assoc_equality_term(ident, self.prev_token.span)?
} else {
unreachable!();
};
@@ -482,11 +503,11 @@
let span = lo.to(self.prev_token.span);
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
- if let AssocTyConstraintKind::Bound { .. } = kind {
+ if let AssocConstraintKind::Bound { .. } = kind {
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
}
let constraint =
- AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
+ AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
Ok(Some(AngleBracketedArg::Constraint(constraint)))
} else {
Ok(Some(AngleBracketedArg::Arg(arg)))
@@ -499,22 +520,25 @@
/// Parse the term to the right of an associated item equality constraint.
/// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<term>`.
- fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
+ fn parse_assoc_equality_term(
+ &mut self,
+ ident: Ident,
+ eq: Span,
+ ) -> PResult<'a, AssocConstraintKind> {
let arg = self.parse_generic_arg(None)?;
let span = ident.span.to(self.prev_token.span);
- match arg {
- Some(GenericArg::Type(ty)) => return Ok(ty),
- Some(GenericArg::Const(expr)) => {
- self.struct_span_err(span, "cannot constrain an associated constant to a value")
- .span_label(ident.span, "this associated constant...")
- .span_label(expr.value.span, "...cannot be constrained to this value")
- .emit();
+ let term = match arg {
+ Some(GenericArg::Type(ty)) => ty.into(),
+ Some(GenericArg::Const(c)) => {
+ self.sess.gated_spans.gate(sym::associated_const_equality, span);
+ c.into()
}
Some(GenericArg::Lifetime(lt)) => {
self.struct_span_err(span, "associated lifetimes are not supported")
.span_label(lt.ident.span, "the lifetime is given here")
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
.emit();
+ self.mk_ty(span, ast::TyKind::Err).into()
}
None => {
let after_eq = eq.shrink_to_hi();
@@ -542,8 +566,8 @@
};
return Err(err);
}
- }
- Ok(self.mk_ty(span, ast::TyKind::Err))
+ };
+ Ok(AssocConstraintKind::Equality { term })
}
/// We do not permit arbitrary expressions as const arguments. They must be one of:
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 02a774b..89595c3 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -44,6 +44,11 @@
No,
}
+pub(super) enum RecoverQuestionMark {
+ Yes,
+ No,
+}
+
/// Signals whether parsing a type should recover `->`.
///
/// More specifically, when parsing a function like:
@@ -100,6 +105,7 @@
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
+ RecoverQuestionMark::Yes,
)
}
@@ -113,6 +119,7 @@
RecoverQPath::Yes,
RecoverReturnSign::Yes,
Some(ty_params),
+ RecoverQuestionMark::Yes,
)
}
@@ -126,6 +133,7 @@
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
+ RecoverQuestionMark::Yes,
)
}
@@ -142,6 +150,31 @@
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
+ RecoverQuestionMark::Yes,
+ )
+ }
+
+ /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin
+ /// for better diagnostics involving `?`.
+ pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::No,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ None,
+ RecoverQuestionMark::No,
+ )
+ }
+
+ pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ None,
+ RecoverQuestionMark::No,
)
}
@@ -153,6 +186,7 @@
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
None,
+ RecoverQuestionMark::Yes,
)
}
@@ -171,6 +205,7 @@
recover_qpath,
recover_return_sign,
None,
+ RecoverQuestionMark::Yes,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
@@ -191,6 +226,7 @@
recover_qpath,
recover_return_sign,
None,
+ RecoverQuestionMark::Yes,
)?;
FnRetTy::Ty(ty)
} else {
@@ -205,6 +241,7 @@
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
ty_generics: Option<&Generics>,
+ recover_question_mark: RecoverQuestionMark,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -280,6 +317,7 @@
// Try to recover from use of `+` with incorrect priority.
self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
+ let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark);
self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
}
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 9d653de..a6a2cbc 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -95,7 +95,7 @@
/// The argument is located at a specific index given in the format
ArgumentIs(usize),
/// The argument has a name.
- ArgumentNamed(Symbol),
+ ArgumentNamed(Symbol, InnerSpan),
}
impl Position {
@@ -147,7 +147,7 @@
/// The count is specified explicitly.
CountIs(usize),
/// The count is specified by the argument with the given name.
- CountIsName(Symbol),
+ CountIsName(Symbol, InnerSpan),
/// The count is specified by the argument at the given index.
CountIsParam(usize),
/// The count is implied and cannot be explicitly specified.
@@ -494,8 +494,11 @@
Some(ArgumentIs(i))
} else {
match self.cur.peek() {
- Some(&(_, c)) if rustc_lexer::is_id_start(c) => {
- Some(ArgumentNamed(Symbol::intern(self.word())))
+ Some(&(start, c)) if rustc_lexer::is_id_start(c) => {
+ let word = self.word();
+ let end = start + word.len();
+ let span = self.to_span_index(start).to(self.to_span_index(end));
+ Some(ArgumentNamed(Symbol::intern(word), span))
}
// This is an `ArgumentNext`.
@@ -662,8 +665,9 @@
if word.is_empty() {
self.cur = tmp;
(CountImplied, None)
- } else if self.consume('$') {
- (CountIsName(Symbol::intern(word)), None)
+ } else if let Some(end) = self.consume_pos('$') {
+ let span = self.to_span_index(start + 1).to(self.to_span_index(end));
+ (CountIsName(Symbol::intern(word), span), None)
} else {
self.cur = tmp;
(CountImplied, None)
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index b7693a8..6c960fd 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -221,8 +221,8 @@
fill: None,
align: AlignUnknown,
flags: 0,
- precision: CountIsName(Symbol::intern("b")),
- width: CountIsName(Symbol::intern("a")),
+ precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)),
+ width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)),
precision_span: None,
width_span: None,
ty: "?",
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d7b0069..479a08e 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,19 +4,18 @@
//! conflicts between multiple such attributes attached to the same
//! item.
-use rustc_middle::hir::map::Map;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
-
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
use rustc_hir::{MethodKind, Target};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
};
@@ -32,7 +31,7 @@
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Fn(..) => {
- let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id()).expect_owner();
+ let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
@@ -63,7 +62,7 @@
fn check_attributes(
&self,
hir_id: HirId,
- span: &Span,
+ span: Span,
target: Target,
item: Option<ItemLike<'_>>,
) {
@@ -77,9 +76,12 @@
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),
+ sym::rustc_must_implement_one_of => {
+ self.check_rustc_must_implement_one_of(attr, span, target)
+ }
sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
sym::track_caller => {
- self.check_track_caller(hir_id, &attr.span, attrs, span, target)
+ self.check_track_caller(hir_id, attr.span, attrs, span, target)
}
sym::doc => self.check_doc_attrs(
attr,
@@ -104,6 +106,9 @@
sym::rustc_legacy_const_generics => {
self.check_rustc_legacy_const_generics(&attr, span, target, item)
}
+ sym::rustc_lint_query_instability => {
+ self.check_rustc_lint_query_instability(&attr, span, target)
+ }
sym::rustc_clean
| sym::rustc_dirty
| sym::rustc_if_this_changed
@@ -114,6 +119,7 @@
}
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
sym::must_use => self.check_must_use(hir_id, &attr, span, target),
+ sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
sym::rustc_const_unstable
| sym::rustc_const_stable
| sym::unstable
@@ -126,6 +132,7 @@
// lint-only checks
match attr.name_or_empty() {
sym::cold => self.check_cold(hir_id, attr, span, target),
+ sym::link => self.check_link(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),
@@ -134,7 +141,6 @@
}
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 => {
@@ -250,7 +256,7 @@
}
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
- fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Closure
@@ -293,7 +299,7 @@
E0518,
"attribute should be applied to function or closure",
)
- .span_label(*span, "not a function or closure")
+ .span_label(span, "not a function or closure")
.emit();
false
}
@@ -332,7 +338,7 @@
}
/// Checks if `#[naked]` is applied to a function definition.
- fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
@@ -351,7 +357,7 @@
attr.span,
"attribute should be applied to a function definition",
)
- .span_label(*span, "not a function definition")
+ .span_label(span, "not a function definition")
.emit();
false
}
@@ -359,7 +365,7 @@
}
/// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition.
- fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
@@ -370,7 +376,7 @@
attr.span,
"attribute should be applied to a function definition",
)
- .span_label(*span, "not a function definition")
+ .span_label(span, "not a function definition")
.emit();
false
}
@@ -381,16 +387,16 @@
fn check_track_caller(
&self,
hir_id: HirId,
- attr_span: &Span,
+ attr_span: Span,
attrs: &[Attribute],
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
match target {
_ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
struct_span_err!(
self.tcx.sess,
- *attr_span,
+ attr_span,
E0736,
"cannot use `#[track_caller]` with `#[naked]`",
)
@@ -411,11 +417,11 @@
_ => {
struct_span_err!(
self.tcx.sess,
- *attr_span,
+ attr_span,
E0739,
"attribute should be applied to function"
)
- .span_label(*span, "not a function")
+ .span_label(span, "not a function")
.emit();
false
}
@@ -427,7 +433,7 @@
&self,
hir_id: HirId,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
match target {
@@ -447,7 +453,7 @@
E0701,
"attribute can only be applied to a struct or enum"
)
- .span_label(*span, "not a struct or enum")
+ .span_label(span, "not a struct or enum")
.emit();
false
}
@@ -455,7 +461,7 @@
}
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
- fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::Trait => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -470,7 +476,27 @@
self.tcx
.sess
.struct_span_err(attr.span, "attribute can only be applied to a trait")
- .span_label(*span, "not a trait")
+ .span_label(span, "not a trait")
+ .emit();
+ false
+ }
+ }
+ }
+
+ /// Checks if the `#[rustc_must_implement_one_of]` attribute on a `target` is valid. Returns `true` if valid.
+ fn check_rustc_must_implement_one_of(
+ &self,
+ attr: &Attribute,
+ span: Span,
+ target: Target,
+ ) -> bool {
+ match target {
+ Target::Trait => true,
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(attr.span, "attribute can only be applied to a trait")
+ .span_label(span, "not a trait")
.emit();
false
}
@@ -482,7 +508,7 @@
&self,
hir_id: HirId,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
match target {
@@ -498,7 +524,7 @@
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(*span, "not a function")
+ .span_label(span, "not a function")
.emit();
});
true
@@ -515,7 +541,7 @@
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(*span, "not a function")
+ .span_label(span, "not a function")
.emit();
false
}
@@ -582,7 +608,7 @@
Target::Impl => Some("implementation block"),
Target::ForeignMod => Some("extern block"),
Target::AssocTy => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
if Target::from_item(containing_item) == Target::Impl {
Some("type alias in implementation block")
@@ -591,7 +617,7 @@
}
}
Target::AssocConst => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
// We can't link to trait impl's consts.
let err = "associated constant in trait implementation block";
@@ -832,7 +858,7 @@
let mut err = lint.build(
"this attribute can only be applied at the crate level",
);
- if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_HIR_ID {
+ if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID {
if let Ok(mut src) =
self.tcx.sess.source_map().span_to_snippet(attr.span)
{
@@ -1066,14 +1092,26 @@
is_valid
}
+ /// Warns against some misuses of `#[pass_by_value]`
+ fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+ match target {
+ Target::Struct | Target::Enum | Target::TyAlias => true,
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(
+ attr.span,
+ "`pass_by_value` attribute should be applied to a struct, enum or type alias.",
+ )
+ .span_label(span, "is not a struct, enum or type alias")
+ .emit();
+ false
+ }
+ }
+ }
+
/// Warns against some misuses of `#[must_use]`
- fn check_must_use(
- &self,
- hir_id: HirId,
- attr: &Attribute,
- span: &Span,
- _target: Target,
- ) -> bool {
+ fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, _target: Target) -> bool {
let node = self.tcx.hir().get(hir_id);
if let Some(fn_node) = node.fn_kind() {
if let rustc_hir::IsAsync::Async = fn_node.asyncness() {
@@ -1084,7 +1122,7 @@
function, not the value within",
)
.span_label(
- *span,
+ span,
"this attribute does nothing, the `Future`s \
returned by async functions are already `must_use`",
)
@@ -1098,14 +1136,14 @@
}
/// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
- fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
_ => {
self.tcx
.sess
.struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
- .span_label(*span, "is not a struct, enum, or trait")
+ .span_label(span, "is not a struct, enum, or trait")
.emit();
false
}
@@ -1113,7 +1151,7 @@
}
/// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
- fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
+ fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
match target {
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1133,15 +1171,35 @@
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(*span, "not a function")
+ .span_label(span, "not a function")
.emit();
});
}
}
}
+ /// Checks if `#[link]` is applied to an item other than a foreign module.
+ fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+ match target {
+ Target::ForeignMod => {}
+ _ => {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ let mut diag = lint.build("attribute should be applied to an `extern` block");
+ diag.warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ );
+
+ diag.span_label(span, "not an `extern` block");
+ diag.emit();
+ });
+ }
+ }
+ }
+
/// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
- fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
+ fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
match target {
Target::ForeignFn | Target::ForeignStatic => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1175,7 +1233,7 @@
}
}
- diag.span_label(*span, "not a foreign function or static");
+ diag.span_label(span, "not a foreign function or static");
diag.emit();
});
}
@@ -1183,7 +1241,7 @@
}
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
- fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::ExternCrate => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1201,7 +1259,7 @@
attr.span,
"attribute should be applied to an `extern crate` item",
)
- .span_label(*span, "not an `extern crate` item")
+ .span_label(span, "not an `extern crate` item")
.emit();
false
}
@@ -1217,7 +1275,7 @@
&self,
hir_id: HirId,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
match target {
@@ -1238,7 +1296,7 @@
attr.span,
"attribute should be applied to a free function, impl method or static",
)
- .span_label(*span, "not a free function, impl method or static")
+ .span_label(span, "not a free function, impl method or static")
.emit();
false
}
@@ -1248,14 +1306,14 @@
fn check_rustc_layout_scalar_valid_range(
&self,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
if target != Target::Struct {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a struct")
- .span_label(*span, "not a struct")
+ .span_label(span, "not a struct")
.emit();
return false;
}
@@ -1280,7 +1338,7 @@
fn check_rustc_legacy_const_generics(
&self,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
item: Option<ItemLike<'_>>,
) -> bool {
@@ -1289,7 +1347,7 @@
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(*span, "not a function")
+ .span_label(span, "not a function")
.emit();
return false;
}
@@ -1375,6 +1433,25 @@
}
}
+ fn check_rustc_lint_query_instability(
+ &self,
+ attr: &Attribute,
+ span: Span,
+ target: Target,
+ ) -> bool {
+ let is_function = matches!(target, Target::Fn | Target::Method(..));
+ if !is_function {
+ self.tcx
+ .sess
+ .struct_span_err(attr.span, "attribute should be applied to a function")
+ .span_label(span, "not a function")
+ .emit();
+ false
+ } else {
+ true
+ }
+ }
+
/// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
/// option is passed to the compiler.
fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
@@ -1390,7 +1467,7 @@
}
/// Checks if `#[link_section]` is applied to a function or static.
- fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
+ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1410,7 +1487,7 @@
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(*span, "not a function or static")
+ .span_label(span, "not a function or static")
.emit();
});
}
@@ -1418,7 +1495,7 @@
}
/// 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) {
+ fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
match target {
Target::Static | Target::Fn => {}
Target::Method(..) if self.is_impl_item(hir_id) => {}
@@ -1448,7 +1525,7 @@
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(*span, format!("foreign {}", foreign_item_kind))
+ .span_label(span, format!("foreign {}", foreign_item_kind))
.note("symbol names in extern blocks are not mangled")
.span_suggestion(
attr.span,
@@ -1471,7 +1548,7 @@
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(*span, "not a free function, impl method or static")
+ .span_label(span, "not a free function, impl method or static")
.emit();
});
}
@@ -1482,7 +1559,7 @@
fn check_repr(
&self,
attrs: &[Attribute],
- span: &Span,
+ span: Span,
target: Target,
item: Option<ItemLike<'_>>,
hir_id: HirId,
@@ -1616,7 +1693,7 @@
"{}",
&format!("attribute should be applied to {} {}", article, allowed_targets)
)
- .span_label(*span, &format!("not {} {}", article, allowed_targets))
+ .span_label(span, &format!("not {} {}", article, allowed_targets))
.emit();
}
@@ -1664,12 +1741,46 @@
}
fn check_used(&self, attrs: &[Attribute], target: Target) {
+ let mut used_linker_span = None;
+ let mut used_compiler_span = None;
for attr in attrs {
if attr.has_name(sym::used) && target != Target::Static {
self.tcx
.sess
.span_err(attr.span, "attribute must be applied to a `static` variable");
}
+ let inner = attr.meta_item_list();
+ match inner.as_deref() {
+ Some([item]) if item.has_name(sym::linker) => {
+ if used_linker_span.is_none() {
+ used_linker_span = Some(attr.span);
+ }
+ }
+ Some([item]) if item.has_name(sym::compiler) => {
+ if used_compiler_span.is_none() {
+ used_compiler_span = Some(attr.span);
+ }
+ }
+ Some(_) => {
+ // This error case is handled in rustc_typeck::collect.
+ }
+ None => {
+ // Default case (compiler) when arg isn't defined.
+ if used_compiler_span.is_none() {
+ used_compiler_span = Some(attr.span);
+ }
+ }
+ }
+ }
+ if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
+ let spans = vec![linker_span, compiler_span];
+ self.tcx
+ .sess
+ .struct_span_err(
+ spans,
+ "`used(compiler)` and `used(linker)` can't be used together",
+ )
+ .emit();
}
}
@@ -1679,7 +1790,7 @@
&self,
hir_id: HirId,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
attrs: &[Attribute],
) -> bool {
@@ -1712,7 +1823,7 @@
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a macro")
- .span_label(*span, "not a macro")
+ .span_label(span, "not a macro")
.emit();
false
}
@@ -1725,7 +1836,7 @@
&self,
hir_id: HirId,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
match target {
@@ -1746,7 +1857,7 @@
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to `const fn`")
- .span_label(*span, "not a `const fn`")
+ .span_label(span, "not a `const fn`")
.emit();
false
}
@@ -1757,7 +1868,7 @@
fn check_default_method_body_is_const(
&self,
attr: &Attribute,
- span: &Span,
+ span: Span,
target: Target,
) -> bool {
match target {
@@ -1769,14 +1880,14 @@
attr.span,
"attribute should be applied to a trait method with body",
)
- .span_label(*span, "not a trait method or missing a body")
+ .span_label(span, "not a trait method or missing a body")
.emit();
false
}
}
}
- fn check_stability_promotable(&self, attr: &Attribute, _span: &Span, target: Target) -> bool {
+ fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
match target {
Target::Expression => {
self.tcx
@@ -1789,7 +1900,7 @@
}
}
- fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: &Span, target: Target) {
+ 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| {
@@ -1823,16 +1934,6 @@
}
}
- 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| {
@@ -1843,10 +1944,10 @@
}
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
@@ -1861,29 +1962,29 @@
}
let target = Target::from_item(item);
- self.check_attributes(item.hir_id(), &item.span, target, Some(ItemLike::Item(item)));
+ self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
intravisit::walk_item(self, item)
}
fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
let target = Target::from_generic_param(generic_param);
- self.check_attributes(generic_param.hir_id, &generic_param.span, target, None);
+ self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
intravisit::walk_generic_param(self, generic_param)
}
fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
let target = Target::from_trait_item(trait_item);
- self.check_attributes(trait_item.hir_id(), &trait_item.span, target, None);
+ self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
intravisit::walk_trait_item(self, trait_item)
}
fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
- self.check_attributes(struct_field.hir_id, &struct_field.span, Target::Field, None);
+ self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
intravisit::walk_field_def(self, struct_field);
}
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
- self.check_attributes(arm.hir_id, &arm.span, Target::Arm, None);
+ self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
intravisit::walk_arm(self, arm);
}
@@ -1891,7 +1992,7 @@
let target = Target::from_foreign_item(f_item);
self.check_attributes(
f_item.hir_id(),
- &f_item.span,
+ f_item.span,
target,
Some(ItemLike::ForeignItem(f_item)),
);
@@ -1900,14 +2001,14 @@
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
let target = target_from_impl_item(self.tcx, impl_item);
- self.check_attributes(impl_item.hir_id(), &impl_item.span, target, None);
+ self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
intravisit::walk_impl_item(self, impl_item)
}
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
// When checking statements ignore expressions, they will be checked later.
if let hir::StmtKind::Local(ref l) = stmt.kind {
- self.check_attributes(l.hir_id, &stmt.span, Target::Statement, None);
+ self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
}
intravisit::walk_stmt(self, stmt)
}
@@ -1918,7 +2019,7 @@
_ => Target::Expression,
};
- self.check_attributes(expr.hir_id, &expr.span, target, None);
+ self.check_attributes(expr.hir_id, expr.span, target, None);
intravisit::walk_expr(self, expr)
}
@@ -1928,12 +2029,12 @@
generics: &'tcx hir::Generics<'tcx>,
item_id: HirId,
) {
- self.check_attributes(variant.id, &variant.span, Target::Variant, None);
+ self.check_attributes(variant.id, variant.span, Target::Variant, None);
intravisit::walk_variant(self, variant, generics, item_id)
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
- self.check_attributes(param.hir_id, ¶m.span, Target::Param, None);
+ self.check_attributes(param.hir_id, param.span, Target::Param, None);
intravisit::walk_param(self, param);
}
@@ -2025,7 +2126,7 @@
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
if module_def_id.is_top_level_module() {
- check_attr_visitor.check_attributes(CRATE_HIR_ID, &DUMMY_SP, Target::Mod, None);
+ 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 a5a6574..2b11f6b 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -11,8 +11,8 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_middle::hir::map::Map;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
@@ -93,26 +93,29 @@
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
{
if let ty::AssocItem {
- kind: ty::AssocKind::Fn, ident, defaultness, ..
- } = trait_item
+ kind: ty::AssocKind::Fn,
+ defaultness,
+ def_id: trait_item_id,
+ ..
+ } = *trait_item
{
// we can ignore functions that do not have default bodies:
// if those are unimplemented it will be catched by typeck.
if !defaultness.has_value()
|| self
.tcx
- .has_attr(trait_item.def_id, sym::default_method_body_is_const)
+ .has_attr(trait_item_id, sym::default_method_body_is_const)
{
continue;
}
let is_implemented = ancestors
- .leaf_def(self.tcx, trait_item.ident, trait_item.kind)
+ .leaf_def(self.tcx, trait_item_id)
.map(|node_item| !node_item.defining_node.is_from_trait())
.unwrap_or(false);
if !is_implemented {
- to_implement.push(ident.to_string());
+ to_implement.push(self.tcx.item_name(trait_item_id).to_string());
}
}
}
@@ -259,10 +262,10 @@
}
impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 3b15332..e52fbc8 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -3,18 +3,21 @@
// from live codes are live, and everything else is dead.
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::pluralize;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{Node, PatKind, TyKind};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy;
+use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
use std::mem;
// Any local node that may call something in its body block should be
@@ -23,7 +26,7 @@
// may need to be marked as live.
fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
matches!(
- tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)),
+ tcx.hir().find_by_def_id(def_id),
Some(
Node::Item(..)
| Node::ImplItem(..)
@@ -47,6 +50,10 @@
ignore_variant_stack: Vec<DefId>,
// maps from tuple struct constructors to tuple struct items
struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
+ // maps from ADTs to ignored derived traits (e.g. Debug and Clone)
+ // and the span of their respective impl (i.e., part of the derive
+ // macro)
+ ignored_derived_traits: FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
}
impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -97,7 +104,7 @@
self.check_def_id(variant_id);
}
}
- Res::SelfTy(t, i) => {
+ Res::SelfTy { trait_: t, alias_to: i } => {
if let Some(t) = t {
self.check_def_id(t);
}
@@ -232,7 +239,7 @@
// tuple struct constructor function
let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
- if let Some(node) = self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(id)) {
+ if let Some(node) = self.tcx.hir().find_by_def_id(id) {
self.live_symbols.insert(id);
self.visit_node(node);
}
@@ -242,7 +249,7 @@
/// Automatically generated items marked with `rustc_trivial_field_reads`
/// will be ignored for the purposes of dead code analysis (see PR #85200
/// for discussion).
- fn should_ignore_item(&self, def_id: DefId) -> bool {
+ fn should_ignore_item(&mut self, def_id: DefId) -> bool {
if let Some(impl_of) = self.tcx.impl_of_method(def_id) {
if !self.tcx.has_attr(impl_of, sym::automatically_derived) {
return false;
@@ -250,6 +257,15 @@
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
+ let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+ if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
+ if let Some(adt_def_id) = adt_def.did.as_local() {
+ self.ignored_derived_traits
+ .entry(adt_def_id)
+ .or_default()
+ .push((trait_of, impl_of));
+ }
+ }
return true;
}
}
@@ -323,12 +339,6 @@
}
impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_nested_body(&mut self, body: hir::BodyId) {
let old_maybe_typeck_results =
self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
@@ -456,7 +466,10 @@
// #[used], #[no_mangle], #[export_name], etc also keeps the item alive
// forcefully, e.g., for placing it in a specific section.
- if cg_attrs.contains_extern_indicator() || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) {
+ if cg_attrs.contains_extern_indicator()
+ || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
+ || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+ {
return true;
}
@@ -553,8 +566,8 @@
fn create_and_seed_worklist<'tcx>(
tcx: TyCtxt<'tcx>,
- access_levels: &privacy::AccessLevels,
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
+ let access_levels = &tcx.privacy_access_levels(());
let worklist = access_levels
.map
.iter()
@@ -574,11 +587,11 @@
(life_seeder.worklist, life_seeder.struct_constructors)
}
-fn find_live<'tcx>(
+fn live_symbols_and_ignored_derived_traits<'tcx>(
tcx: TyCtxt<'tcx>,
- access_levels: &privacy::AccessLevels,
-) -> FxHashSet<LocalDefId> {
- let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels);
+ (): (),
+) -> (FxHashSet<LocalDefId>, FxHashMap<LocalDefId, Vec<(DefId, DefId)>>) {
+ let (worklist, struct_constructors) = create_and_seed_worklist(tcx);
let mut symbol_visitor = MarkSymbolVisitor {
worklist,
tcx,
@@ -590,14 +603,16 @@
pub_visibility: false,
ignore_variant_stack: vec![],
struct_constructors,
+ ignored_derived_traits: FxHashMap::default(),
};
symbol_visitor.mark_live_symbols();
- symbol_visitor.live_symbols
+ (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
}
struct DeadVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- live_symbols: FxHashSet<LocalDefId>,
+ live_symbols: &'tcx FxHashSet<LocalDefId>,
+ ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
}
impl<'tcx> DeadVisitor<'tcx> {
@@ -666,21 +681,52 @@
self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
let def_id = self.tcx.hir().local_def_id(id);
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
- lint.build(&format!("{} is never {}: `{}`", descr, participle, name)).emit()
+ let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name));
+ let hir = self.tcx.hir();
+ if let Some(encl_scope) = hir.get_enclosing_scope(id) {
+ if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) {
+ if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
+ let traits_str = ign_traits
+ .iter()
+ .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
+ .collect::<Vec<_>>()
+ .join(" and ");
+ let plural_s = pluralize!(ign_traits.len());
+ let article = if ign_traits.len() > 1 { "" } else { "a " };
+ let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
+ let msg = format!(
+ "`{}` has {}derived impl{} for the trait{} {}, but {} \
+ intentionally ignored during dead code analysis",
+ self.tcx.item_name(encl_def_id.to_def_id()),
+ article,
+ plural_s,
+ plural_s,
+ traits_str,
+ is_are
+ );
+ let multispan = ign_traits
+ .iter()
+ .map(|(_, impl_id)| self.tcx.def_span(*impl_id))
+ .collect::<Vec<_>>();
+ err.span_note(multispan, &msg);
+ }
+ }
+ }
+ err.emit();
});
}
}
}
impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
/// Walk nested items in place so that we don't report dead-code
/// on inner functions when the outer function is already getting
/// an error. We could do this also by checking the parents, but
/// this is how the code is setup and it seems harmless enough.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -719,6 +765,9 @@
}
}
+ // This visitor should only visit a single module at a time.
+ fn visit_mod(&mut self, _: &'tcx hir::Mod<'tcx>, _: Span, _: hir::HirId) {}
+
fn visit_variant(
&mut self,
variant: &'tcx hir::Variant<'tcx>,
@@ -794,9 +843,16 @@
}
}
-pub fn check_crate(tcx: TyCtxt<'_>) {
- let access_levels = &tcx.privacy_access_levels(());
- let live_symbols = find_live(tcx, access_levels);
- let mut visitor = DeadVisitor { tcx, live_symbols };
- tcx.hir().walk_toplevel_module(&mut visitor);
+fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
+ let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
+ let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
+ let (module, _, module_id) = tcx.hir().get_module(module);
+ // Do not use an ItemLikeVisitor since we may want to skip visiting some items
+ // when a surrounding one is warned against or `_`.
+ intravisit::walk_mod(&mut visitor, module, module_id);
+}
+
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers =
+ Providers { live_symbols_and_ignored_derived_traits, check_mod_deathness, ..*providers };
}
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 63f9b3e..fdabe41 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,8 +1,8 @@
use rustc_ast::entry::EntryPointType;
use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
+use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
@@ -18,14 +18,14 @@
map: Map<'tcx>,
/// The function that has attribute named `main`.
- attr_main_fn: Option<(HirId, Span)>,
+ attr_main_fn: Option<(LocalDefId, Span)>,
/// The function that has the attribute 'start' on it.
- start_fn: Option<(HirId, Span)>,
+ start_fn: Option<(LocalDefId, Span)>,
/// The functions that one might think are `main` but aren't, e.g.
/// main functions not defined at the top level. For diagnostics.
- non_main_fns: Vec<(HirId, Span)>,
+ non_main_fns: Vec<Span>,
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
@@ -112,11 +112,11 @@
}
EntryPointType::MainNamed => (),
EntryPointType::OtherMain => {
- ctxt.non_main_fns.push((item.hir_id(), item.span));
+ ctxt.non_main_fns.push(item.span);
}
EntryPointType::MainAttr => {
if ctxt.attr_main_fn.is_none() {
- ctxt.attr_main_fn = Some((item.hir_id(), item.span));
+ ctxt.attr_main_fn = Some((item.def_id, item.span));
} else {
struct_span_err!(
ctxt.session,
@@ -131,7 +131,7 @@
}
EntryPointType::Start => {
if ctxt.start_fn.is_none() {
- ctxt.start_fn = Some((item.hir_id(), item.span));
+ ctxt.start_fn = Some((item.def_id, item.span));
} else {
struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
@@ -143,20 +143,19 @@
}
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
- if let Some((hir_id, _)) = visitor.start_fn {
- Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start))
- } else if let Some((hir_id, _)) = visitor.attr_main_fn {
- Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main))
+ if let Some((def_id, _)) = visitor.start_fn {
+ Some((def_id.to_def_id(), EntryFnType::Start))
+ } else if let Some((def_id, _)) = visitor.attr_main_fn {
+ Some((def_id.to_def_id(), EntryFnType::Main))
} else {
if let Some(main_def) = tcx.resolutions(()).main_def {
if let Some(def_id) = main_def.opt_fn_def_id() {
// non-local main imports are handled below
- if def_id.is_local() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- if matches!(tcx.hir().find(hir_id), Some(Node::ForeignItem(_))) {
+ if let Some(def_id) = def_id.as_local() {
+ if matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
tcx.sess
.struct_span_err(
- tcx.hir().span(hir_id),
+ tcx.def_span(def_id),
"the `main` function cannot be declared in an `extern` block",
)
.emit();
@@ -201,7 +200,7 @@
);
let filename = &tcx.sess.local_crate_source_file;
let note = if !visitor.non_main_fns.is_empty() {
- for &(_, span) in &visitor.non_main_fns {
+ for &span in &visitor.non_main_fns {
err.span_note(span, "here is a function named `main`");
}
err.note("you have one or more functions named `main` not defined at the crate level");
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 0e60ca9..56755d6 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -6,6 +6,7 @@
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{HirId, ItemLocalId};
use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
pub fn check_crate(tcx: TyCtxt<'_>) {
@@ -57,22 +58,22 @@
impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
- inner_visitor.check(i.hir_id(), |this| intravisit::walk_item(this, i));
+ inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
}
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
- inner_visitor.check(i.hir_id(), |this| intravisit::walk_trait_item(this, i));
+ inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
}
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
- inner_visitor.check(i.hir_id(), |this| intravisit::walk_impl_item(this, i));
+ inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
}
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
- inner_visitor.check(i.hir_id(), |this| intravisit::walk_foreign_item(this, i));
+ inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
}
}
@@ -83,9 +84,8 @@
self.errors.lock().push(f());
}
- fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, walk: F) {
+ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId, walk: F) {
assert!(self.owner.is_none());
- let owner = self.hir_map.local_def_id(hir_id);
self.owner = Some(owner);
walk(self);
@@ -140,10 +140,10 @@
}
impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
- type Map = Map<'hir>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.hir_map
}
fn visit_id(&mut self, hir_id: HirId) {
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d665c12..6cf1aa4 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -95,12 +95,6 @@
hir_visit::walk_param(self, param)
}
- type Map = Map<'v>;
-
- fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
- panic!("visit_nested_xxx must be manually implemented in this visitor")
- }
-
fn visit_nested_item(&mut self, id: hir::ItemId) {
let nested_item = self.krate.unwrap().item(id);
self.visit_item(nested_item)
@@ -338,9 +332,9 @@
ast_visit::walk_path_segment(self, path_span, path_segment)
}
- fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
- self.record("AssocTyConstraint", Id::None, constraint);
- ast_visit::walk_assoc_ty_constraint(self, constraint)
+ fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
+ self.record("AssocConstraint", Id::None, constraint);
+ ast_visit::walk_assoc_constraint(self, constraint)
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 064c469..1031ba0 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -3,7 +3,7 @@
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::query::Providers;
@@ -294,9 +294,8 @@
// (!). In that case we still need the earlier check to verify that the
// register class is usable at all.
if let Some(feature) = feature {
- let feat_sym = Symbol::intern(feature);
- if !self.tcx.sess.target_features.contains(&feat_sym)
- && !target_features.contains(&feat_sym)
+ if !self.tcx.sess.target_features.contains(&feature)
+ && !target_features.contains(&feature)
{
let msg = &format!("`{}` target feature is not enabled", feature);
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
@@ -377,9 +376,8 @@
{
match feature {
Some(feature) => {
- let feat_sym = Symbol::intern(feature);
- if self.tcx.sess.target_features.contains(&feat_sym)
- || attrs.target_features.contains(&feat_sym)
+ if self.tcx.sess.target_features.contains(&feature)
+ || attrs.target_features.contains(&feature)
{
missing_required_features.clear();
break;
@@ -413,7 +411,11 @@
let msg = format!(
"register class `{}` requires at least one of the following target features: {}",
reg_class.name(),
- features.join(", ")
+ features
+ .iter()
+ .map(|f| f.as_str())
+ .intersperse(", ")
+ .collect::<String>(),
);
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
// register isn't enabled, don't do more checks
@@ -488,12 +490,6 @@
}
impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
let body = self.tcx.hir().body(body_id);
@@ -505,12 +501,6 @@
}
impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
match expr.kind {
hir::ExprKind::Path(ref qpath) => {
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index a808d6c..0c934ec 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -10,7 +10,6 @@
use crate::check_attr::target_from_impl_item;
use crate::weak_lang_items;
-use rustc_ast::Attribute;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -57,8 +56,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: &Attribute, sym| attr.has_name(sym);
- if let Some((value, span)) = extract(check_name, &attrs) {
+ if let Some((value, span)) = extract(&attrs) {
match ITEM_REFS.get(&value).cloned() {
// Known lang item with attribute on correct target.
Some((item_index, expected_target)) if actual_target == expected_target => {
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 8a411f0..3130513 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,11 +6,14 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
+#![feature(iter_intersperse)]
+#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(nll)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
@@ -42,6 +45,7 @@
pub fn provide(providers: &mut Providers) {
check_attr::provide(providers);
check_const::provide(providers);
+ dead::provide(providers);
diagnostic_items::provide(providers);
entry::provide(providers);
lang_items::provide(providers);
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 40d12c4..0044569 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -6,8 +6,8 @@
use rustc_ast::{Attribute, MetaItemKind};
use rustc_errors::struct_span_err;
-use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_middle::hir::map::Map;
+use rustc_hir::intravisit::Visitor;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::LibFeatures;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
@@ -111,10 +111,10 @@
}
impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_attribute(&mut self, _: rustc_hir::HirId, attr: &'tcx Attribute) {
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 9ee305b..69cd1b4 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -90,10 +90,10 @@
use rustc_hir as hir;
use rustc_hir::def::*;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
use rustc_index::vec::IndexVec;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt};
use rustc_session::lint;
@@ -103,7 +103,6 @@
use std::collections::VecDeque;
use std::io;
use std::io::prelude::*;
-use std::iter;
use std::rc::Rc;
mod rwu_table;
@@ -317,10 +316,10 @@
}
impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
@@ -470,7 +469,6 @@
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
- | hir::ExprKind::LlvmInlineAsm(..)
| hir::ExprKind::Box(..)
| hir::ExprKind::Type(..)
| hir::ExprKind::Err
@@ -726,7 +724,7 @@
);
self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
}
- ty::UpvarCapture::ByValue(_) => {}
+ ty::UpvarCapture::ByValue => {}
}
}
}
@@ -1091,26 +1089,6 @@
succ
}
- hir::ExprKind::LlvmInlineAsm(ref asm) => {
- let ia = &asm.inner;
- let outputs = asm.outputs_exprs;
- let inputs = asm.inputs_exprs;
- let succ = iter::zip(&ia.outputs, outputs).rev().fold(succ, |succ, (o, output)| {
- // see comment on places
- // in propagate_through_place_components()
- if o.is_indirect {
- self.propagate_through_expr(output, succ)
- } else {
- let acc = if o.is_rw { ACC_WRITE | ACC_READ } else { ACC_WRITE };
- let succ = self.write_place(output, succ, acc);
- self.propagate_through_place_components(output, succ)
- }
- });
-
- // Inputs are executed first. Propagate last because of rev order
- self.propagate_through_exprs(inputs, succ)
- }
-
hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Err
@@ -1327,12 +1305,6 @@
// Checking for error conditions
impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
if local.init.is_some() {
@@ -1387,20 +1359,6 @@
}
}
- hir::ExprKind::LlvmInlineAsm(ref asm) => {
- for input in asm.inputs_exprs {
- this.visit_expr(input);
- }
-
- // Output operands must be places
- for (o, output) in iter::zip(&asm.inner.outputs, asm.outputs_exprs) {
- if !o.is_indirect {
- this.check_place(output);
- }
- this.visit_expr(output);
- }
- }
-
hir::ExprKind::Let(let_expr) => {
this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
}
@@ -1481,7 +1439,7 @@
for (&var_hir_id, min_capture_list) in closure_min_captures {
for captured_place in min_capture_list {
match captured_place.info.capture_kind {
- ty::UpvarCapture::ByValue(_) => {}
+ ty::UpvarCapture::ByValue => {}
ty::UpvarCapture::ByRef(..) => continue,
};
let span = captured_place.get_capture_kind_span(self.ir.tcx);
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 4bfac1b..02b09da 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -3,9 +3,10 @@
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Destination, Movability, Node};
use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
@@ -41,10 +42,10 @@
}
impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
- type Map = Map<'hir>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.hir_map)
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.hir_map
}
fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 07cb165..00a93cc 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,14 +1,14 @@
//! Checks validity of naked functions.
use rustc_ast::{Attribute, InlineAsmOptions};
+use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{FnKind, 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;
use rustc_target::spec::abi::Abi;
@@ -29,12 +29,6 @@
}
impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
- type Map = ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_fn(
&mut self,
fk: FnKind<'_>,
@@ -70,18 +64,16 @@
check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
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_asm(self.tcx, body, span);
+ check_inline(self.tcx, attrs);
}
}
}
/// Check that the function isn't inlined.
-fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
+fn check_inline(tcx: TyCtxt<'_>, 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();
- });
+ tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
}
}
@@ -129,12 +121,6 @@
}
impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
- type Map = ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Path(hir::QPath::Resolved(
_,
@@ -158,31 +144,31 @@
}
/// Checks that function body contains a single inline assembly block.
-fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body);
if let [(ItemKind::Asm, _)] = this.items[..] {
// Ok.
} else {
- tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
- let mut diag = lint.build("naked functions must contain a single asm block");
- let mut has_asm = false;
- for &(kind, span) in &this.items {
- match kind {
- ItemKind::Asm if has_asm => {
- diag.span_label(
- span,
- "multiple asm blocks are unsupported in naked functions",
- );
- }
- ItemKind::Asm => has_asm = true,
- ItemKind::NonAsm => {
- diag.span_label(span, "non-asm is unsupported in naked functions");
- }
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ fn_span,
+ E0787,
+ "naked functions must contain a single asm block"
+ );
+ let mut has_asm = false;
+ for &(kind, span) in &this.items {
+ match kind {
+ ItemKind::Asm if has_asm => {
+ diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
+ }
+ ItemKind::Asm => has_asm = true,
+ ItemKind::NonAsm => {
+ diag.span_label(span, "non-asm is unsupported in naked functions");
}
}
- diag.emit();
- });
+ }
+ diag.emit();
}
}
@@ -233,23 +219,7 @@
ExprKind::InlineAsm(ref asm) => {
self.items.push((ItemKind::Asm, span));
- self.check_inline_asm(expr.hir_id, asm, span);
- }
-
- ExprKind::LlvmInlineAsm(..) => {
- self.items.push((ItemKind::Asm, span));
- self.tcx.struct_span_lint_hir(
- UNSUPPORTED_NAKED_FUNCTIONS,
- expr.hir_id,
- span,
- |lint| {
- lint.build(
- "the LLVM-style inline assembly is unsupported in naked functions",
- )
- .help("use the new asm! syntax specified in RFC 2873")
- .emit();
- },
- );
+ self.check_inline_asm(asm, span);
}
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
@@ -258,7 +228,7 @@
}
}
- fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
+ fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
let unsupported_operands: Vec<Span> = asm
.operands
.iter()
@@ -271,18 +241,17 @@
})
.collect();
if !unsupported_operands.is_empty() {
- self.tcx.struct_span_lint_hir(
- UNSUPPORTED_NAKED_FUNCTIONS,
- hir_id,
+ struct_span_err!(
+ self.tcx.sess,
unsupported_operands,
- |lint| {
- lint.build("only `const` and `sym` operands are supported in naked functions")
- .emit();
- },
- );
+ E0787,
+ "only `const` and `sym` operands are supported in naked functions",
+ )
+ .emit();
}
let unsupported_options: Vec<&'static str> = [
+ (InlineAsmOptions::MAY_UNWIND, "`may_unwind`"),
(InlineAsmOptions::NOMEM, "`nomem`"),
(InlineAsmOptions::NOSTACK, "`nostack`"),
(InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
@@ -294,30 +263,29 @@
.collect();
if !unsupported_options.is_empty() {
- self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
- lint.build(&format!(
- "asm options unsupported in naked functions: {}",
- unsupported_options.join(", ")
- ))
- .emit();
- });
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0787,
+ "asm options unsupported in naked functions: {}",
+ unsupported_options.join(", ")
+ )
+ .emit();
}
if !asm.options.contains(InlineAsmOptions::NORETURN) {
- self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
- lint.build("asm in naked functions must use `noreturn` option").emit();
- });
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0787,
+ "asm in naked functions must use `noreturn` option"
+ )
+ .emit();
}
}
}
impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
- type Map = ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
match stmt.kind {
StmtKind::Item(..) => {}
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 707e6b1..6cd9dc2 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -9,7 +9,7 @@
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -52,7 +52,7 @@
return true;
}
}
- match tcx.hir().find(tcx.hir().local_def_id_to_hir_id(impl_src)) {
+ match tcx.hir().find_by_def_id(impl_src) {
Some(Node::Item(item)) => item_might_be_inlined(tcx, &item, codegen_fn_attrs),
Some(..) | None => span_bug!(impl_item.span, "impl did is not an item"),
}
@@ -74,12 +74,6 @@
}
impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_nested_body(&mut self, body: hir::BodyId) {
let old_maybe_typeck_results =
self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
@@ -140,14 +134,11 @@
// Returns true if the given def ID represents a local item that is
// eligible for inlining and false otherwise.
fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
- let hir_id = match def_id.as_local() {
- Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id),
- None => {
- return false;
- }
+ let Some(def_id) = def_id.as_local() else {
+ return false;
};
- match self.tcx.hir().find(hir_id) {
+ match self.tcx.hir().find_by_def_id(def_id) {
Some(Node::Item(item)) => match item.kind {
hir::ItemKind::Fn(..) => {
item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id))
@@ -169,7 +160,8 @@
if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
true
} else {
- let impl_did = self.tcx.hir().get_parent_did(hir_id);
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+ let impl_did = self.tcx.hir().get_parent_item(hir_id);
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
@@ -198,9 +190,7 @@
continue;
}
- if let Some(ref item) =
- self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(search_item))
- {
+ if let Some(ref item) = self.tcx.hir().find_by_def_id(search_item) {
self.propagate_node(item, search_item);
}
}
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 8968c16..fdf93e5 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -10,7 +10,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
use rustc_index::vec::Idx;
use rustc_middle::middle::region::*;
@@ -366,7 +366,8 @@
let target_scopes = visitor.fixup_scopes.drain(start_point..);
for scope in target_scopes {
- let mut yield_data = visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap();
+ let mut yield_data =
+ visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap();
let count = yield_data.expr_and_pat_count;
let span = yield_data.span;
@@ -429,7 +430,13 @@
};
let data =
YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source };
- visitor.scope_tree.yield_in_scope.insert(scope, data);
+ match visitor.scope_tree.yield_in_scope.get_mut(&scope) {
+ Some(yields) => yields.push(data),
+ None => {
+ visitor.scope_tree.yield_in_scope.insert(scope, vec![data]);
+ }
+ }
+
if visitor.pessimistic_yield {
debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope);
visitor.fixup_scopes.push(scope);
@@ -721,12 +728,6 @@
}
impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
resolve_block(self, b);
}
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 5f19991..1360596 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -9,9 +9,9 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability::{DeprecationEntry, Index};
use rustc_middle::ty::{self, query::Providers, TyCtxt};
@@ -378,10 +378,10 @@
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
@@ -577,26 +577,30 @@
}
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
- let stab_map = self.tcx.stability();
- 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(def_id);
- if const_stab.is_none() {
- self.tcx.sess.span_err(
- span,
- "`#[stable]` const functions must also be either \
- `#[rustc_const_stable]` or `#[rustc_const_unstable]`",
- );
- }
+ if !self.tcx.features().staged_api {
+ return;
+ }
+
+ let is_const = self.tcx.is_const_fn(def_id.to_def_id());
+ let is_stable = self
+ .tcx
+ .lookup_stability(def_id)
+ .map_or(false, |stability| stability.level.is_stable());
+ let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
+ let is_reachable = self.access_levels.is_reachable(def_id);
+
+ if is_const && is_stable && missing_const_stability_attribute && is_reachable {
+ let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
+ self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
}
}
}
impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
@@ -612,13 +616,8 @@
self.check_missing_stability(i.def_id, i.span);
}
- // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
- // `rustc_const_stable`.
- if self.tcx.features().staged_api
- && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
- {
- self.check_missing_const_stability(i.def_id, i.span);
- }
+ // Ensure stable `const fn` have a const stability attribute.
+ self.check_missing_const_stability(i.def_id, i.span);
intravisit::walk_item(self, i)
}
@@ -629,9 +628,10 @@
}
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()));
+ let impl_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.def_id, ii.span);
+ self.check_missing_const_stability(ii.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
@@ -738,13 +738,13 @@
}
impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -794,19 +794,12 @@
}
}
- if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
- for impl_item_ref in items {
- let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
- let trait_item_def_id = self
- .tcx
- .associated_items(trait_did)
- .filter_by_name_unhygienic(impl_item.ident.name)
- .next()
- .map(|item| item.def_id);
- if let Some(def_id) = trait_item_def_id {
- // Pass `None` to skip deprecation warnings.
- self.tcx.check_stability(def_id, None, impl_item.span, None);
- }
+ for impl_item_ref in items {
+ let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+
+ if let Some(def_id) = impl_item.trait_item_def_id {
+ // Pass `None` to skip deprecation warnings.
+ self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
}
}
}
@@ -867,12 +860,6 @@
}
impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
- type Map = Map<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
if let Some(def_id) = path.res.opt_def_id() {
if let Some(stab) = self.tcx.lookup_stability(def_id) {
diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs
index 2d84c8c..25fe8e4 100644
--- a/compiler/rustc_passes/src/upvars.rs
+++ b/compiler/rustc_passes/src/upvars.rs
@@ -3,7 +3,7 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::def::Res;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self, HirId};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
@@ -43,12 +43,6 @@
}
impl<'tcx> Visitor<'tcx> for LocalCollector {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind {
self.locals.insert(hir_id);
@@ -72,12 +66,6 @@
}
impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
if let Res::Local(var_id) = path.res {
self.visit_local_use(var_id, path.span);
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 61c82f0..6b73c95 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -1,10 +1,9 @@
//! 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;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items::{self, LangItem};
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
use rustc_middle::middle::lang_items::required;
@@ -96,16 +95,9 @@
}
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
- 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) {
+ if let Some((lang_item, _)) = lang_items::extract(attrs) {
self.register(lang_item, i.span);
}
intravisit::walk_foreign_item(self, i)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 183a5a2..48594e7 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -4,6 +4,7 @@
#![feature(try_blocks)]
#![feature(associated_type_defaults)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
use rustc_ast::MacroDef;
use rustc_attr as attr;
@@ -11,12 +12,11 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-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::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
+use rustc_hir::intravisit::{self, DeepVisitor, Visitor};
use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
use rustc_middle::bug;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
use rustc_middle::span_bug;
use rustc_middle::thir::abstract_const::Node as ACNode;
@@ -26,7 +26,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, sym, Ident};
+use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
@@ -128,8 +128,8 @@
constness: _,
polarity: _,
}) => self.visit_trait(trait_ref),
- ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
- ty.visit_with(self)?;
+ ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+ term.visit_with(self)?;
self.visit_projection_ty(projection_ty)
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
@@ -178,10 +178,6 @@
{
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`.
@@ -284,8 +280,8 @@
}
}
- fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- self.visit_ty(c.ty)?;
+ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ self.visit_ty(c.ty())?;
let tcx = self.def_id_visitor.tcx();
if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
self.visit_abstract_const_expr(tcx, ct)?;
@@ -310,10 +306,10 @@
}
impl<'tcx> Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_vis(&mut self, vis: &'tcx hir::Visibility<'tcx>) {
self.has_pub_restricted = self.has_pub_restricted || vis.node.is_pub_restricted();
@@ -436,6 +432,15 @@
self.access_levels.map.get(&def_id).copied()
}
+ fn update_with_hir_id(
+ &mut self,
+ hir_id: hir::HirId,
+ level: Option<AccessLevel>,
+ ) -> Option<AccessLevel> {
+ let def_id = self.tcx.hir().local_def_id(hir_id);
+ self.update(def_id, level)
+ }
+
/// Updates node level and returns the updated level.
fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
let old_level = self.get(def_id);
@@ -520,7 +525,7 @@
let vis = self.tcx.visibility(item_id.def_id);
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) {
+ if let Some(exports) = self.tcx.module_reexports(module_def_id) {
for export in exports {
if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
if let Res::Def(def_kind, def_id) = export.res {
@@ -623,116 +628,37 @@
| DefKind::Generator => (),
}
}
-
- /// 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`.
- ///
- /// This isn't trivial as `path.res` has the `DefId` of the eventual target
- /// of the use statement not of the next intermediate use statement.
- ///
- /// To do this, consider the last two segments of the path to our intermediate
- /// use statement. We expect the penultimate segment to be a module and the
- /// last segment to be the name of the item we are exporting. We can then
- /// look at the items contained in the module for the use statement with that
- /// name and update that item's visibility.
- ///
- /// FIXME: This solution won't work with glob imports and doesn't respect
- /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
- fn update_visibility_of_intermediate_use_statements(
- &mut self,
- segments: &[hir::PathSegment<'_>],
- ) {
- if let [.., module, segment] = segments {
- if let Some(item) = module
- .res
- .and_then(|res| res.mod_def_id())
- // If the module is `self`, i.e. the current crate,
- // there will be no corresponding item.
- .filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
- .and_then(|def_id| def_id.as_local())
- .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
- {
- if let hir::ItemKind::Mod(m) = &item.kind {
- for &item_id in m.item_ids {
- let item = self.tcx.hir().item(item_id);
- if !self.tcx.hygienic_eq(
- segment.ident,
- item.ident,
- item_id.def_id.to_def_id(),
- ) {
- continue;
- }
- if let hir::ItemKind::Use(..) = item.kind {
- self.update(item.def_id, Some(AccessLevel::Exported));
- }
- }
- }
- }
- }
- }
}
impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let inherited_item_level = match item.kind {
+ let item_level = match item.kind {
hir::ItemKind::Impl { .. } => {
- Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels)
+ let impl_level =
+ Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels);
+ self.update(item.def_id, impl_level)
}
- // 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,
- // Other `pub` items inherit levels from parents.
- hir::ItemKind::Const(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::ExternCrate(..)
- | hir::ItemKind::GlobalAsm(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::Macro(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::Static(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Trait(..)
- | hir::ItemKind::TraitAlias(..)
- | hir::ItemKind::OpaqueTy(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Union(..)
- | hir::ItemKind::Use(..) => {
- if item.vis.node.is_pub() {
- self.prev_level
- } else {
- None
- }
- }
+ _ => self.get(item.def_id),
};
- // Update level of the item itself.
- 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(self.tcx.hir().local_def_id(variant.id), item_level);
+ let variant_level = self.update_with_hir_id(variant.id, item_level);
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
- self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
+ self.update_with_hir_id(ctor_hir_id, item_level);
}
for field in variant.data.fields() {
- self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level);
+ self.update_with_hir_id(field.hir_id, variant_level);
}
}
}
@@ -752,11 +678,11 @@
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
if let Some(ctor_hir_id) = def.ctor_hir_id() {
- self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
+ self.update_with_hir_id(ctor_hir_id, item_level);
}
for field in def.fields() {
if field.vis.node.is_pub() {
- self.update(self.tcx.hir().local_def_id(field.hir_id), item_level);
+ self.update_with_hir_id(field.hir_id, item_level);
}
}
}
@@ -789,14 +715,8 @@
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
- // all of the items of a mod in `visit_mod` looking for use statements, we handle
- // making sure that intermediate use statements have their visibilities updated here.
- hir::ItemKind::Use(path, _) => {
- if item_level.is_some() {
- self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
- }
- }
+ // Handled in the access level of in rustc_resolve
+ hir::ItemKind::Use(..) => {}
// The interface is empty.
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::OpaqueTy(..) => {
@@ -920,27 +840,6 @@
intravisit::walk_block(self, b);
self.prev_level = orig_level;
}
-
- fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
- // This code is here instead of in visit_item so that the
- // crate module gets processed as well.
- if self.prev_level.is_some() {
- let def_id = self.tcx.hir().local_def_id(id);
- if let Some(exports) = self.tcx.module_exports(def_id) {
- for export in exports.iter() {
- if export.vis.is_public() {
- if let Some(def_id) = export.res.opt_def_id() {
- if let Some(def_id) = def_id.as_local() {
- self.update(def_id, Some(AccessLevel::Exported));
- }
- }
- }
- }
- }
- }
-
- intravisit::walk_mod(self, m, id);
- }
}
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
@@ -1045,7 +944,7 @@
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)
+ format!("field `{}` is private", field.name)
} else {
"private field".to_string()
};
@@ -1055,7 +954,7 @@
span,
E0451,
"field `{}` of {} `{}` is private",
- field.ident,
+ field.name,
def.variant_descr(),
self.tcx.def_path_str(def.did)
)
@@ -1066,12 +965,12 @@
}
impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
@@ -1195,12 +1094,12 @@
}
impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
@@ -1250,19 +1149,11 @@
if self.visit(ty).is_break() {
return;
}
+ } else {
+ // We don't do anything for const infers here.
}
} 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;
- }
+ bug!("visit_infer without typeck_results");
}
intravisit::walk_inf(self, inf);
}
@@ -1287,10 +1178,10 @@
}
for (poly_predicate, _) in bounds.projection_bounds {
- if self.visit(poly_predicate.skip_binder().ty).is_break()
- || self
- .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
- .is_break()
+ let pred = poly_predicate.skip_binder();
+ let poly_pred_term = self.visit(pred.term);
+ if poly_pred_term.is_break()
+ || self.visit_projection_ty(pred.projection_ty).is_break()
{
return;
}
@@ -1313,9 +1204,9 @@
return;
}
}
- hir::ExprKind::MethodCall(_, span, _, _) => {
+ hir::ExprKind::MethodCall(segment, ..) => {
// Method calls have to be checked specially.
- self.span = span;
+ self.span = segment.ident.span;
if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) {
if self.visit(self.tcx.type_of(def_id)).is_break() {
return;
@@ -1459,7 +1350,7 @@
impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
let did = match path.res {
- Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => return false,
+ Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => return false,
res => res.def_id(),
};
@@ -1497,12 +1388,6 @@
}
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- 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),
@@ -1533,12 +1418,12 @@
}
impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -1982,10 +1867,10 @@
}
impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -2122,7 +2007,7 @@
// Visibilities of trait impl items are inherited from their traits
// and are not filled in resolve.
Node::ImplItem(impl_item) => {
- match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
+ match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id)) {
Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(tr), .. }),
..
@@ -2166,11 +2051,12 @@
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx,
- access_levels: Default::default(),
+ access_levels: tcx.resolutions(()).access_levels.clone(),
macro_reachable: Default::default(),
prev_level: Some(AccessLevel::Public),
changed: false,
};
+
loop {
tcx.hir().walk_toplevel_module(&mut visitor);
if visitor.changed {
@@ -2179,7 +2065,6 @@
break;
}
}
- visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public));
tcx.arena.alloc(visitor.access_levels)
}
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index f984bb1..f1899a6 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -8,7 +8,7 @@
[dependencies]
measureme = "10.0.0"
-rustc-rayon-core = "0.3.1"
+rustc-rayon-core = "0.3.2"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 581a2bc..84de31a 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -275,7 +275,7 @@
}
}
-impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
+impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
@@ -345,7 +345,7 @@
}
}
-impl<'tcx> Key for &'tcx ty::Const<'tcx> {
+impl<'tcx> Key for ty::Const<'tcx> {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index de9d425..55e95e1 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -7,6 +7,7 @@
#![feature(once_cell)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
@@ -14,6 +15,7 @@
extern crate rustc_middle;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::AtomicU64;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::{self, DepKindStruct, SerializedDepNodeIndex};
use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
@@ -27,9 +29,6 @@
pub use plumbing::QueryCtxt;
use rustc_query_system::query::*;
-mod stats;
-pub use self::stats::print_stats;
-
mod keys;
use keys::Key;
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 6a88e12..06e276a 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -163,15 +163,12 @@
// Decode the *position* of the footer, which can be found in the
// last 8 bytes of the file.
decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
- let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder)
- .expect("error while trying to decode footer position")
- .0 as usize;
+ let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize;
// Decode the file footer, which contains all the lookup tables, etc.
decoder.set_position(footer_pos);
decode_tagged(&mut decoder, TAG_FILE_FOOTER)
- .expect("error while trying to decode footer position")
};
Self {
@@ -372,7 +369,7 @@
dep_node_index: SerializedDepNodeIndex,
) -> QuerySideEffects {
let side_effects: Option<QuerySideEffects> =
- self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index, "side_effects");
+ self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index);
side_effects.unwrap_or_default()
}
@@ -398,7 +395,7 @@
where
T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
{
- self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
+ self.load_indexed(tcx, dep_node_index, &self.query_result_index)
}
/// Stores side effect emitted during computation of an anonymous query.
@@ -423,17 +420,13 @@
tcx: TyCtxt<'tcx>,
dep_node_index: SerializedDepNodeIndex,
index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
- debug_tag: &'static str,
) -> Option<T>
where
T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
{
let pos = index.get(&dep_node_index).cloned()?;
- self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) {
- Ok(v) => Some(v),
- Err(e) => bug!("could not decode cached {}: {}", debug_tag, e),
- })
+ self.with_decoder(tcx, pos, |decoder| Some(decode_tagged(decoder, dep_node_index)))
}
fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>(
@@ -535,7 +528,7 @@
// Decodes something that was encoded with `encode_tagged()` and verify that the
// tag matches and the correct amount of bytes was read.
-fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
+fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V
where
T: Decodable<D> + Eq + std::fmt::Debug,
V: Decodable<D>,
@@ -543,15 +536,15 @@
{
let start_pos = decoder.position();
- let actual_tag = T::decode(decoder)?;
+ let actual_tag = T::decode(decoder);
assert_eq!(actual_tag, expected_tag);
- let value = V::decode(decoder)?;
+ let value = V::decode(decoder);
let end_pos = decoder.position();
- let expected_len: u64 = Decodable::decode(decoder)?;
+ let expected_len: u64 = Decodable::decode(decoder);
assert_eq!((end_pos - start_pos) as u64, expected_len);
- Ok(value)
+ value
}
impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
@@ -572,26 +565,22 @@
self.opaque.data[self.opaque.position()]
}
- fn cached_ty_for_shorthand<F>(
- &mut self,
- shorthand: usize,
- or_insert_with: F,
- ) -> Result<Ty<'tcx>, Self::Error>
+ fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
where
- F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>,
+ F: FnOnce(&mut Self) -> Ty<'tcx>,
{
let tcx = self.tcx();
let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
- return Ok(ty);
+ return ty;
}
- let ty = or_insert_with(self)?;
+ let ty = or_insert_with(self);
// This may overwrite the entry, but it should overwrite with the same value.
tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
- Ok(ty)
+ ty
}
fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
@@ -607,7 +596,7 @@
r
}
- fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
+ fn decode_alloc_id(&mut self) -> interpret::AllocId {
let alloc_decoding_session = self.alloc_decoding_session;
alloc_decoding_session.decode_alloc_id(self)
}
@@ -619,35 +608,35 @@
// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt
// into specializations this way, given how `CacheDecoder` and the decoding traits currently work.
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
Decodable::decode(&mut d.opaque)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
- fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
let syntax_contexts = decoder.syntax_contexts;
rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| {
// This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
// We look up the position of the associated `SyntaxData` and decode it.
let pos = syntax_contexts.get(&id).unwrap();
this.with_position(pos.to_usize(), |decoder| {
- let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?;
- Ok(data)
+ let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT);
+ data
})
})
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
- fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
- let hash = ExpnHash::decode(decoder)?;
+ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let hash = ExpnHash::decode(decoder);
if hash.is_root() {
- return Ok(ExpnId::root());
+ return ExpnId::root();
}
if let Some(expn_id) = ExpnId::from_hash(hash) {
- return Ok(expn_id);
+ return expn_id;
}
let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id());
@@ -660,7 +649,7 @@
.unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data));
let data: ExpnData = decoder
- .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?;
+ .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA));
let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash);
#[cfg(debug_assertions)]
@@ -687,21 +676,21 @@
};
debug_assert_eq!(expn_id.krate, krate);
- Ok(expn_id)
+ expn_id
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
- fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
- let ctxt = SyntaxContext::decode(decoder)?;
- let parent = Option::<LocalDefId>::decode(decoder)?;
- let tag: u8 = Decodable::decode(decoder)?;
+ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let ctxt = SyntaxContext::decode(decoder);
+ let parent = Option::<LocalDefId>::decode(decoder);
+ let tag: u8 = Decodable::decode(decoder);
if tag == TAG_PARTIAL_SPAN {
- return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent));
+ return Span::new(BytePos(0), BytePos(0), ctxt, parent);
} else if tag == TAG_RELATIVE_SPAN {
- let dlo = u32::decode(decoder)?;
- let dto = u32::decode(decoder)?;
+ let dlo = u32::decode(decoder);
+ let dto = u32::decode(decoder);
let enclosing =
decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked();
@@ -712,29 +701,29 @@
parent,
);
- return Ok(span);
+ return span;
} else {
debug_assert_eq!(tag, TAG_FULL_SPAN);
}
- let file_lo_index = SourceFileIndex::decode(decoder)?;
- let line_lo = usize::decode(decoder)?;
- let col_lo = BytePos::decode(decoder)?;
- let len = BytePos::decode(decoder)?;
+ let file_lo_index = SourceFileIndex::decode(decoder);
+ let line_lo = usize::decode(decoder);
+ let col_lo = BytePos::decode(decoder);
+ let len = BytePos::decode(decoder);
let file_lo = decoder.file_index_to_file(file_lo_index);
let lo = file_lo.lines[line_lo - 1] + col_lo;
let hi = lo + len;
- Ok(Span::new(lo, hi, ctxt, parent))
+ Span::new(lo, hi, ctxt, parent)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
- let stable_id = StableCrateId::decode(d)?;
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let stable_id = StableCrateId::decode(d);
let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id);
- Ok(cnum)
+ cnum
}
}
@@ -743,8 +732,8 @@
// because we would not know how to transform the `DefIndex` to the current
// context.
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> {
- Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`"))
+ fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex {
+ panic!("trying to decode `DefIndex` outside the context of a `DefId`")
}
}
@@ -752,21 +741,23 @@
// compilation sessions. We use the `DefPathHash`, which is stable across
// sessions, to map the old `DefId` to the new one.
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
// Load the `DefPathHash` which is was we encoded the `DefId` as.
- let def_path_hash = DefPathHash::decode(d)?;
+ let def_path_hash = DefPathHash::decode(d);
// Using the `DefPathHash`, we can lookup the new `DefId`.
// Subtle: We only encode a `DefId` as part of a query result.
// If we get to this point, then all of the query inputs were green,
// which means that the definition with this hash is guaranteed to
// still exist in the current compilation session.
- Ok(d.tcx().def_path_hash_to_def_id(def_path_hash))
+ d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
+ panic!("Failed to convert DefPathHash {:?}", def_path_hash)
+ })
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
@@ -774,31 +765,31 @@
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
{
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
- fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 6d76d09..ff9d32a 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -3,7 +3,7 @@
//! manage the caches, and so forth.
use crate::{on_disk_cache, Queries};
-use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::ty::TyCtxt;
use rustc_query_system::dep_graph::HasDepContext;
@@ -15,6 +15,7 @@
use rustc_serialize::opaque;
use std::any::Any;
+use std::num::NonZeroU64;
#[derive(Copy, Clone)]
pub struct QueryCtxt<'tcx> {
@@ -42,11 +43,20 @@
}
impl QueryContext for QueryCtxt<'_> {
- fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
+ fn next_job_id(&self) -> QueryJobId {
+ QueryJobId(
+ NonZeroU64::new(
+ self.queries.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed),
+ )
+ .unwrap(),
+ )
+ }
+
+ fn current_query_job(&self) -> Option<QueryJobId> {
tls::with_related_context(**self, |icx| icx.query)
}
- fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>> {
+ fn try_collect_active_jobs(&self) -> Option<QueryMap> {
self.queries.try_collect_active_jobs(**self)
}
@@ -81,7 +91,7 @@
#[inline(always)]
fn start_query<R>(
&self,
- token: QueryJobId<Self::DepKind>,
+ token: QueryJobId,
diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
compute: impl FnOnce() -> R,
) -> R {
@@ -152,7 +162,7 @@
pub fn try_print_query_stack(
self,
- query: Option<QueryJobId<DepKind>>,
+ query: Option<QueryJobId>,
handler: &Handler,
num_frames: Option<usize>,
) -> usize {
@@ -299,7 +309,7 @@
}
#[allow(nonstandard_style)]
- pub mod queries {
+ mod queries {
use std::marker::PhantomData;
$(pub struct $name<$tcx> {
@@ -320,7 +330,7 @@
type Cache = query_storage::$name<$tcx>;
#[inline(always)]
- fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, Self::Key>
+ fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<Self::Key>
where QueryCtxt<$tcx>: 'a
{
&tcx.queries.$name
@@ -353,7 +363,7 @@
})*
#[allow(nonstandard_style)]
- pub mod query_callbacks {
+ mod query_callbacks {
use super::*;
use rustc_middle::dep_graph::DepNode;
use rustc_middle::ty::query::query_keys;
@@ -402,7 +412,7 @@
}
}
- $(pub fn $name()-> DepKindStruct {
+ $(pub(crate) fn $name()-> DepKindStruct {
let is_anon = is_anon!([$($modifiers)*]);
let is_eval_always = is_eval_always!([$($modifiers)*]);
@@ -471,10 +481,9 @@
pub on_disk_cache: Option<OnDiskCache<$tcx>>,
- $($(#[$attr])* $name: QueryState<
- crate::dep_graph::DepKind,
- query_keys::$name<$tcx>,
- >,)*
+ jobs: AtomicU64,
+
+ $($(#[$attr])* $name: QueryState<query_keys::$name<$tcx>>,)*
}
impl<$tcx> Queries<$tcx> {
@@ -487,6 +496,7 @@
local_providers: Box::new(local_providers),
extern_providers: Box::new(extern_providers),
on_disk_cache,
+ jobs: AtomicU64::new(1),
$($name: Default::default()),*
}
}
@@ -494,14 +504,13 @@
pub(crate) fn try_collect_active_jobs(
&$tcx self,
tcx: TyCtxt<$tcx>,
- ) -> Option<QueryMap<crate::dep_graph::DepKind>> {
+ ) -> Option<QueryMap> {
let tcx = QueryCtxt { tcx, queries: self };
let mut jobs = QueryMap::default();
$(
self.$name.try_collect_active_jobs(
tcx,
- dep_graph::DepKind::$name,
make_query::$name,
&mut jobs,
)?;
diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs
deleted file mode 100644
index c3bbd51..0000000
--- a/compiler/rustc_query_impl/src/stats.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_middle::ty::query::query_storage;
-use rustc_middle::ty::TyCtxt;
-use rustc_query_system::query::{QueryCache, QueryCacheStore};
-
-use std::any::type_name;
-use std::mem;
-
-trait KeyStats {
- fn key_stats(&self, stats: &mut QueryStats);
-}
-
-impl<T> KeyStats for T {
- default fn key_stats(&self, _: &mut QueryStats) {}
-}
-
-impl KeyStats for DefId {
- fn key_stats(&self, stats: &mut QueryStats) {
- if self.krate == LOCAL_CRATE {
- stats.local_def_id_keys = Some(stats.local_def_id_keys.unwrap_or(0) + 1);
- }
- }
-}
-
-#[derive(Clone)]
-struct QueryStats {
- name: &'static str,
- key_size: usize,
- key_type: &'static str,
- value_size: usize,
- value_type: &'static str,
- entry_count: usize,
- local_def_id_keys: Option<usize>,
-}
-
-fn stats<C>(name: &'static str, map: &QueryCacheStore<C>) -> QueryStats
-where
- C: QueryCache,
-{
- let mut stats = QueryStats {
- name,
- key_size: mem::size_of::<C::Key>(),
- key_type: type_name::<C::Key>(),
- value_size: mem::size_of::<C::Value>(),
- value_type: type_name::<C::Value>(),
- entry_count: 0,
- local_def_id_keys: None,
- };
- map.iter_results(&mut |key, _, _| {
- stats.entry_count += 1;
- key.key_stats(&mut stats)
- });
- stats
-}
-
-pub fn print_stats(tcx: TyCtxt<'_>) {
- let queries = query_stats(tcx);
-
- let mut query_key_sizes = queries.clone();
- query_key_sizes.sort_by_key(|q| q.key_size);
- eprintln!("\nLarge query keys:");
- for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
- eprintln!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
- }
-
- let mut query_value_sizes = queries.clone();
- query_value_sizes.sort_by_key(|q| q.value_size);
- eprintln!("\nLarge query values:");
- for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
- eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
- }
-
- let mut query_value_count = queries.clone();
- query_value_count.sort_by_key(|q| q.entry_count);
- eprintln!("\nQuery value count:");
- for q in query_value_count.iter().rev() {
- eprintln!(" {} - {}", q.name, q.entry_count);
- }
-
- let mut def_id_density: Vec<_> =
- queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
- def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
- eprintln!("\nLocal DefId density:");
- let total = tcx.resolutions(()).definitions.def_index_count() as f64;
- for q in def_id_density.iter().rev() {
- let local = q.local_def_id_keys.unwrap();
- eprintln!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
- }
-}
-
-macro_rules! print_stats {
- (<$tcx:tt>
- $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
- ) => {
- fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
- let mut queries = Vec::new();
-
- $(
- queries.push(stats::<
- query_storage::$name<'_>,
- >(
- stringify!($name),
- &tcx.query_caches.$name,
- ));
- )*
-
- queries
- }
- }
-}
-
-rustc_query_append! { [print_stats!][<'tcx>] }
diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_query_impl/src/values.rs
index 003867b..718a297 100644
--- a/compiler/rustc_query_impl/src/values.rs
+++ b/compiler/rustc_query_impl/src/values.rs
@@ -1,5 +1,5 @@
use super::QueryCtxt;
-use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyS};
+use rustc_middle::ty::{self, AdtSizedConstraint, Ty};
pub(super) trait Value<'tcx>: Sized {
fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self;
@@ -12,7 +12,7 @@
}
}
-impl<'tcx> Value<'tcx> for &'_ TyS<'_> {
+impl<'tcx> Value<'tcx> for Ty<'_> {
fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 898a8ca..79f791e 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -9,7 +9,7 @@
[dependencies]
rustc_arena = { path = "../rustc_arena" }
tracing = "0.1"
-rustc-rayon-core = "0.3.1"
+rustc-rayon-core = "0.3.2"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 7bc3fd7..a080b4a3 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -9,6 +9,7 @@
use rustc_index::vec::IndexVec;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use smallvec::{smallvec, SmallVec};
+use std::assert_matches::assert_matches;
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash::Hash;
@@ -165,7 +166,11 @@
pub fn assert_ignored(&self) {
if let Some(..) = self.data {
K::read_deps(|task_deps| {
- assert!(task_deps.is_none(), "expected no task dependency tracking");
+ assert_matches!(
+ task_deps,
+ TaskDepsRef::Ignore,
+ "expected no task dependency tracking"
+ );
})
}
}
@@ -174,7 +179,60 @@
where
OP: FnOnce() -> R,
{
- K::with_deps(None, op)
+ K::with_deps(TaskDepsRef::Ignore, op)
+ }
+
+ /// Used to wrap the deserialization of a query result from disk,
+ /// This method enforces that no new `DepNodes` are created during
+ /// query result deserialization.
+ ///
+ /// Enforcing this makes the query dep graph simpler - all nodes
+ /// must be created during the query execution, and should be
+ /// created from inside the 'body' of a query (the implementation
+ /// provided by a particular compiler crate).
+ ///
+ /// Consider the case of three queries `A`, `B`, and `C`, where
+ /// `A` invokes `B` and `B` invokes `C`:
+ ///
+ /// `A -> B -> C`
+ ///
+ /// Suppose that decoding the result of query `B` required re-computing
+ /// the query `C`. If we did not create a fresh `TaskDeps` when
+ /// decoding `B`, we would still be using the `TaskDeps` for query `A`
+ /// (if we needed to re-execute `A`). This would cause us to create
+ /// a new edge `A -> C`. If this edge did not previously
+ /// exist in the `DepGraph`, then we could end up with a different
+ /// `DepGraph` at the end of compilation, even if there were no
+ /// meaningful changes to the overall program (e.g. a newline was added).
+ /// In addition, this edge might cause a subsequent compilation run
+ /// to try to force `C` before marking other necessary nodes green. If
+ /// `C` did not exist in the new compilation session, then we could
+ /// get an ICE. Normally, we would have tried (and failed) to mark
+ /// some other query green (e.g. `item_children`) which was used
+ /// to obtain `C`, which would prevent us from ever trying to force
+ /// a non-existent `D`.
+ ///
+ /// It might be possible to enforce that all `DepNode`s read during
+ /// deserialization already exist in the previous `DepGraph`. In
+ /// the above example, we would invoke `D` during the deserialization
+ /// of `B`. Since we correctly create a new `TaskDeps` from the decoding
+ /// of `B`, this would result in an edge `B -> D`. If that edge already
+ /// existed (with the same `DepPathHash`es), then it should be correct
+ /// to allow the invocation of the query to proceed during deserialization
+ /// of a query result. We would merely assert that the dep-graph fragment
+ /// that would have been added by invoking `C` while decoding `B`
+ /// is equivalent to the dep-graph fragment that we already instantiated for B
+ /// (at the point where we successfully marked B as green).
+ ///
+ /// However, this would require additional complexity
+ /// in the query infrastructure, and is not currently needed by the
+ /// decoding of any query results. Should the need arise in the future,
+ /// we should consider extending the query system with this functionality.
+ pub fn with_query_deserialization<OP, R>(&self, op: OP) -> R
+ where
+ OP: FnOnce() -> R,
+ {
+ K::with_deps(TaskDepsRef::Forbid, op)
}
/// Starts a new dep-graph task. Dep-graph tasks are specified
@@ -259,7 +317,13 @@
phantom_data: PhantomData,
}))
};
- let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
+
+ let task_deps_ref = match &task_deps {
+ Some(deps) => TaskDepsRef::Allow(deps),
+ None => TaskDepsRef::Ignore,
+ };
+
+ let result = K::with_deps(task_deps_ref, || task(cx, arg));
let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
let dcx = cx.dep_context();
@@ -312,7 +376,7 @@
if let Some(ref data) = self.data {
let task_deps = Lock::new(TaskDeps::default());
- let result = K::with_deps(Some(&task_deps), op);
+ let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op);
let task_deps = task_deps.into_inner();
let task_deps = task_deps.reads;
@@ -365,42 +429,47 @@
pub fn read_index(&self, dep_node_index: DepNodeIndex) {
if let Some(ref data) = self.data {
K::read_deps(|task_deps| {
- if let Some(task_deps) = task_deps {
- let mut task_deps = task_deps.lock();
- let task_deps = &mut *task_deps;
- if cfg!(debug_assertions) {
- data.current.total_read_count.fetch_add(1, Relaxed);
+ let mut task_deps = match task_deps {
+ TaskDepsRef::Allow(deps) => deps.lock(),
+ TaskDepsRef::Ignore => return,
+ TaskDepsRef::Forbid => {
+ panic!("Illegal read of: {:?}", dep_node_index)
+ }
+ };
+ let task_deps = &mut *task_deps;
+
+ if cfg!(debug_assertions) {
+ data.current.total_read_count.fetch_add(1, Relaxed);
+ }
+
+ // As long as we only have a low number of reads we can avoid doing a hash
+ // insert and potentially allocating/reallocating the hashmap
+ let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
+ task_deps.reads.iter().all(|other| *other != dep_node_index)
+ } else {
+ task_deps.read_set.insert(dep_node_index)
+ };
+ if new_read {
+ task_deps.reads.push(dep_node_index);
+ if task_deps.reads.len() == TASK_DEPS_READS_CAP {
+ // Fill `read_set` with what we have so far so we can use the hashset
+ // next time
+ task_deps.read_set.extend(task_deps.reads.iter().copied());
}
- // As long as we only have a low number of reads we can avoid doing a hash
- // insert and potentially allocating/reallocating the hashmap
- let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
- task_deps.reads.iter().all(|other| *other != dep_node_index)
- } else {
- task_deps.read_set.insert(dep_node_index)
- };
- if new_read {
- task_deps.reads.push(dep_node_index);
- if task_deps.reads.len() == TASK_DEPS_READS_CAP {
- // Fill `read_set` with what we have so far so we can use the hashset
- // next time
- task_deps.read_set.extend(task_deps.reads.iter().copied());
- }
-
- #[cfg(debug_assertions)]
- {
- if let Some(target) = task_deps.node {
- if let Some(ref forbidden_edge) = data.current.forbidden_edge {
- let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
- if forbidden_edge.test(&src, &target) {
- panic!("forbidden edge {:?} -> {:?} created", src, target)
- }
+ #[cfg(debug_assertions)]
+ {
+ if let Some(target) = task_deps.node {
+ if let Some(ref forbidden_edge) = data.current.forbidden_edge {
+ let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
+ if forbidden_edge.test(&src, &target) {
+ panic!("forbidden edge {:?} -> {:?} created", src, target)
}
}
}
- } else if cfg!(debug_assertions) {
- data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
}
+ } else if cfg!(debug_assertions) {
+ data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
}
})
}
@@ -1123,7 +1192,26 @@
const TASK_DEPS_READS_CAP: usize = 8;
type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
-pub struct TaskDeps<K> {
+#[derive(Debug, Clone, Copy)]
+pub enum TaskDepsRef<'a, K: DepKind> {
+ /// New dependencies can be added to the
+ /// `TaskDeps`. This is used when executing a 'normal' query
+ /// (no `eval_always` modifier)
+ Allow(&'a Lock<TaskDeps<K>>),
+ /// New dependencies are ignored. This is used when
+ /// executing an `eval_always` query, since there's no
+ /// need to track dependencies for a query that's always
+ /// re-executed. This is also used for `dep_graph.with_ignore`
+ Ignore,
+ /// Any attempt to add new dependencies will cause a panic.
+ /// This is used when decoding a query result from disk,
+ /// to ensure that the decoding process doesn't itself
+ /// require the execution of any queries.
+ Forbid,
+}
+
+#[derive(Debug)]
+pub struct TaskDeps<K: DepKind> {
#[cfg(debug_assertions)]
node: Option<DepNode<K>>,
reads: EdgesVec,
@@ -1131,7 +1219,7 @@
phantom_data: PhantomData<DepNode<K>>,
}
-impl<K> Default for TaskDeps<K> {
+impl<K: DepKind> Default for TaskDeps<K> {
fn default() -> Self {
Self {
#[cfg(debug_assertions)]
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 047fc9f..5907ae3 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -5,13 +5,14 @@
mod serialized;
pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
-pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
+pub use graph::{
+ hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct,
+};
pub use query::DepGraphQuery;
pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
use crate::ich::StableHashingContext;
use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_data_structures::sync::Lock;
use rustc_serialize::{opaque::FileEncoder, Encodable};
use rustc_session::Session;
@@ -90,12 +91,12 @@
fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
/// Execute the operation with provided dependencies.
- fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R
+ fn with_deps<OP, R>(deps: TaskDepsRef<'_, Self>, op: OP) -> R
where
OP: FnOnce() -> R;
/// Access dependencies from current implicit context.
fn read_deps<OP>(op: OP)
where
- OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
+ OP: for<'a> FnOnce(TaskDepsRef<'a, Self>);
}
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 47197a1..c95dff1 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -100,7 +100,7 @@
for SerializedDepGraph<K>
{
#[instrument(level = "debug", skip(d))]
- fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String> {
+ fn decode(d: &mut opaque::Decoder<'a>) -> SerializedDepGraph<K> {
let start_position = d.position();
// The last 16 bytes are the node count and edge count.
@@ -108,8 +108,8 @@
d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE);
debug!("position: {:?}", d.position());
- let node_count = IntEncodedWithFixedSize::decode(d)?.0 as usize;
- let edge_count = IntEncodedWithFixedSize::decode(d)?.0 as usize;
+ let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
+ let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
debug!(?node_count, ?edge_count);
debug!("position: {:?}", d.position());
@@ -123,12 +123,12 @@
for _index in 0..node_count {
d.read_struct(|d| {
- let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?;
+ let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode);
let _i: SerializedDepNodeIndex = nodes.push(dep_node);
debug_assert_eq!(_i.index(), _index);
let fingerprint: Fingerprint =
- d.read_struct_field("fingerprint", Decodable::decode)?;
+ d.read_struct_field("fingerprint", Decodable::decode);
let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint);
debug_assert_eq!(_i.index(), _index);
@@ -136,22 +136,21 @@
d.read_seq(|d, len| {
let start = edge_list_data.len().try_into().unwrap();
for _ in 0..len {
- let edge = d.read_seq_elt(Decodable::decode)?;
+ let edge = d.read_seq_elt(Decodable::decode);
edge_list_data.push(edge);
}
let end = edge_list_data.len().try_into().unwrap();
let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end));
debug_assert_eq!(_i.index(), _index);
- Ok(())
})
})
- })?;
+ });
}
let index: FxHashMap<_, _> =
nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
- Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index })
+ SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
}
}
@@ -183,7 +182,7 @@
total_edge_count: 0,
total_node_count: 0,
result: Ok(()),
- stats: if record_stats { Some(FxHashMap::default()) } else { None },
+ stats: record_stats.then(FxHashMap::default),
}
}
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index 5f31fa0..76e21be 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -3,6 +3,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashingControls, NodeIdHashingMode};
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -26,20 +27,15 @@
pub struct StableHashingContext<'a> {
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
+ // The value of `-Z incremental-ignore-spans`.
+ // This field should only be used by `debug_opts_incremental_ignore_span`
+ incremental_ignore_spans: bool,
pub(super) body_resolver: BodyResolver<'a>,
- hash_spans: bool,
- pub(super) node_id_hashing_mode: NodeIdHashingMode,
-
// Very often, we are hashing something that does not need the
// `CachingSourceMapView`, so we initialize it lazily.
raw_source_map: &'a SourceMap,
caching_source_map: Option<CachingSourceMapView<'a>>,
-}
-
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub enum NodeIdHashingMode {
- Ignore,
- HashDefPath,
+ pub(super) hashing_controls: HashingControls,
}
/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
@@ -70,10 +66,13 @@
body_resolver: BodyResolver::Forbidden,
definitions,
cstore,
+ incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans,
caching_source_map: None,
raw_source_map: sess.source_map(),
- hash_spans: hash_spans_initial,
- node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+ hashing_controls: HashingControls {
+ hash_spans: hash_spans_initial,
+ node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+ },
}
}
@@ -133,10 +132,10 @@
#[inline]
pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
- let prev_hash_spans = self.hash_spans;
- self.hash_spans = hash_spans;
+ let prev_hash_spans = self.hashing_controls.hash_spans;
+ self.hashing_controls.hash_spans = hash_spans;
f(self);
- self.hash_spans = prev_hash_spans;
+ self.hashing_controls.hash_spans = prev_hash_spans;
}
#[inline]
@@ -145,10 +144,10 @@
mode: NodeIdHashingMode,
f: F,
) {
- let prev = self.node_id_hashing_mode;
- self.node_id_hashing_mode = mode;
+ let prev = self.hashing_controls.node_id_hashing_mode;
+ self.hashing_controls.node_id_hashing_mode = mode;
f(self);
- self.node_id_hashing_mode = prev;
+ self.hashing_controls.node_id_hashing_mode = prev;
}
#[inline]
@@ -183,6 +182,11 @@
}
IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
}
+
+ #[inline]
+ pub fn hashing_controls(&self) -> HashingControls {
+ self.hashing_controls.clone()
+ }
}
impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
@@ -195,7 +199,12 @@
impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
#[inline]
fn hash_spans(&self) -> bool {
- self.hash_spans
+ self.hashing_controls.hash_spans
+ }
+
+ #[inline]
+ fn debug_opts_incremental_ignore_spans(&self) -> bool {
+ self.incremental_ignore_spans
}
#[inline]
@@ -215,6 +224,11 @@
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
self.source_map().span_data_to_lines_and_cols(span)
}
+
+ #[inline]
+ fn hashing_controls(&self) -> HashingControls {
+ self.hashing_controls.clone()
+ }
}
impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs
index 3117140..bf3cf6a 100644
--- a/compiler/rustc_query_system/src/ich/impls_hir.rs
+++ b/compiler/rustc_query_system/src/ich/impls_hir.rs
@@ -11,7 +11,7 @@
#[inline]
fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
let hcx = self;
- match hcx.node_id_hashing_mode {
+ match hcx.hashing_controls.node_id_hashing_mode {
NodeIdHashingMode::Ignore => {
// Don't do anything.
}
@@ -89,12 +89,12 @@
#[inline]
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
- let prev_hash_node_ids = self.node_id_hashing_mode;
- self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+ let prev_hash_node_ids = self.hashing_controls.node_id_hashing_mode;
+ self.hashing_controls.node_id_hashing_mode = NodeIdHashingMode::Ignore;
f(self);
- self.node_id_hashing_mode = prev_hash_node_ids;
+ self.hashing_controls.node_id_hashing_mode = prev_hash_node_ids;
}
#[inline]
diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs
index 5441690..c42fcc9 100644
--- a/compiler/rustc_query_system/src/ich/mod.rs
+++ b/compiler/rustc_query_system/src/ich/mod.rs
@@ -1,6 +1,7 @@
//! ICH - Incremental Compilation Hash
-pub use self::hcx::{NodeIdHashingMode, StableHashingContext};
+pub use self::hcx::StableHashingContext;
+pub use rustc_data_structures::stable_hasher::NodeIdHashingMode;
use rustc_span::symbol::{sym, Symbol};
mod hcx;
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 0436e07..750ac76 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -5,6 +5,7 @@
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(extern_types)]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index d2b102b..b1ff1e1 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -59,7 +59,7 @@
fn describe(tcx: CTX, key: Self::Key) -> String;
// Don't use this method to access query results, instead use the methods on TyCtxt
- fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, Self::Key>
+ fn query_state<'a>(tcx: CTX) -> &'a QueryState<Self::Key>
where
CTX: 'a;
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index bd67303..adf878a 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -7,13 +7,11 @@
use rustc_session::Session;
use rustc_span::Span;
-use std::convert::TryFrom;
use std::hash::Hash;
-use std::num::NonZeroU32;
+use std::num::NonZeroU64;
#[cfg(parallel_compiler)]
use {
- crate::dep_graph::DepKind,
parking_lot::{Condvar, Mutex},
rustc_data_structures::fx::FxHashSet,
rustc_data_structures::sync::Lock,
@@ -33,80 +31,57 @@
pub query: QueryStackFrame,
}
-pub type QueryMap<D> = FxHashMap<QueryJobId<D>, QueryJobInfo<D>>;
-
-/// A value uniquely identifying an active query job within a shard in the query cache.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct QueryShardJobId(pub NonZeroU32);
+pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>;
/// A value uniquely identifying an active query job.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct QueryJobId<D> {
- /// Which job within a shard is this
- pub job: QueryShardJobId,
+pub struct QueryJobId(pub NonZeroU64);
- /// In which shard is this job
- pub shard: u16,
-
- /// What kind of query this job is.
- pub kind: D,
-}
-
-impl<D> QueryJobId<D>
-where
- D: Copy + Clone + Eq + Hash,
-{
- pub fn new(job: QueryShardJobId, shard: usize, kind: D) -> Self {
- QueryJobId { job, shard: u16::try_from(shard).unwrap(), kind }
- }
-
- fn query(self, map: &QueryMap<D>) -> QueryStackFrame {
+impl QueryJobId {
+ fn query(self, map: &QueryMap) -> QueryStackFrame {
map.get(&self).unwrap().query.clone()
}
#[cfg(parallel_compiler)]
- fn span(self, map: &QueryMap<D>) -> Span {
+ fn span(self, map: &QueryMap) -> Span {
map.get(&self).unwrap().job.span
}
#[cfg(parallel_compiler)]
- fn parent(self, map: &QueryMap<D>) -> Option<QueryJobId<D>> {
+ fn parent(self, map: &QueryMap) -> Option<QueryJobId> {
map.get(&self).unwrap().job.parent
}
#[cfg(parallel_compiler)]
- fn latch<'a>(self, map: &'a QueryMap<D>) -> Option<&'a QueryLatch<D>> {
+ fn latch<'a>(self, map: &'a QueryMap) -> Option<&'a QueryLatch> {
map.get(&self).unwrap().job.latch.as_ref()
}
}
-pub struct QueryJobInfo<D> {
+pub struct QueryJobInfo {
pub query: QueryStackFrame,
- pub job: QueryJob<D>,
+ pub job: QueryJob,
}
/// Represents an active query job.
#[derive(Clone)]
-pub struct QueryJob<D> {
- pub id: QueryShardJobId,
+pub struct QueryJob {
+ pub id: QueryJobId,
/// The span corresponding to the reason for which this query was required.
pub span: Span,
/// The parent query job which created this job and is implicitly waiting on it.
- pub parent: Option<QueryJobId<D>>,
+ pub parent: Option<QueryJobId>,
/// The latch that is used to wait on this job.
#[cfg(parallel_compiler)]
- latch: Option<QueryLatch<D>>,
+ latch: Option<QueryLatch>,
}
-impl<D> QueryJob<D>
-where
- D: Copy + Clone + Eq + Hash,
-{
+impl QueryJob {
/// Creates a new query job.
- pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId<D>>) -> Self {
+ pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
QueryJob {
id,
span,
@@ -117,7 +92,7 @@
}
#[cfg(parallel_compiler)]
- pub(super) fn latch(&mut self) -> QueryLatch<D> {
+ pub(super) fn latch(&mut self) -> QueryLatch {
if self.latch.is_none() {
self.latch = Some(QueryLatch::new());
}
@@ -139,16 +114,13 @@
}
#[cfg(not(parallel_compiler))]
-impl<D> QueryJobId<D>
-where
- D: Copy + Clone + Eq + Hash,
-{
+impl QueryJobId {
#[cold]
#[inline(never)]
pub(super) fn find_cycle_in_stack(
&self,
- query_map: QueryMap<D>,
- current_job: &Option<QueryJobId<D>>,
+ query_map: QueryMap,
+ current_job: &Option<QueryJobId>,
span: Span,
) -> CycleError {
// Find the waitee amongst `current_job` parents
@@ -184,15 +156,15 @@
}
#[cfg(parallel_compiler)]
-struct QueryWaiter<D> {
- query: Option<QueryJobId<D>>,
+struct QueryWaiter {
+ query: Option<QueryJobId>,
condvar: Condvar,
span: Span,
cycle: Lock<Option<CycleError>>,
}
#[cfg(parallel_compiler)]
-impl<D> QueryWaiter<D> {
+impl QueryWaiter {
fn notify(&self, registry: &rayon_core::Registry) {
rayon_core::mark_unblocked(registry);
self.condvar.notify_one();
@@ -200,34 +172,27 @@
}
#[cfg(parallel_compiler)]
-struct QueryLatchInfo<D> {
+struct QueryLatchInfo {
complete: bool,
- waiters: Vec<Lrc<QueryWaiter<D>>>,
+ waiters: Vec<Lrc<QueryWaiter>>,
}
#[cfg(parallel_compiler)]
#[derive(Clone)]
-pub(super) struct QueryLatch<D> {
- info: Lrc<Mutex<QueryLatchInfo<D>>>,
+pub(super) struct QueryLatch {
+ info: Lrc<Mutex<QueryLatchInfo>>,
}
#[cfg(parallel_compiler)]
-impl<D: Eq + Hash> QueryLatch<D> {
+impl QueryLatch {
fn new() -> Self {
QueryLatch {
info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
}
}
-}
-#[cfg(parallel_compiler)]
-impl<D> QueryLatch<D> {
/// Awaits for the query job to complete.
- pub(super) fn wait_on(
- &self,
- query: Option<QueryJobId<D>>,
- span: Span,
- ) -> Result<(), CycleError> {
+ pub(super) fn wait_on(&self, query: Option<QueryJobId>, span: Span) -> Result<(), CycleError> {
let waiter =
Lrc::new(QueryWaiter { query, span, cycle: Lock::new(None), condvar: Condvar::new() });
self.wait_on_inner(&waiter);
@@ -242,7 +207,7 @@
}
/// Awaits the caller on this latch by blocking the current thread.
- fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<D>>) {
+ fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter>) {
let mut info = self.info.lock();
if !info.complete {
// We push the waiter on to the `waiters` list. It can be accessed inside
@@ -276,7 +241,7 @@
/// Removes a single waiter from the list of waiters.
/// This is used to break query cycles.
- fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<D>> {
+ fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter> {
let mut info = self.info.lock();
debug_assert!(!info.complete);
// Remove the waiter from the list of waiters
@@ -286,7 +251,7 @@
/// A resumable waiter of a query. The usize is the index into waiters in the query's latch
#[cfg(parallel_compiler)]
-type Waiter<D> = (QueryJobId<D>, usize);
+type Waiter = (QueryJobId, usize);
/// Visits all the non-resumable and resumable waiters of a query.
/// Only waiters in a query are visited.
@@ -298,14 +263,9 @@
/// required information to resume the waiter.
/// If all `visit` calls returns None, this function also returns None.
#[cfg(parallel_compiler)]
-fn visit_waiters<D, F>(
- query_map: &QueryMap<D>,
- query: QueryJobId<D>,
- mut visit: F,
-) -> Option<Option<Waiter<D>>>
+fn visit_waiters<F>(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option<Option<Waiter>>
where
- D: Copy + Clone + Eq + Hash,
- F: FnMut(Span, QueryJobId<D>) -> Option<Option<Waiter<D>>>,
+ F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>,
{
// Visit the parent query which is a non-resumable waiter since it's on the same stack
if let Some(parent) = query.parent(query_map) {
@@ -334,16 +294,13 @@
/// If a cycle is detected, this initial value is replaced with the span causing
/// the cycle.
#[cfg(parallel_compiler)]
-fn cycle_check<D>(
- query_map: &QueryMap<D>,
- query: QueryJobId<D>,
+fn cycle_check(
+ query_map: &QueryMap,
+ query: QueryJobId,
span: Span,
- stack: &mut Vec<(Span, QueryJobId<D>)>,
- visited: &mut FxHashSet<QueryJobId<D>>,
-) -> Option<Option<Waiter<D>>>
-where
- D: Copy + Clone + Eq + Hash,
-{
+ stack: &mut Vec<(Span, QueryJobId)>,
+ visited: &mut FxHashSet<QueryJobId>,
+) -> Option<Option<Waiter>> {
if !visited.insert(query) {
return if let Some(p) = stack.iter().position(|q| q.1 == query) {
// We detected a query cycle, fix up the initial span and return Some
@@ -378,14 +335,11 @@
/// from `query` without going through any of the queries in `visited`.
/// This is achieved with a depth first search.
#[cfg(parallel_compiler)]
-fn connected_to_root<D>(
- query_map: &QueryMap<D>,
- query: QueryJobId<D>,
- visited: &mut FxHashSet<QueryJobId<D>>,
-) -> bool
-where
- D: Copy + Clone + Eq + Hash,
-{
+fn connected_to_root(
+ query_map: &QueryMap,
+ query: QueryJobId,
+ visited: &mut FxHashSet<QueryJobId>,
+) -> bool {
// We already visited this or we're deliberately ignoring it
if !visited.insert(query) {
return false;
@@ -404,10 +358,9 @@
// Deterministically pick an query from a list
#[cfg(parallel_compiler)]
-fn pick_query<'a, D, T, F>(query_map: &QueryMap<D>, queries: &'a [T], f: F) -> &'a T
+fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T
where
- D: Copy + Clone + Eq + Hash,
- F: Fn(&T) -> (Span, QueryJobId<D>),
+ F: Fn(&T) -> (Span, QueryJobId),
{
// Deterministically pick an entry point
// FIXME: Sort this instead
@@ -431,10 +384,10 @@
/// If a cycle was not found, the starting query is removed from `jobs` and
/// the function returns false.
#[cfg(parallel_compiler)]
-fn remove_cycle<D: DepKind>(
- query_map: &QueryMap<D>,
- jobs: &mut Vec<QueryJobId<D>>,
- wakelist: &mut Vec<Lrc<QueryWaiter<D>>>,
+fn remove_cycle(
+ query_map: &QueryMap,
+ jobs: &mut Vec<QueryJobId>,
+ wakelist: &mut Vec<Lrc<QueryWaiter>>,
) -> bool {
let mut visited = FxHashSet::default();
let mut stack = Vec::new();
@@ -489,7 +442,7 @@
}
}
})
- .collect::<Vec<(Span, QueryJobId<D>, Option<(Span, QueryJobId<D>)>)>>();
+ .collect::<Vec<(Span, QueryJobId, Option<(Span, QueryJobId)>)>>();
// Deterministically pick an entry point
let (_, entry_point, usage) = pick_query(query_map, &entry_points, |e| (e.0, e.1));
@@ -544,7 +497,7 @@
let mut wakelist = Vec::new();
let query_map = tcx.try_collect_active_jobs().unwrap();
- let mut jobs: Vec<QueryJobId<CTX::DepKind>> = query_map.keys().cloned().collect();
+ let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
let mut found_cycle = false;
@@ -630,7 +583,7 @@
pub fn print_query_stack<CTX: QueryContext>(
tcx: CTX,
- mut current_query: Option<QueryJobId<CTX::DepKind>>,
+ mut current_query: Option<QueryJobId>,
handler: &Handler,
num_frames: Option<usize>,
) -> usize {
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index a2f7843..361ae3c 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -117,10 +117,12 @@
}
pub trait QueryContext: HasDepContext {
- /// Get the query information from the TLS context.
- fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
+ fn next_job_id(&self) -> QueryJobId;
- fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>>;
+ /// Get the query information from the TLS context.
+ fn current_query_job(&self) -> Option<QueryJobId>;
+
+ fn try_collect_active_jobs(&self) -> Option<QueryMap>;
/// Load side effects associated to the node in the previous session.
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
@@ -140,7 +142,7 @@
/// captured during execution and the actual result.
fn start_query<R>(
&self,
- token: QueryJobId<Self::DepKind>,
+ token: QueryJobId,
diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
compute: impl FnOnce() -> R,
) -> R;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 33732f9..77e1fd3 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -5,11 +5,8 @@
use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
use crate::query::caches::QueryCache;
use crate::query::config::{QueryDescription, QueryVtable};
-use crate::query::job::{
- report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
-};
+use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
-
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHasher};
#[cfg(parallel_compiler)]
@@ -25,7 +22,6 @@
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::mem;
-use std::num::NonZeroU32;
use std::ptr;
pub struct QueryCacheStore<C: QueryCache> {
@@ -70,36 +66,32 @@
}
}
-struct QueryStateShard<D, K> {
- active: FxHashMap<K, QueryResult<D>>,
-
- /// Used to generate unique ids for active jobs.
- jobs: u32,
+struct QueryStateShard<K> {
+ active: FxHashMap<K, QueryResult>,
}
-impl<D, K> Default for QueryStateShard<D, K> {
- fn default() -> QueryStateShard<D, K> {
- QueryStateShard { active: Default::default(), jobs: 0 }
+impl<K> Default for QueryStateShard<K> {
+ fn default() -> QueryStateShard<K> {
+ QueryStateShard { active: Default::default() }
}
}
-pub struct QueryState<D, K> {
- shards: Sharded<QueryStateShard<D, K>>,
+pub struct QueryState<K> {
+ shards: Sharded<QueryStateShard<K>>,
}
/// Indicates the state of a query for a given key in a query map.
-enum QueryResult<D> {
+enum QueryResult {
/// An already executing query. The query job can be used to await for its completion.
- Started(QueryJob<D>),
+ Started(QueryJob),
/// The query panicked. Queries trying to wait on this will raise a fatal error which will
/// silently panic.
Poisoned,
}
-impl<D, K> QueryState<D, K>
+impl<K> QueryState<K>
where
- D: Copy + Clone + Eq + Hash,
K: Eq + Hash + Clone + Debug,
{
pub fn all_inactive(&self) -> bool {
@@ -110,19 +102,17 @@
pub fn try_collect_active_jobs<CTX: Copy>(
&self,
tcx: CTX,
- kind: D,
make_query: fn(CTX, K) -> QueryStackFrame,
- jobs: &mut QueryMap<D>,
+ jobs: &mut QueryMap,
) -> Option<()> {
// We use try_lock_shards here since we are called from the
// deadlock handler, and this shouldn't be locked.
let shards = self.shards.try_lock_shards()?;
- for (shard_id, shard) in shards.iter().enumerate() {
+ for shard in shards.iter() {
for (k, v) in shard.active.iter() {
if let QueryResult::Started(ref job) = *v {
- let id = QueryJobId::new(job.id, shard_id, kind);
let query = make_query(tcx, k.clone());
- jobs.insert(id, QueryJobInfo { query, job: job.clone() });
+ jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
}
}
}
@@ -131,22 +121,21 @@
}
}
-impl<D, K> Default for QueryState<D, K> {
- fn default() -> QueryState<D, K> {
+impl<K> Default for QueryState<K> {
+ fn default() -> QueryState<K> {
QueryState { shards: Default::default() }
}
}
/// A type representing the responsibility to execute the job in the `job` field.
/// This will poison the relevant query if dropped.
-struct JobOwner<'tcx, D, K>
+struct JobOwner<'tcx, K>
where
- D: Copy + Clone + Eq + Hash,
K: Eq + Hash + Clone,
{
- state: &'tcx QueryState<D, K>,
+ state: &'tcx QueryState<K>,
key: K,
- id: QueryJobId<D>,
+ id: QueryJobId,
}
#[cold]
@@ -167,9 +156,8 @@
cache.store_nocache(value)
}
-impl<'tcx, D, K> JobOwner<'tcx, D, K>
+impl<'tcx, K> JobOwner<'tcx, K>
where
- D: Copy + Clone + Eq + Hash,
K: Eq + Hash + Clone,
{
/// Either gets a `JobOwner` corresponding the query, allowing us to
@@ -183,12 +171,11 @@
#[inline(always)]
fn try_start<'b, CTX>(
tcx: &'b CTX,
- state: &'b QueryState<CTX::DepKind, K>,
+ state: &'b QueryState<K>,
span: Span,
key: K,
lookup: QueryLookup,
- dep_kind: CTX::DepKind,
- ) -> TryGetJob<'b, CTX::DepKind, K>
+ ) -> TryGetJob<'b, K>
where
CTX: QueryContext,
{
@@ -198,27 +185,21 @@
match lock.active.entry(key) {
Entry::Vacant(entry) => {
- // Generate an id unique within this shard.
- let id = lock.jobs.checked_add(1).unwrap();
- lock.jobs = id;
- let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
-
+ let id = tcx.next_job_id();
let job = tcx.current_query_job();
let job = QueryJob::new(id, span, job);
let key = entry.key().clone();
entry.insert(QueryResult::Started(job));
- let global_id = QueryJobId::new(id, shard, dep_kind);
- let owner = JobOwner { state, id: global_id, key };
+ let owner = JobOwner { state, id, key };
return TryGetJob::NotYetStarted(owner);
}
Entry::Occupied(mut entry) => {
match entry.get_mut() {
#[cfg(not(parallel_compiler))]
QueryResult::Started(job) => {
- let id = QueryJobId::new(job.id, shard, dep_kind);
-
+ let id = job.id;
drop(state_lock);
// If we are single-threaded we know that we have cycle error,
@@ -296,9 +277,8 @@
}
}
-impl<'tcx, D, K> Drop for JobOwner<'tcx, D, K>
+impl<'tcx, K> Drop for JobOwner<'tcx, K>
where
- D: Copy + Clone + Eq + Hash,
K: Eq + Hash + Clone,
{
#[inline(never)]
@@ -330,13 +310,12 @@
}
/// The result of `try_start`.
-enum TryGetJob<'tcx, D, K>
+enum TryGetJob<'tcx, K>
where
- D: Copy + Clone + Eq + Hash,
K: Eq + Hash + Clone,
{
/// The query is not yet started. Contains a guard to the cache eventually used to start it.
- NotYetStarted(JobOwner<'tcx, D, K>),
+ NotYetStarted(JobOwner<'tcx, K>),
/// The query was already completed.
/// Returns the result of the query and its dep-node index
@@ -376,7 +355,7 @@
fn try_execute_query<CTX, C>(
tcx: CTX,
- state: &QueryState<CTX::DepKind, C::Key>,
+ state: &QueryState<C::Key>,
cache: &QueryCacheStore<C>,
span: Span,
key: C::Key,
@@ -389,14 +368,7 @@
C::Key: Clone + DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- match JobOwner::<'_, CTX::DepKind, C::Key>::try_start(
- &tcx,
- state,
- span,
- key.clone(),
- lookup,
- query.dep_kind,
- ) {
+ match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone(), lookup) {
TryGetJob::NotYetStarted(job) => {
let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
let result = job.complete(cache, result, dep_node_index);
@@ -428,7 +400,7 @@
key: K,
mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
query: &QueryVtable<CTX, K, V>,
- job_id: QueryJobId<CTX::DepKind>,
+ job_id: QueryJobId,
) -> (V, DepNodeIndex)
where
K: Clone + DepNodeParams<CTX::DepContext>,
@@ -515,7 +487,13 @@
// Some things are never cached on disk.
if query.cache_on_disk {
let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
- let result = query.try_load_from_disk(tcx, prev_dep_node_index);
+
+ // The call to `with_query_deserialization` enforces that no new `DepNodes`
+ // are created during deserialization. See the docs of that method for more
+ // details.
+ let result = dep_graph
+ .with_query_deserialization(|| query.try_load_from_disk(tcx, prev_dep_node_index));
+
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some(result) = result {
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
new file mode 100644
index 0000000..60cc424
--- /dev/null
+++ b/compiler/rustc_resolve/src/access_levels.rs
@@ -0,0 +1,237 @@
+use rustc_ast::ast;
+use rustc_ast::visit;
+use rustc_ast::visit::Visitor;
+use rustc_ast::Crate;
+use rustc_ast::EnumDef;
+use rustc_ast::ForeignMod;
+use rustc_ast::NodeId;
+use rustc_ast_lowering::ResolverAstLowering;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::AccessLevel;
+use rustc_middle::ty::Visibility;
+use rustc_span::sym;
+
+use crate::imports::ImportKind;
+use crate::BindingKey;
+use crate::NameBinding;
+use crate::NameBindingKind;
+use crate::Resolver;
+
+pub struct AccessLevelsVisitor<'r, 'a> {
+ r: &'r mut Resolver<'a>,
+ prev_level: Option<AccessLevel>,
+ changed: bool,
+}
+
+impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
+ /// Fills the `Resolver::access_levels` table with public & exported items
+ /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
+ /// need access to a TyCtxt for that.
+ pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+ let mut visitor =
+ AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) };
+
+ visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
+ visitor.set_exports_access_level(CRATE_DEF_ID);
+
+ while visitor.changed {
+ visitor.reset();
+ visit::walk_crate(&mut visitor, krate);
+ }
+
+ tracing::info!("resolve::access_levels: {:#?}", r.access_levels);
+ }
+
+ fn reset(&mut self) {
+ self.changed = false;
+ self.prev_level = Some(AccessLevel::Public);
+ }
+
+ /// Update the access level of the exports of the given module accordingly. The module access
+ /// level has to be Exported or Public.
+ /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
+ fn set_exports_access_level(&mut self, module_id: LocalDefId) {
+ assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+
+ // Set the given binding access level to `AccessLevel::Public` and
+ // sets the rest of the `use` chain to `AccessLevel::Exported` until
+ // we hit the actual exported item.
+ let set_import_binding_access_level =
+ |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level| {
+ while let NameBindingKind::Import { binding: nested_binding, import, .. } =
+ binding.kind
+ {
+ this.set_access_level(import.id, access_level);
+ if let ImportKind::Single { additional_ids, .. } = import.kind {
+ this.set_access_level(additional_ids.0, access_level);
+ this.set_access_level(additional_ids.1, access_level);
+ }
+
+ access_level = Some(AccessLevel::Exported);
+ binding = nested_binding;
+ }
+ };
+
+ let module_level = self.r.access_levels.map.get(&module_id).copied();
+ assert!(module_level >= Some(AccessLevel::Exported));
+
+ if let Some(exports) = self.r.reexport_map.get(&module_id) {
+ let pub_exports = exports
+ .iter()
+ .filter(|ex| ex.vis == Visibility::Public)
+ .cloned()
+ .collect::<Vec<_>>();
+
+ let module = self.r.get_module(module_id.to_def_id()).unwrap();
+ for export in pub_exports.into_iter() {
+ if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) {
+ self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported));
+ }
+
+ if let Some(ns) = export.res.ns() {
+ let key = BindingKey { ident: export.ident, ns, disambiguator: 0 };
+ let name_res = self.r.resolution(module, key);
+ if let Some(binding) = name_res.borrow().binding() {
+ set_import_binding_access_level(self, binding, module_level)
+ }
+ }
+ }
+ }
+ }
+
+ /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`.
+ /// This function will panic if the `NodeId` does not have a `LocalDefId`
+ fn set_access_level(
+ &mut self,
+ node_id: NodeId,
+ access_level: Option<AccessLevel>,
+ ) -> Option<AccessLevel> {
+ self.set_access_level_def_id(self.r.local_def_id(node_id), access_level)
+ }
+
+ fn set_access_level_def_id(
+ &mut self,
+ def_id: LocalDefId,
+ access_level: Option<AccessLevel>,
+ ) -> Option<AccessLevel> {
+ let old_level = self.r.access_levels.map.get(&def_id).copied();
+ if old_level < access_level {
+ self.r.access_levels.map.insert(def_id, access_level.unwrap());
+ self.changed = true;
+ access_level
+ } else {
+ old_level
+ }
+ }
+}
+
+impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
+ fn visit_item(&mut self, item: &'ast ast::Item) {
+ let inherited_item_level = match item.kind {
+ // Resolved in rustc_privacy when types are available
+ ast::ItemKind::Impl(..) => return,
+
+ // Only exported `macro_rules!` items are public, but they always are
+ ast::ItemKind::MacroDef(..) => {
+ let is_macro_export =
+ item.attrs.iter().any(|attr| attr.has_name(sym::macro_export));
+ if is_macro_export { Some(AccessLevel::Public) } else { None }
+ }
+
+ // Foreign modules inherit level from parents.
+ ast::ItemKind::ForeignMod(..) => self.prev_level,
+
+ // Other `pub` items inherit levels from parents.
+ ast::ItemKind::ExternCrate(..)
+ | ast::ItemKind::Use(..)
+ | ast::ItemKind::Static(..)
+ | ast::ItemKind::Const(..)
+ | ast::ItemKind::Fn(..)
+ | ast::ItemKind::Mod(..)
+ | ast::ItemKind::GlobalAsm(..)
+ | ast::ItemKind::TyAlias(..)
+ | ast::ItemKind::Enum(..)
+ | ast::ItemKind::Struct(..)
+ | ast::ItemKind::Union(..)
+ | ast::ItemKind::Trait(..)
+ | ast::ItemKind::TraitAlias(..) => {
+ if item.vis.kind.is_pub() {
+ self.prev_level
+ } else {
+ None
+ }
+ }
+
+ // Should be unreachable at this stage
+ ast::ItemKind::MacCall(..) => panic!(
+ "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
+ ),
+ };
+
+ let access_level = self.set_access_level(item.id, inherited_item_level);
+
+ // Set access level of nested items.
+ // If it's a mod, also make the visitor walk all of its items
+ match item.kind {
+ ast::ItemKind::Mod(..) => {
+ if access_level.is_some() {
+ self.set_exports_access_level(self.r.local_def_id(item.id));
+ }
+
+ let orig_level = std::mem::replace(&mut self.prev_level, access_level);
+ visit::walk_item(self, item);
+ self.prev_level = orig_level;
+ }
+
+ ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => {
+ for nested in items {
+ if nested.vis.kind.is_pub() {
+ self.set_access_level(nested.id, access_level);
+ }
+ }
+ }
+ ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+ for variant in variants {
+ let variant_level = self.set_access_level(variant.id, access_level);
+ if let Some(ctor_id) = variant.data.ctor_id() {
+ self.set_access_level(ctor_id, access_level);
+ }
+
+ for field in variant.data.fields() {
+ self.set_access_level(field.id, variant_level);
+ }
+ }
+ }
+ ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+ if let Some(ctor_id) = def.ctor_id() {
+ self.set_access_level(ctor_id, access_level);
+ }
+
+ for field in def.fields() {
+ if field.vis.kind.is_pub() {
+ self.set_access_level(field.id, access_level);
+ }
+ }
+ }
+ ast::ItemKind::Trait(ref trait_kind) => {
+ for nested in trait_kind.items.iter() {
+ self.set_access_level(nested.id, access_level);
+ }
+ }
+
+ ast::ItemKind::ExternCrate(..)
+ | ast::ItemKind::Use(..)
+ | ast::ItemKind::Static(..)
+ | ast::ItemKind::Const(..)
+ | ast::ItemKind::GlobalAsm(..)
+ | ast::ItemKind::TyAlias(..)
+ | ast::ItemKind::TraitAlias(..)
+ | ast::ItemKind::MacroDef(..)
+ | ast::ItemKind::Fn(..) => return,
+
+ // Unreachable kinds
+ ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(),
+ }
+ }
+}
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 39074f8..3fa9343 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -26,7 +26,7 @@
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_metadata::creader::LoadedMacro;
use rustc_middle::bug;
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::ty;
use rustc_session::cstore::CrateStore;
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
@@ -108,7 +108,7 @@
/// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
/// but they cannot use def-site hygiene, so the assumption holds
/// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
- crate fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
+ pub fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
loop {
match self.get_module(def_id) {
Some(module) => return module,
@@ -214,7 +214,7 @@
}
crate fn build_reduced_graph_external(&mut self, module: Module<'a>) {
- for child in self.cstore().item_children_untracked(module.def_id(), self.session) {
+ for child in self.cstore().module_children_untracked(module.def_id(), self.session) {
let parent_scope = ParentScope::module(module, self);
BuildReducedGraphVisitor { r: self, parent_scope }
.build_reduced_graph_for_external_crate_res(child);
@@ -383,8 +383,6 @@
used: Cell::new(false),
});
- debug!("add_import({:?})", import);
-
self.r.indeterminate_imports.push(import);
match import.kind {
// Don't add unresolved underscore imports to modules
@@ -455,7 +453,7 @@
prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
};
match use_tree.kind {
- ast::UseTreeKind::Simple(rename, ..) => {
+ ast::UseTreeKind::Simple(rename, id1, id2) => {
let mut ident = use_tree.ident();
let mut module_path = prefix;
let mut source = module_path.pop().unwrap();
@@ -565,7 +563,9 @@
},
type_ns_only,
nested,
+ additional_ids: (id1, id2),
};
+
self.add_import(
module_path,
kind,
@@ -938,9 +938,9 @@
}
/// Builds the reduced graph for a single item in an external crate.
- fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
+ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
let parent = self.parent_scope.module;
- let Export { ident, res, vis, span } = child;
+ let ModChild { ident, res, vis, span } = child;
let res = res.expect_non_local();
let expansion = self.parent_scope.expansion;
// Record primary definitions.
@@ -991,7 +991,7 @@
_,
)
| Res::Local(..)
- | Res::SelfTy(..)
+ | Res::SelfTy { .. }
| Res::SelfCtor(..)
| Res::Err => bug!("unexpected resolution: {:?}", res),
}
@@ -999,12 +999,14 @@
let cstore = self.r.cstore();
match res {
Res::Def(DefKind::Struct, def_id) => {
- let field_names = cstore.struct_field_names_untracked(def_id, self.r.session);
+ let field_names =
+ cstore.struct_field_names_untracked(def_id, self.r.session).collect();
let ctor = cstore.ctor_def_id_and_kind_untracked(def_id);
if let Some((ctor_def_id, ctor_kind)) = ctor {
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let ctor_vis = cstore.visibility_untracked(ctor_def_id);
- let field_visibilities = cstore.struct_field_visibilities_untracked(def_id);
+ let field_visibilities =
+ cstore.struct_field_visibilities_untracked(def_id).collect();
self.r
.struct_constructors
.insert(def_id, (ctor_res, ctor_vis, field_visibilities));
@@ -1012,7 +1014,8 @@
self.insert_field_names(def_id, field_names);
}
Res::Def(DefKind::Union, def_id) => {
- let field_names = cstore.struct_field_names_untracked(def_id, self.r.session);
+ let field_names =
+ cstore.struct_field_names_untracked(def_id, self.r.session).collect();
self.insert_field_names(def_id, field_names);
}
Res::Def(DefKind::AssocFn, def_id) => {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4feeae5..9a2fb3b 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -123,7 +123,7 @@
let sm = self.session.source_map();
match outer_res {
- Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
+ Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
if let Some(impl_span) =
maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
{
@@ -453,28 +453,28 @@
// edit:
// only do this if the const and usage of the non-constant value are on the same line
// the further the two are apart, the higher the chance of the suggestion being wrong
- // also make sure that the pos for the suggestion is not 0 (ICE #90878)
- let sp =
- self.session.source_map().span_extend_to_prev_str(ident.span, current, true);
+ let sp = self
+ .session
+ .source_map()
+ .span_extend_to_prev_str(ident.span, current, true, false);
- let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32);
-
- if sp.lo().0 == 0
- || pos_for_suggestion == 0
- || self.session.source_map().is_multiline(sp)
- {
- err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
- } else {
- let sp = sp.with_lo(BytePos(pos_for_suggestion));
- err.span_suggestion(
- sp,
- &format!("consider using `{}` instead of `{}`", sugg, current),
- format!("{} {}", sugg, ident),
- Applicability::MaybeIncorrect,
- );
- err.span_label(span, "non-constant value");
+ match sp {
+ Some(sp) if !self.session.source_map().is_multiline(sp) => {
+ let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
+ err.span_suggestion(
+ sp,
+ &format!("consider using `{}` instead of `{}`", sugg, current),
+ format!("{} {}", sugg, ident),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_label(span, "non-constant value");
+ }
+ _ => {
+ err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
+ }
}
+
err
}
ResolutionError::BindingShadowsSomethingUnacceptable {
@@ -602,6 +602,25 @@
err
}
+ ResolutionError::TraitImplMismatch {
+ name,
+ kind,
+ code,
+ trait_item_span,
+ trait_path,
+ } => {
+ let mut err = self.session.struct_span_err_with_code(
+ span,
+ &format!(
+ "item `{}` is an associated {}, which doesn't match its trait `{}`",
+ name, kind, trait_path,
+ ),
+ code,
+ );
+ err.span_label(span, "does not match trait");
+ err.span_label(trait_item_span, "item in trait");
+ err
+ }
}
}
@@ -895,11 +914,8 @@
// a note about editions
let note = if let Some(did) = did {
let requires_note = !did.is_local()
- && this
- .cstore()
- .item_attrs_untracked(did, this.session)
- .iter()
- .any(|attr| {
+ && this.cstore().item_attrs_untracked(did, this.session).any(
+ |attr| {
if attr.has_name(sym::rustc_diagnostic_item) {
[sym::TryInto, sym::TryFrom, sym::FromIterator]
.map(|x| Some(x))
@@ -907,7 +923,8 @@
} else {
false
}
- });
+ },
+ );
requires_note.then(|| {
format!(
@@ -1345,8 +1362,7 @@
.filter(|(_, module)| {
current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module)
})
- .map(|(_, module)| module.kind.name())
- .flatten(),
+ .flat_map(|(_, module)| module.kind.name()),
)
.filter(|c| !c.to_string().is_empty())
.collect::<Vec<_>>();
@@ -1842,7 +1858,7 @@
let instead = if instead { " instead" } else { "" };
let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
- for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
err.note(note);
}
@@ -1925,7 +1941,7 @@
multi_span.push_span_label(span, format!("`{}`: not accessible", name));
}
- for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
err.note(note);
}
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index bf4cece..a8c2a5e 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -11,11 +11,11 @@
use rustc_ast::NodeId;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::intern::Interned;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_hir::def::{self, PartialRes};
use rustc_hir::def_id::DefId;
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::span_bug;
use rustc_middle::ty;
use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
@@ -48,6 +48,9 @@
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
nested: bool,
+ /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
+ /// (eg. implicit struct constructors)
+ additional_ids: (NodeId, NodeId),
},
Glob {
is_prelude: bool,
@@ -131,7 +134,7 @@
pub struct NameResolution<'a> {
/// Single imports that may define the name in the namespace.
/// Imports are arena-allocated, so it's ok to use pointers as keys.
- single_imports: FxHashSet<PtrKey<'a, Import<'a>>>,
+ single_imports: FxHashSet<Interned<'a, Import<'a>>>,
/// The least shadowable known binding for this name, or None if there are no known bindings.
pub binding: Option<&'a NameBinding<'a>>,
shadowed_glob: Option<&'a NameBinding<'a>>,
@@ -150,7 +153,7 @@
}
crate fn add_single_import(&mut self, import: &'a Import<'a>) {
- self.single_imports.insert(PtrKey(import));
+ self.single_imports.insert(Interned::new_unchecked(import));
}
}
@@ -834,7 +837,6 @@
import.span,
);
import.vis.set(orig_vis);
-
source_bindings[ns].set(binding);
} else {
return;
@@ -848,7 +850,7 @@
Err(Determined) => {
let key = this.new_key(target, ns);
this.update_resolution(parent, key, |_, resolution| {
- resolution.single_imports.remove(&PtrKey(import));
+ resolution.single_imports.remove(&Interned::new_unchecked(import));
});
}
Ok(binding) if !binding.is_importable() => {
@@ -1409,7 +1411,7 @@
if is_good_import || binding.is_macro_def() {
let res = binding.res().expect_non_local();
if res != def::Res::Err {
- reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
+ reexports.push(ModChild { ident, res, vis: binding.vis, span: binding.span });
}
}
});
@@ -1418,7 +1420,7 @@
if let Some(def_id) = module.opt_def_id() {
// Call to `expect_local` should be fine because current
// code is only called for local modules.
- self.r.export_map.insert(def_id.expect_local(), reexports);
+ self.r.reexport_map.insert(def_id.expect_local(), reexports);
}
}
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5730502..9ac3e6e 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -289,7 +289,7 @@
| DefKind::ForeignTy,
_,
) | Res::PrimTy(..)
- | Res::SelfTy(..)
+ | Res::SelfTy { .. }
),
PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)),
PathSource::Trait(AliasPossibility::Maybe) => {
@@ -326,7 +326,7 @@
| DefKind::TyAlias
| DefKind::AssocTy,
_,
- ) | Res::SelfTy(..)
+ ) | Res::SelfTy { .. }
),
PathSource::TraitItem(ns) => match res {
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
@@ -400,6 +400,8 @@
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
current_where_predicate: Option<&'ast WherePredicate>,
+
+ current_type_path: Option<&'ast Ty>,
}
struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -472,8 +474,10 @@
}
fn visit_ty(&mut self, ty: &'ast Ty) {
let prev = self.diagnostic_metadata.current_trait_object;
+ let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind {
TyKind::Path(ref qself, ref path) => {
+ self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
}
TyKind::ImplicitSelf => {
@@ -490,6 +494,7 @@
}
visit::walk_ty(self, ty);
self.diagnostic_metadata.current_trait_object = prev;
+ self.diagnostic_metadata.current_type_path = prev_ty;
}
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
self.smart_resolve_path(
@@ -520,9 +525,16 @@
}
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
let rib_kind = match fn_kind {
- // Bail if there's no body.
- FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp),
- FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind,
+ // Bail if the function is foreign, and thus cannot validly have
+ // a body, or if there's no body for some other reason.
+ FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
+ // We don't need to deal with patterns in parameters, because
+ // they are not possible for foreign or bodiless functions.
+ self.visit_fn_header(&sig.header);
+ visit::walk_fn_decl(self, &sig.decl);
+ return;
+ }
+ FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
FnKind::Closure(..) => ClosureOrAsyncRibKind,
};
@@ -899,9 +911,12 @@
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let item_def_id = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
- visit::walk_item(this, item);
- });
+ this.with_self_rib(
+ Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+ |this| {
+ visit::walk_item(this, item);
+ },
+ );
});
});
}
@@ -987,8 +1002,8 @@
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();
- this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
+ let def = this.r.local_def_id(item.id).to_def_id();
+ this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
@@ -1039,8 +1054,8 @@
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();
- this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
+ let def = this.r.local_def_id(item.id).to_def_id();
+ this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
});
@@ -1240,15 +1255,14 @@
);
let res = res.base_res();
if res != Res::Err {
- new_id = Some(res.def_id());
- let span = trait_ref.path.span;
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(
&path,
Some(TypeNS),
- false,
- span,
+ true,
+ trait_ref.path.span,
CrateLint::SimplePath(trait_ref.ref_id),
) {
+ new_id = Some(res.def_id());
new_val = Some((module, trait_ref.clone()));
}
}
@@ -1285,7 +1299,7 @@
// If applicable, create a rib for the type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
// Dummy self type for better errors if `Self` is used in the trait path.
- this.with_self_rib(Res::SelfTy(None, None), |this| {
+ this.with_self_rib(Res::SelfTy { trait_: None, alias_to: 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);
@@ -1296,7 +1310,9 @@
}
let item_def_id = item_def_id.to_def_id();
- this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
+ let res =
+ Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
+ this.with_self_rib(res, |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path.
visit::walk_trait_ref(this, trait_ref);
@@ -1317,6 +1333,7 @@
// If this is a trait impl, ensure the const
// exists in trait
this.check_trait_item(
+ item.id,
item.ident,
&item.kind,
ValueNS,
@@ -1352,6 +1369,7 @@
// If this is a trait impl, ensure the method
// exists in trait
this.check_trait_item(
+ item.id,
item.ident,
&item.kind,
ValueNS,
@@ -1379,6 +1397,7 @@
// If this is a trait impl, ensure the type
// exists in trait
this.check_trait_item(
+ item.id,
item.ident,
&item.kind,
TypeNS,
@@ -1409,7 +1428,8 @@
fn check_trait_item<F>(
&mut self,
- ident: Ident,
+ id: NodeId,
+ mut ident: Ident,
kind: &AssocItemKind,
ns: Namespace,
span: Span,
@@ -1417,26 +1437,62 @@
) where
F: FnOnce(Ident, &str, Option<Symbol>) -> ResolutionError<'_>,
{
- // If there is a TraitRef in scope for an impl, then the method must be in the
- // trait.
- if let Some((module, _)) = self.current_trait_ref {
- if self
- .r
- .resolve_ident_in_module(
- ModuleOrUniformRoot::Module(module),
- ident,
- ns,
- &self.parent_scope,
- false,
- span,
- )
- .is_err()
- {
- let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
- let path = &self.current_trait_ref.as_ref().unwrap().1.path;
- self.report_error(span, err(ident, &path_names_to_string(path), candidate));
- }
+ // If there is a TraitRef in scope for an impl, then the method must be in the trait.
+ let Some((module, _)) = &self.current_trait_ref else { return; };
+ ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
+ let key = self.r.new_key(ident, ns);
+ let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
+ debug!(?binding);
+ if binding.is_none() {
+ // We could not find the trait item in the correct namespace.
+ // Check the other namespace to report an error.
+ let ns = match ns {
+ ValueNS => TypeNS,
+ TypeNS => ValueNS,
+ _ => ns,
+ };
+ let key = self.r.new_key(ident, ns);
+ binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
+ debug!(?binding);
}
+ let Some(binding) = binding else {
+ // We could not find the method: report an error.
+ let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
+ let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+ self.report_error(span, err(ident, &path_names_to_string(path), candidate));
+ return;
+ };
+
+ let res = binding.res();
+ let Res::Def(def_kind, _) = res else { bug!() };
+ match (def_kind, kind) {
+ (DefKind::AssocTy, AssocItemKind::TyAlias(..))
+ | (DefKind::AssocFn, AssocItemKind::Fn(..))
+ | (DefKind::AssocConst, AssocItemKind::Const(..)) => {
+ self.r.record_partial_res(id, PartialRes::new(res));
+ return;
+ }
+ _ => {}
+ }
+
+ // The method kind does not correspond to what appeared in the trait, report.
+ let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+ let (code, kind) = match kind {
+ AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
+ AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
+ AssocItemKind::TyAlias(..) => (rustc_errors::error_code!(E0325), "type"),
+ AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
+ };
+ self.report_error(
+ span,
+ ResolutionError::TraitImplMismatch {
+ name: ident.name,
+ kind,
+ code,
+ trait_path: path_names_to_string(path),
+ trait_item_span: binding.span,
+ },
+ );
}
fn resolve_params(&mut self, params: &'ast [Param]) {
@@ -1890,7 +1946,6 @@
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,
@@ -2471,6 +2526,10 @@
self.visit_expr(elem);
self.resolve_anon_const(ct, IsRepeatExpr::Yes);
}
+ ExprKind::Index(ref elem, ref idx) => {
+ self.resolve_expr(elem, Some(expr));
+ self.visit_expr(idx);
+ }
_ => {
visit::walk_expr(self, expr);
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 4cd1b34..129db03 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -26,6 +26,7 @@
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use std::iter;
+use std::ops::Deref;
use tracing::debug;
@@ -265,6 +266,8 @@
}
}
+ self.detect_assoct_type_constraint_meant_as_path(base_span, &mut err);
+
// Emit special messages for unresolved `Self` and `self`.
if is_self_type(path, ns) {
err.code(rustc_errors::error_code!(E0411));
@@ -603,6 +606,40 @@
(err, candidates)
}
+ fn detect_assoct_type_constraint_meant_as_path(
+ &self,
+ base_span: Span,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
+ let TyKind::Path(_, path) = &ty.kind else { return; };
+ for segment in &path.segments {
+ let Some(params) = &segment.args else { continue; };
+ let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
+ for param in ¶ms.args {
+ let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
+ let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
+ continue;
+ };
+ for bound in bounds {
+ let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
+ = bound else
+ {
+ continue;
+ };
+ if base_span == trait_ref.span {
+ err.span_suggestion_verbose(
+ constraint.ident.span.between(trait_ref.span),
+ "you might have meant to write a path instead of an associated type bound",
+ "::".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+ }
+ }
+
fn get_single_associated_item(
&mut self,
path: &[Segment],
@@ -667,7 +704,7 @@
) = &bounded_ty.kind
{
// use this to verify that ident is a type param.
- let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+ let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
bounded_ty.id,
None,
&Segment::from_path(path),
@@ -675,9 +712,7 @@
span,
true,
CrateLint::No,
- ) {
- partial_res
- } else {
+ ) else {
return false;
};
if !(matches!(
@@ -694,7 +729,7 @@
if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind {
// Confirm that the `SelfTy` is a type parameter.
- let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+ let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
bounded_ty.id,
None,
&Segment::from_path(type_param_path),
@@ -702,9 +737,7 @@
span,
true,
CrateLint::No,
- ) {
- partial_res
- } else {
+ ) else {
return false;
};
if !(matches!(
@@ -970,7 +1003,13 @@
};
match (res, source) {
- (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+ (
+ Res::Def(DefKind::Macro(MacroKind::Bang), _),
+ PathSource::Expr(Some(Expr {
+ kind: ExprKind::Index(..) | ExprKind::Call(..), ..
+ }))
+ | PathSource::Struct,
+ ) => {
err.span_label(span, fallback_label);
err.span_suggestion_verbose(
span.shrink_to_hi(),
@@ -982,6 +1021,9 @@
err.note("if you want the `try` keyword, you need Rust 2018 or later");
}
}
+ (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+ err.span_label(span, fallback_label);
+ }
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits");
if self.r.session.is_nightly_build() {
@@ -1121,7 +1163,7 @@
err.span_suggestion(
span,
&"use this syntax instead",
- format!("{path_str}"),
+ path_str.to_string(),
Applicability::MaybeIncorrect,
);
}
@@ -1143,7 +1185,7 @@
Applicability::HasPlaceholders,
);
}
- (Res::SelfTy(..), _) if ns == ValueNS => {
+ (Res::SelfTy { .. }, _) if ns == ValueNS => {
err.span_label(span, fallback_label);
err.note("can't use `Self` as a constructor, you must use the implemented struct");
}
@@ -1162,9 +1204,7 @@
ident: Symbol,
kind: &AssocItemKind,
) -> Option<Symbol> {
- let module = if let Some((module, _)) = self.current_trait_ref {
- module
- } else {
+ let Some((module, _)) = &self.current_trait_ref else {
return None;
};
if ident == kw::Underscore {
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 3322e36..3bea95f 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -14,10 +14,11 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug};
@@ -40,9 +41,9 @@
}
trait RegionExt {
- fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
+ fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
- fn late(index: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
+ fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
@@ -58,7 +59,7 @@
}
impl RegionExt for Region {
- fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
+ fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
let i = *index;
*index += 1;
let def_id = hir_map.local_def_id(param.hir_id);
@@ -67,7 +68,7 @@
(param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin))
}
- fn late(idx: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
+ fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
let depth = ty::INNERMOST;
let def_id = hir_map.local_def_id(param.hir_id);
let origin = LifetimeDefOrigin::from_param(param);
@@ -376,12 +377,9 @@
named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
is_late_bound_map,
- object_lifetime_defaults_map: |tcx, id| {
- let hir_id = tcx.hir().local_def_id_to_hir_id(id);
- match tcx.hir().find(hir_id) {
- Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
- _ => None,
- }
+ object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) {
+ Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
+ _ => None,
},
late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
lifetime_scope_map: |tcx, id| {
@@ -514,14 +512,14 @@
/// Finds the `Item` that contains the given `LocalDefId`
fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
- let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
- match tcx.hir().find(hir_id) {
+ match tcx.hir().find_by_def_id(local_def_id) {
Some(Node::Item(item)) => {
return item.def_id;
}
_ => {}
}
let item = {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
let mut parent_iter = tcx.hir().parent_iter(hir_id);
loop {
let node = parent_iter.next().map(|n| n.1);
@@ -654,10 +652,10 @@
}
}
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
// We want to nest trait/impl items in their parent, but nothing else.
@@ -819,7 +817,7 @@
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- Some(Region::early(&self.tcx.hir(), &mut index, param))
+ Some(Region::early(self.tcx.hir(), &mut index, param))
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
non_lifetime_count += 1;
@@ -890,7 +888,7 @@
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
@@ -1002,46 +1000,37 @@
// `fn foo<'a>() -> MyAnonTy<'a> { ... }`
// ^ ^this gets resolved in the current scope
for lifetime in lifetimes {
- if let hir::GenericArg::Lifetime(lifetime) = lifetime {
- self.visit_lifetime(lifetime);
+ let hir::GenericArg::Lifetime(lifetime) = lifetime else {
+ continue
+ };
+ self.visit_lifetime(lifetime);
- // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
- // and ban them. Type variables instantiated inside binders aren't
- // well-supported at the moment, so this doesn't work.
- // In the future, this should be fixed and this error should be removed.
- let def = self.map.defs.get(&lifetime.hir_id).cloned();
- if let Some(Region::LateBound(_, _, def_id, _)) = def {
- if let Some(def_id) = def_id.as_local() {
- 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);
- // 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 {
- struct_span_err!(
- self.tcx.sess,
- lifetime.span,
- E0657,
- "`impl Trait` can only capture lifetimes \
- bound at the fn or impl level"
- )
- .emit();
- }
- self.uninsert_lifetime_on_error(lifetime, def.unwrap());
- }
- }
+ // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
+ // and ban them. Type variables instantiated inside binders aren't
+ // well-supported at the moment, so this doesn't work.
+ // In the future, this should be fixed and this error should be removed.
+ let def = self.map.defs.get(&lifetime.hir_id).cloned();
+ let Some(Region::LateBound(_, _, def_id, _)) = def else {
+ continue
+ };
+ let Some(def_id) = def_id.as_local() else {
+ continue
+ };
+ 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);
+ if !parent_id.is_owner() {
+ if !self.trait_definition_only {
+ struct_span_err!(
+ self.tcx.sess,
+ lifetime.span,
+ E0657,
+ "`impl Trait` can only capture lifetimes \
+ bound at the fn or impl level"
+ )
+ .emit();
}
+ self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
}
@@ -1056,7 +1045,7 @@
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {
- let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m);
+ let (name, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
let Region::EarlyBound(_, def_id, _) = reg else {
bug!();
};
@@ -1137,7 +1126,7 @@
self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_did(trait_item.hir_id())),
+ Some(tcx.hir().get_parent_item(trait_item.hir_id())),
trait_item.hir_id(),
&sig.decl,
&trait_item.generics,
@@ -1156,7 +1145,7 @@
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- Some(Region::early(&self.tcx.hir(), &mut index, param))
+ Some(Region::early(self.tcx.hir(), &mut index, param))
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
non_lifetime_count += 1;
@@ -1206,7 +1195,7 @@
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_did(impl_item.hir_id())),
+ Some(tcx.hir().get_parent_item(impl_item.hir_id())),
impl_item.hir_id(),
&sig.decl,
&impl_item.generics,
@@ -1225,7 +1214,7 @@
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- Some(Region::early(&self.tcx.hir(), &mut index, param))
+ Some(Region::early(self.tcx.hir(), &mut index, param))
}
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => {
non_lifetime_count += 1;
@@ -1379,7 +1368,7 @@
.enumerate()
.map(|(late_bound_idx, param)| {
let pair =
- Region::late(late_bound_idx as u32, &this.tcx.hir(), param);
+ Region::late(late_bound_idx as u32, this.tcx.hir(), param);
let r = late_region_as_bound_region(this.tcx, &pair.1);
(pair, r)
})
@@ -1474,11 +1463,8 @@
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(
- initial_bound_vars + late_bound_idx as u32,
- &self.tcx.hir(),
- param,
- );
+ let pair =
+ Region::late(initial_bound_vars + late_bound_idx as u32, self.tcx.hir(), param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
lifetimes.insert(pair.0, pair.1);
r
@@ -1619,12 +1605,6 @@
gather.visit_body(body);
impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, ex: &hir::Expr<'_>) {
if let Some(label) = expression_label(ex) {
for prior_label in &self.labels_in_fn[..] {
@@ -1675,13 +1655,10 @@
if let Some(def) =
lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0()))
{
- let hir_id =
- tcx.hir().local_def_id_to_hir_id(def.id().unwrap().expect_local());
-
signal_shadowing_problem(
tcx,
label.name,
- original_lifetime(tcx.hir().span(hir_id)),
+ original_lifetime(tcx.def_span(def.id().unwrap().expect_local())),
shadower_label(label.span),
);
return;
@@ -1693,10 +1670,10 @@
}
}
-fn compute_object_lifetime_defaults(
- tcx: TyCtxt<'_>,
+fn compute_object_lifetime_defaults<'tcx>(
+ tcx: TyCtxt<'tcx>,
item: &hir::Item<'_>,
-) -> Option<Vec<ObjectLifetimeDefault>> {
+) -> Option<&'tcx [ObjectLifetimeDefault]> {
match item.kind {
hir::ItemKind::Struct(_, ref generics)
| hir::ItemKind::Union(_, ref generics)
@@ -1749,10 +1726,10 @@
/// Scan the bounds and where-clauses on parameters to extract bounds
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
/// for each type parameter.
-fn object_lifetime_defaults_for_item(
- tcx: TyCtxt<'_>,
+fn object_lifetime_defaults_for_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
generics: &hir::Generics<'_>,
-) -> Vec<ObjectLifetimeDefault> {
+) -> &'tcx [ObjectLifetimeDefault] {
fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>]) {
for bound in bounds {
if let hir::GenericBound::Outlives(ref lifetime) = *bound {
@@ -1761,81 +1738,75 @@
}
}
- generics
- .params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => None,
- GenericParamKind::Type { .. } => {
- let mut set = Set1::Empty;
+ let process_param = |param: &hir::GenericParam<'_>| match param.kind {
+ GenericParamKind::Lifetime { .. } => None,
+ GenericParamKind::Type { .. } => {
+ let mut set = Set1::Empty;
- add_bounds(&mut set, ¶m.bounds);
+ add_bounds(&mut set, ¶m.bounds);
- let param_def_id = tcx.hir().local_def_id(param.hir_id);
- for predicate in generics.where_clause.predicates {
- // Look for `type: ...` where clauses.
- let data = match *predicate {
- hir::WherePredicate::BoundPredicate(ref data) => data,
- _ => continue,
- };
+ let param_def_id = tcx.hir().local_def_id(param.hir_id);
+ for predicate in generics.where_clause.predicates {
+ // Look for `type: ...` where clauses.
+ let data = match *predicate {
+ hir::WherePredicate::BoundPredicate(ref data) => data,
+ _ => continue,
+ };
- // Ignore `for<'a> type: ...` as they can change what
- // lifetimes mean (although we could "just" handle it).
- if !data.bound_generic_params.is_empty() {
- continue;
- }
-
- let res = match data.bounded_ty.kind {
- hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res,
- _ => continue,
- };
-
- if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) {
- add_bounds(&mut set, &data.bounds);
- }
+ // Ignore `for<'a> type: ...` as they can change what
+ // lifetimes mean (although we could "just" handle it).
+ if !data.bound_generic_params.is_empty() {
+ continue;
}
- Some(match set {
- Set1::Empty => Set1::Empty,
- Set1::One(name) => {
- if name == hir::LifetimeName::Static {
- Set1::One(Region::Static)
- } else {
- generics
- .params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some((
- param.hir_id,
- hir::LifetimeName::Param(param.name),
- LifetimeDefOrigin::from_param(param),
- )),
- _ => None,
- })
- .enumerate()
- .find(|&(_, (_, lt_name, _))| lt_name == name)
- .map_or(Set1::Many, |(i, (id, _, origin))| {
- let def_id = tcx.hir().local_def_id(id);
- Set1::One(Region::EarlyBound(
- i as u32,
- def_id.to_def_id(),
- origin,
- ))
- })
- }
+ let res = match data.bounded_ty.kind {
+ hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res,
+ _ => continue,
+ };
+
+ if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) {
+ add_bounds(&mut set, &data.bounds);
+ }
+ }
+
+ Some(match set {
+ Set1::Empty => Set1::Empty,
+ Set1::One(name) => {
+ if name == hir::LifetimeName::Static {
+ Set1::One(Region::Static)
+ } else {
+ generics
+ .params
+ .iter()
+ .filter_map(|param| match param.kind {
+ GenericParamKind::Lifetime { .. } => Some((
+ param.hir_id,
+ hir::LifetimeName::Param(param.name),
+ LifetimeDefOrigin::from_param(param),
+ )),
+ _ => None,
+ })
+ .enumerate()
+ .find(|&(_, (_, lt_name, _))| lt_name == name)
+ .map_or(Set1::Many, |(i, (id, _, origin))| {
+ let def_id = tcx.hir().local_def_id(id);
+ Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id(), origin))
+ })
}
- Set1::Many => Set1::Many,
- })
- }
- GenericParamKind::Const { .. } => {
- // Generic consts don't impose any constraints.
- //
- // We still store a dummy value here to allow generic parameters
- // in an arbitrary order.
- Some(Set1::Empty)
- }
- })
- .collect()
+ }
+ Set1::Many => Set1::Many,
+ })
+ }
+ GenericParamKind::Const { .. } => {
+ // Generic consts don't impose any constraints.
+ //
+ // We still store a dummy value here to allow generic parameters
+ // in an arbitrary order.
+ Some(Set1::Empty)
+ }
+ };
+
+ tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param))
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
@@ -1913,6 +1884,7 @@
let remove_decl = self
.tcx
.parent(def_id)
+ .and_then(|parent_def_id| parent_def_id.as_local())
.and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
.and_then(|generics| self.lifetime_deletion_span(name, generics));
@@ -1953,7 +1925,7 @@
};
if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) {
if let Some(parent) =
- self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id))
+ self.tcx.hir().find_by_def_id(self.tcx.hir().get_parent_item(hir_lifetime.hir_id))
{
match parent {
Node::Item(item) => {
@@ -2035,19 +2007,20 @@
match lifetimeuseset {
Some(LifetimeUseSet::One(lifetime)) => {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- debug!("hir id first={:?}", hir_id);
- if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) {
- Node::Lifetime(hir_lifetime) => Some((
- hir_lifetime.hir_id,
- hir_lifetime.span,
- hir_lifetime.name.ident(),
- )),
- Node::GenericParam(param) => {
- Some((param.hir_id, param.span, param.name.ident()))
+ debug!(?def_id);
+ if let Some((id, span, name)) =
+ match self.tcx.hir().get_by_def_id(def_id.expect_local()) {
+ Node::Lifetime(hir_lifetime) => Some((
+ hir_lifetime.hir_id,
+ hir_lifetime.span,
+ hir_lifetime.name.ident(),
+ )),
+ Node::GenericParam(param) => {
+ Some((param.hir_id, param.span, param.name.ident()))
+ }
+ _ => None,
}
- _ => None,
- } {
+ {
debug!("id = {:?} span = {:?} name = {:?}", id, span, name);
if name.name == kw::UnderscoreLifetime {
continue;
@@ -2055,12 +2028,10 @@
if let Some(parent_def_id) = self.tcx.parent(def_id) {
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)
+ .get_attrs(def_id.to_def_id())
.iter()
.any(|attr| attr.has_name(sym::automatically_derived))
{
@@ -2072,7 +2043,7 @@
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy(ref opaque),
..
- }) = self.tcx.hir().get(parent_hir_id)
+ }) = self.tcx.hir().get_by_def_id(def_id)
{
if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
continue 'lifetimes;
@@ -2118,18 +2089,19 @@
debug!("not one use lifetime");
}
None => {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) {
- Node::Lifetime(hir_lifetime) => Some((
- hir_lifetime.hir_id,
- hir_lifetime.span,
- hir_lifetime.name.ident(),
- )),
- Node::GenericParam(param) => {
- Some((param.hir_id, param.span, param.name.ident()))
+ if let Some((id, span, name)) =
+ match self.tcx.hir().get_by_def_id(def_id.expect_local()) {
+ Node::Lifetime(hir_lifetime) => Some((
+ hir_lifetime.hir_id,
+ hir_lifetime.span,
+ hir_lifetime.name.ident(),
+ )),
+ Node::GenericParam(param) => {
+ Some((param.hir_id, param.span, param.name.ident()))
+ }
+ _ => None,
}
- _ => None,
- } {
+ {
debug!("id ={:?} span = {:?} name = {:?}", id, span, name);
self.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_LIFETIMES,
@@ -2140,7 +2112,7 @@
.build(&format!("lifetime parameter `{}` never used", name));
if let Some(parent_def_id) = self.tcx.parent(def_id) {
if let Some(generics) =
- self.tcx.hir().get_generics(parent_def_id)
+ self.tcx.hir().get_generics(parent_def_id.expect_local())
{
let unused_lt_span =
self.lifetime_deletion_span(name, generics);
@@ -2219,9 +2191,9 @@
if self.map.late_bound.contains(¶m.hir_id) {
let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1;
- Some(Region::late(late_bound_idx, &self.tcx.hir(), param))
+ Some(Region::late(late_bound_idx, self.tcx.hir(), param))
} else {
- Some(Region::early(&self.tcx.hir(), &mut next_early_index, param))
+ Some(Region::early(self.tcx.hir(), &mut next_early_index, param))
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@@ -2241,7 +2213,7 @@
})
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
+ let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
@@ -2528,7 +2500,12 @@
};
if let Some(def_id) = def_id.as_local() {
let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- self.tcx.object_lifetime_defaults(id).unwrap().iter().map(set_to_region).collect()
+ self.tcx
+ .object_lifetime_defaults(id.owner)
+ .unwrap()
+ .iter()
+ .map(set_to_region)
+ .collect()
} else {
let tcx = self.tcx;
self.xcrate_object_lifetime_defaults
@@ -2764,7 +2741,7 @@
Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
if let hir::ItemKind::Trait(.., ref trait_items) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
{
assoc_item_kind =
trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
@@ -2777,7 +2754,7 @@
Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
{
impl_self = Some(self_ty);
assoc_item_kind =
@@ -2816,7 +2793,7 @@
// Look for `self: &'a Self` - also desugared from `&'a self`,
// and if that matches, use it for elision and return early.
fn is_self_ty(&self, res: Res) -> bool {
- if let Res::SelfTy(..) = res {
+ if let Res::SelfTy { .. } = res {
return true;
}
@@ -2840,12 +2817,6 @@
}
impl<'a> Visitor<'a> for SelfVisitor<'a> {
- type Map = intravisit::ErasedMap<'a>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) {
if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind {
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind
@@ -2930,12 +2901,6 @@
}
impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
if let hir::TyKind::BareFn(_) = ty.kind {
self.outer_index.shift_in(1);
@@ -3013,12 +2978,6 @@
anon_count: u32,
}
impl<'v> Visitor<'v> for GatherAnonLifetimes {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
#[instrument(skip(self), level = "trace")]
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
// If we enter a `BareFn`, then we enter a *new* binding scope
@@ -3342,13 +3301,10 @@
Scope::Binder { ref lifetimes, s, .. } => {
if let Some(&def) = lifetimes.get(¶m.name.normalize_to_macros_2_0()) {
- let hir_id =
- self.tcx.hir().local_def_id_to_hir_id(def.id().unwrap().expect_local());
-
signal_shadowing_problem(
self.tcx,
param.name.ident().name,
- original_lifetime(self.tcx.hir().span(hir_id)),
+ original_lifetime(self.tcx.def_span(def.id().unwrap())),
shadower_lifetime(¶m),
);
return;
@@ -3519,12 +3475,6 @@
}
impl<'v> Visitor<'v> for ConstrainedCollector {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
match ty.kind {
hir::TyKind::Path(
@@ -3563,12 +3513,6 @@
}
impl<'v> Visitor<'v> for AllCollector {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b46a93c..28d8d92 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -18,6 +18,7 @@
#![feature(nll)]
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
@@ -37,7 +38,7 @@
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
@@ -49,10 +50,11 @@
use rustc_hir::TraitCandidate;
use rustc_index::vec::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
-use rustc_middle::hir::exports::ExportMap;
+use rustc_middle::metadata::ModChild;
+use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::span_bug;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
use rustc_query_system::ich::StableHashingContext;
use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
use rustc_session::lint;
@@ -66,7 +68,7 @@
use smallvec::{smallvec, SmallVec};
use std::cell::{Cell, RefCell};
-use std::collections::{BTreeMap, BTreeSet};
+use std::collections::BTreeSet;
use std::ops::ControlFlow;
use std::{cmp, fmt, iter, mem, ptr};
use tracing::debug;
@@ -77,8 +79,11 @@
use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*};
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
+use crate::access_levels::AccessLevelsVisitor;
+
type Res = def::Res<NodeId>;
+mod access_levels;
mod build_reduced_graph;
mod check_unused;
mod def_collector;
@@ -258,6 +263,14 @@
SelfInGenericParamDefault,
/// Error E0767: use of unreachable label
UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
+ /// Error E0323, E0324, E0325: mismatch between trait item and impl item.
+ TraitImplMismatch {
+ name: Symbol,
+ kind: &'static str,
+ trait_path: String,
+ trait_item_span: Span,
+ code: rustc_errors::DiagnosticId,
+ },
}
enum VisResolutionError<'a> {
@@ -602,7 +615,8 @@
}
}
- fn def_id(&self) -> DefId {
+ // Public for rustdoc.
+ pub fn def_id(&self) -> DefId {
self.opt_def_id().expect("`ModuleData::def_id` is called on a block module")
}
@@ -927,7 +941,7 @@
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- export_map: ExportMap,
+ reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules.
@@ -950,7 +964,7 @@
/// language items.
empty_module: Module<'a>,
module_map: FxHashMap<DefId, Module<'a>>,
- binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
+ binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>,
underscore_disambiguator: u32,
/// Maps glob imports to the names of items actually imported.
@@ -977,7 +991,7 @@
macro_names: FxHashSet<Ident>,
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
registered_attrs: FxHashSet<Ident>,
- registered_tools: FxHashSet<Ident>,
+ registered_tools: RegisteredTools,
macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,
all_macros: FxHashMap<Symbol, Res>,
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
@@ -1047,11 +1061,13 @@
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
main_def: Option<MainDefinition>,
- trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
+ trait_impls: FxIndexMap<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>,
confused_type_with_std_module: FxHashMap<Span, Span>,
+
+ access_levels: AccessLevels,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1099,7 +1115,7 @@
self.name_resolutions.alloc(Default::default())
}
fn alloc_macro_rules_scope(&'a self, scope: MacroRulesScope<'a>) -> MacroRulesScopeRef<'a> {
- PtrKey(self.dropless.alloc(Cell::new(scope)))
+ Interned::new_unchecked(self.dropless.alloc(Cell::new(scope)))
}
fn alloc_macro_rules_binding(
&'a self,
@@ -1333,7 +1349,7 @@
import_res_map: Default::default(),
label_res_map: Default::default(),
extern_crate_map: Default::default(),
- export_map: FxHashMap::default(),
+ reexport_map: FxHashMap::default(),
trait_map: NodeMap::default(),
underscore_disambiguator: 0,
empty_module,
@@ -1407,6 +1423,7 @@
trait_impls: Default::default(),
proc_macros: Default::default(),
confused_type_with_std_module: Default::default(),
+ access_levels: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1446,18 +1463,20 @@
let definitions = self.definitions;
let visibilities = self.visibilities;
let extern_crate_map = self.extern_crate_map;
- let export_map = self.export_map;
+ let reexport_map = self.reexport_map;
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
let glob_map = self.glob_map;
let main_def = self.main_def;
let confused_type_with_std_module = self.confused_type_with_std_module;
+ let access_levels = self.access_levels;
ResolverOutputs {
definitions,
cstore: Box::new(self.crate_loader.into_cstore()),
visibilities,
+ access_levels,
extern_crate_map,
- export_map,
+ reexport_map,
glob_map,
maybe_unused_trait_imports,
maybe_unused_extern_crates,
@@ -1470,6 +1489,7 @@
trait_impls: self.trait_impls,
proc_macros,
confused_type_with_std_module,
+ registered_tools: self.registered_tools,
}
}
@@ -1477,10 +1497,11 @@
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
ResolverOutputs {
definitions: self.definitions.clone(),
+ access_levels: self.access_levels.clone(),
cstore: Box::new(self.cstore().clone()),
visibilities: self.visibilities.clone(),
extern_crate_map: self.extern_crate_map.clone(),
- export_map: self.export_map.clone(),
+ reexport_map: self.reexport_map.clone(),
glob_map: self.glob_map.clone(),
maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
@@ -1493,6 +1514,7 @@
trait_impls: self.trait_impls.clone(),
proc_macros,
confused_type_with_std_module: self.confused_type_with_std_module.clone(),
+ registered_tools: self.registered_tools.clone(),
}
}
@@ -1532,6 +1554,9 @@
pub fn resolve_crate(&mut self, krate: &Crate) {
self.session.time("resolve_crate", || {
self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
+ self.session.time("resolve_access_levels", || {
+ AccessLevelsVisitor::compute_access_levels(self, krate)
+ });
self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
self.session.time("resolve_main", || self.resolve_main());
@@ -2759,7 +2784,7 @@
return Res::Err;
}
}
- Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
+ Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
for rib in ribs {
let has_generic_params: HasGenericParams = match rib.kind {
NormalRibKind
@@ -2779,8 +2804,8 @@
// 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.
- if let Res::SelfTy(trait_def, Some((impl_def, _))) = res {
- res = Res::SelfTy(trait_def, Some((impl_def, true)));
+ if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
+ res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
} else {
if record_used {
self.report_error(
@@ -2913,7 +2938,9 @@
}
fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) {
- if let Some(old_module) = self.binding_parent_modules.insert(PtrKey(binding), module) {
+ if let Some(old_module) =
+ self.binding_parent_modules.insert(Interned::new_unchecked(binding), module)
+ {
if !ptr::eq(module, old_module) {
span_bug!(binding.span, "parent module is reset for binding");
}
@@ -2929,8 +2956,8 @@
// is disambiguated to mitigate regressions from macro modularization.
// Scoping for `macro_rules` behaves like scoping for `let` at module level, in general.
match (
- self.binding_parent_modules.get(&PtrKey(macro_rules)),
- self.binding_parent_modules.get(&PtrKey(modularized)),
+ self.binding_parent_modules.get(&Interned::new_unchecked(macro_rules)),
+ self.binding_parent_modules.get(&Interned::new_unchecked(modularized)),
) {
(Some(macro_rules), Some(modularized)) => {
macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod()
@@ -3384,6 +3411,16 @@
&self.all_macros
}
+ /// For rustdoc.
+ /// For local modules returns only reexports, for external modules returns all children.
+ pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
+ if let Some(def_id) = def_id.as_local() {
+ self.reexport_map.get(&def_id).cloned().unwrap_or_default()
+ } else {
+ self.cstore().module_children_untracked(def_id, self.session)
+ }
+ }
+
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
#[inline]
pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
@@ -3421,7 +3458,6 @@
let attr = self
.cstore()
.item_attrs_untracked(def_id, self.session)
- .into_iter()
.find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
let mut ret = Vec::new();
for meta in attr.meta_item_list()? {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 52685ec..89c2a0c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -11,7 +11,7 @@
use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
@@ -23,7 +23,7 @@
use rustc_hir::def_id::{CrateNum, LocalDefId};
use rustc_hir::PrimTy;
use rustc_middle::middle::stability;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, RegisteredTools};
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK};
use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
use rustc_session::lint::BuiltinLintDiagnostics;
@@ -71,7 +71,7 @@
/// This helps to avoid uncontrollable growth of `macro_rules!` scope chains,
/// which usually grow lineraly with the number of macro invocations
/// in a module (including derives) and hurt performance.
-pub(crate) type MacroRulesScopeRef<'a> = PtrKey<'a, Cell<MacroRulesScope<'a>>>;
+pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell<MacroRulesScope<'a>>>;
// Macro namespace is separated into two sub-namespaces, one for bang macros and
// one for attribute-like macros (attributes, derives).
@@ -447,6 +447,10 @@
fn declare_proc_macro(&mut self, id: NodeId) {
self.proc_macros.push(id)
}
+
+ fn registered_tools(&self) -> &RegisteredTools {
+ &self.registered_tools
+ }
}
impl<'a> Resolver<'a> {
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 23f5b17..0ff56a3 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -21,7 +21,7 @@
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::config::Input;
@@ -47,11 +47,10 @@
use tracing::{debug, error};
+#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213
macro_rules! down_cast_data {
($id:ident, $kind:ident, $sp:expr) => {
- let $id = if let super::Data::$kind(data) = $id {
- data
- } else {
+ let super::Data::$kind($id) = $id else {
span_bug!($sp, "unexpected data kind: {:?}", $id);
};
};
@@ -263,7 +262,7 @@
) {
debug!("process_method: {:?}:{}", def_id, ident);
- let map = &self.tcx.hir();
+ let map = self.tcx.hir();
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) {
@@ -362,7 +361,7 @@
ty_params: &'tcx hir::Generics<'tcx>,
body: hir::BodyId,
) {
- let map = &self.tcx.hir();
+ let map = self.tcx.hir();
self.nest_typeck_results(item.def_id, |v| {
let body = map.body(body);
if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
@@ -627,7 +626,7 @@
}
}
- let map = &self.tcx.hir();
+ let map = self.tcx.hir();
self.nest_typeck_results(item.def_id, |v| {
v.visit_ty(&impl_.self_ty);
if let Some(trait_ref) = &impl_.of_trait {
@@ -717,7 +716,7 @@
// walk generics and methods
self.process_generic_params(generics, &qualname, item.hir_id());
for method in methods {
- let map = &self.tcx.hir();
+ let map = self.tcx.hir();
self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
}
}
@@ -922,7 +921,7 @@
| HirDefKind::AssocTy,
_,
)
- | Res::SelfTy(..) => {
+ | Res::SelfTy { .. } => {
self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
}
def => {
@@ -1137,10 +1136,10 @@
}
impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -1363,9 +1362,7 @@
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
}
- hir::ExprKind::MethodCall(ref seg, _, args, _) => {
- self.process_method_call(ex, seg, args)
- }
+ hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args),
hir::ExprKind::Field(ref sub_ex, _) => {
self.visit_expr(&sub_ex);
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 7ec619e..8b0adba 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,7 +1,9 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(if_let_guard)]
#![feature(nll)]
+#![feature(let_else)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
mod dump_visitor;
mod dumper;
@@ -18,7 +20,7 @@
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Node;
use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt};
use rustc_middle::{bug, span_bug};
@@ -710,13 +712,11 @@
}
Res::Def(HirDefKind::AssocFn, decl_id) => {
let def_id = if decl_id.is_local() {
- let ti = self.tcx.associated_item(decl_id);
-
- self.tcx
- .associated_items(ti.container.id())
- .filter_by_name_unhygienic(ti.ident.name)
- .find(|item| item.defaultness.has_value())
- .map(|item| item.def_id)
+ if self.tcx.associated_item(decl_id).defaultness.has_value() {
+ Some(decl_id)
+ } else {
+ None
+ }
} else {
None
};
@@ -749,7 +749,7 @@
_,
)
| Res::PrimTy(..)
- | Res::SelfTy(..)
+ | Res::SelfTy { .. }
| Res::ToolMod
| Res::NonMacroAttr(..)
| Res::SelfCtor(..)
@@ -814,7 +814,7 @@
fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
match self.get_path_res(ref_id) {
- Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None,
+ Res::PrimTy(_) | Res::SelfTy { .. } | Res::Err => None,
def => def.opt_def_id(),
}
}
@@ -823,9 +823,9 @@
let mut result = String::new();
for attr in attrs {
- if let Some(val) = attr.doc_str() {
+ if let Some((val, kind)) = attr.doc_str_and_comment_kind() {
// FIXME: Should save-analysis beautify doc strings itself or leave it to users?
- result.push_str(beautify_doc_string(val).as_str());
+ result.push_str(beautify_doc_string(val, kind).as_str());
result.push('\n');
}
}
@@ -861,10 +861,10 @@
}
impl<'l> Visitor<'l> for PathCollector<'l> {
- type Map = Map<'l>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_pat(&mut self, p: &'l hir::Pat<'l>) {
@@ -986,7 +986,7 @@
tcx.dep_graph.with_ignore(|| {
info!("Dumping crate {}", cratename);
- // Privacy checking requires and is done after type checking; use a
+ // Privacy checking must be done outside of type inference; use a
// fallback in case the access levels couldn't have been correctly computed.
let access_levels = match tcx.sess.compile_status() {
Ok(..) => tcx.privacy_access_levels(()),
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 4971bb6..3bb1d2f 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -573,7 +573,7 @@
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
let (name, start, end) = match res {
- Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => {
+ Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => {
return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
}
Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 49778f8..f6b9e17 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -4,7 +4,7 @@
edition = "2021"
[dependencies]
-indexmap = "1"
+indexmap = "1.8.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
[dev-dependencies]
diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs
index 80a7f65..02b28f7 100644
--- a/compiler/rustc_serialize/src/collection_impls.rs
+++ b/compiler/rustc_serialize/src/collection_impls.rs
@@ -17,15 +17,8 @@
}
impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> {
- fn decode(d: &mut D) -> Result<SmallVec<A>, D::Error> {
- d.read_seq(|d, len| {
- let mut vec = SmallVec::with_capacity(len);
- // FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error>
- for _ in 0..len {
- vec.push(d.read_seq_elt(|d| Decodable::decode(d))?);
- }
- Ok(vec)
- })
+ fn decode(d: &mut D) -> SmallVec<A> {
+ d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect())
}
}
@@ -41,14 +34,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> {
- fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> {
- d.read_seq(|d, len| {
- let mut list = LinkedList::new();
- for _ in 0..len {
- list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
- }
- Ok(list)
- })
+ fn decode(d: &mut D) -> LinkedList<T> {
+ d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect())
}
}
@@ -64,14 +51,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> {
- fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> {
- d.read_seq(|d, len| {
- let mut deque: VecDeque<T> = VecDeque::with_capacity(len);
- for _ in 0..len {
- deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
- }
- Ok(deque)
- })
+ fn decode(d: &mut D) -> VecDeque<T> {
+ d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect())
}
}
@@ -96,15 +77,15 @@
K: Decodable<D> + PartialEq + Ord,
V: Decodable<D>,
{
- fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
+ fn decode(d: &mut D) -> BTreeMap<K, V> {
d.read_map(|d, len| {
let mut map = BTreeMap::new();
for _ in 0..len {
- let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
+ let key = d.read_map_elt_key(|d| Decodable::decode(d));
+ let val = d.read_map_elt_val(|d| Decodable::decode(d));
map.insert(key, val);
}
- Ok(map)
+ map
})
}
}
@@ -127,13 +108,13 @@
where
T: Decodable<D> + PartialEq + Ord,
{
- fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
+ fn decode(d: &mut D) -> BTreeSet<T> {
d.read_seq(|d, len| {
let mut set = BTreeSet::new();
for _ in 0..len {
- set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d)));
}
- Ok(set)
+ set
})
}
}
@@ -161,16 +142,16 @@
V: Decodable<D>,
S: BuildHasher + Default,
{
- fn decode(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
+ fn decode(d: &mut D) -> HashMap<K, V, S> {
d.read_map(|d, len| {
let state = Default::default();
let mut map = HashMap::with_capacity_and_hasher(len, state);
for _ in 0..len {
- let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
+ let key = d.read_map_elt_key(|d| Decodable::decode(d));
+ let val = d.read_map_elt_val(|d| Decodable::decode(d));
map.insert(key, val);
}
- Ok(map)
+ map
})
}
}
@@ -205,14 +186,14 @@
T: Decodable<D> + Hash + Eq,
S: BuildHasher + Default,
{
- fn decode(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
+ fn decode(d: &mut D) -> HashSet<T, S> {
d.read_seq(|d, len| {
let state = Default::default();
let mut set = HashSet::with_capacity_and_hasher(len, state);
for _ in 0..len {
- set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d)));
}
- Ok(set)
+ set
})
}
}
@@ -240,16 +221,16 @@
V: Decodable<D>,
S: BuildHasher + Default,
{
- fn decode(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> {
+ fn decode(d: &mut D) -> indexmap::IndexMap<K, V, S> {
d.read_map(|d, len| {
let state = Default::default();
let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
for _ in 0..len {
- let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
+ let key = d.read_map_elt_key(|d| Decodable::decode(d));
+ let val = d.read_map_elt_val(|d| Decodable::decode(d));
map.insert(key, val);
}
- Ok(map)
+ map
})
}
}
@@ -274,14 +255,14 @@
T: Decodable<D> + Hash + Eq,
S: BuildHasher + Default,
{
- fn decode(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> {
+ fn decode(d: &mut D) -> indexmap::IndexSet<T, S> {
d.read_seq(|d, len| {
let state = Default::default();
let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
for _ in 0..len {
- set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d)));
}
- Ok(set)
+ set
})
}
}
@@ -294,9 +275,9 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
- fn decode(d: &mut D) -> Result<Rc<[T]>, D::Error> {
- let vec: Vec<T> = Decodable::decode(d)?;
- Ok(vec.into())
+ fn decode(d: &mut D) -> Rc<[T]> {
+ let vec: Vec<T> = Decodable::decode(d);
+ vec.into()
}
}
@@ -308,8 +289,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
- fn decode(d: &mut D) -> Result<Arc<[T]>, D::Error> {
- let vec: Vec<T> = Decodable::decode(d)?;
- Ok(vec.into())
+ fn decode(d: &mut D) -> Arc<[T]> {
+ let vec: Vec<T> = Decodable::decode(d);
+ vec.into()
}
}
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index cb9df3c..6a39854 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -89,7 +89,7 @@
//! let encoded = json::encode(&object).unwrap();
//!
//! // Deserialize using `json::decode`
-//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
+//! let decoded: TestStruct = json::decode(&encoded[..]);
//! ```
//!
//! ## Using the `ToJson` trait
@@ -173,7 +173,7 @@
//! let json_str: String = json_obj.to_string();
//!
//! // Deserialize like before
-//! let decoded: TestStruct = json::decode(&json_str).unwrap();
+//! let decoded: TestStruct = json::decode(&json_str);
//! ```
use self::DecoderError::*;
@@ -185,8 +185,6 @@
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
-use std::io;
-use std::io::prelude::*;
use std::mem::swap;
use std::num::FpCategory as Fp;
use std::ops::Index;
@@ -250,7 +248,6 @@
pub enum ParserError {
/// msg, line, col
SyntaxError(ErrorCode, usize, usize),
- IoError(io::ErrorKind, String),
}
// Builder and Parser have the same errors.
@@ -265,6 +262,12 @@
ApplicationError(string::String),
}
+macro_rules! bad {
+ ($e:expr) => {{
+ panic!("json decode error: {:?}", $e);
+ }};
+}
+
#[derive(Copy, Clone, Debug)]
pub enum EncoderError {
FmtError(fmt::Error),
@@ -295,10 +298,10 @@
}
/// Shortcut function to decode a JSON `&str` into an object
-pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> DecodeResult<T> {
+pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> T {
let json = match from_str(s) {
Ok(x) => x,
- Err(e) => return Err(ParseError(e)),
+ Err(e) => bad!(ParseError(e)),
};
let mut decoder = Decoder::new(json);
@@ -323,10 +326,6 @@
}
}
-fn io_error_to_error(io: io::Error) -> ParserError {
- IoError(io.kind(), io.to_string())
-}
-
impl fmt::Display for ParserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME this should be a nicer error
@@ -334,15 +333,6 @@
}
}
-impl fmt::Display for DecoderError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // FIXME this should be a nicer error
- fmt::Debug::fmt(self, f)
- }
-}
-
-impl std::error::Error for DecoderError {}
-
impl fmt::Display for EncoderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME this should be a nicer error
@@ -2166,21 +2156,6 @@
}
}
-/// Decodes a json value from an `&mut io::Read`
-pub fn from_reader(rdr: &mut dyn Read) -> Result<Json, BuilderError> {
- let mut contents = Vec::new();
- match rdr.read_to_end(&mut contents) {
- Ok(c) => c,
- Err(e) => return Err(io_error_to_error(e)),
- };
- let s = match str::from_utf8(&contents).ok() {
- Some(s) => s,
- _ => return Err(SyntaxError(NotUtf8, 0, 0)),
- };
- let mut builder = Builder::new(s.chars());
- builder.build()
-}
-
/// Decodes a json value from a string
pub fn from_str(s: &str) -> Result<Json, BuilderError> {
let mut builder = Builder::new(s.chars());
@@ -2206,41 +2181,39 @@
macro_rules! expect {
($e:expr, Null) => {{
match $e {
- Json::Null => Ok(()),
- other => Err(ExpectedError("Null".to_owned(), other.to_string())),
+ Json::Null => (),
+ other => bad!(ExpectedError("Null".to_owned(), other.to_string())),
}
}};
($e:expr, $t:ident) => {{
match $e {
- Json::$t(v) => Ok(v),
- other => Err(ExpectedError(stringify!($t).to_owned(), other.to_string())),
+ Json::$t(v) => v,
+ other => bad!(ExpectedError(stringify!($t).to_owned(), other.to_string())),
}
}};
}
macro_rules! read_primitive {
($name:ident, $ty:ty) => {
- fn $name(&mut self) -> DecodeResult<$ty> {
+ fn $name(&mut self) -> $ty {
match self.pop() {
- Json::I64(f) => Ok(f as $ty),
- Json::U64(f) => Ok(f as $ty),
- Json::F64(f) => Err(ExpectedError("Integer".to_owned(), f.to_string())),
+ Json::I64(f) => f as $ty,
+ Json::U64(f) => f as $ty,
+ Json::F64(f) => bad!(ExpectedError("Integer".to_owned(), f.to_string())),
// re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
// is going to have a string here, as per JSON spec.
Json::String(s) => match s.parse().ok() {
- Some(f) => Ok(f),
- None => Err(ExpectedError("Number".to_owned(), s)),
+ Some(f) => f,
+ None => bad!(ExpectedError("Number".to_owned(), s)),
},
- value => Err(ExpectedError("Number".to_owned(), value.to_string())),
+ value => bad!(ExpectedError("Number".to_owned(), value.to_string())),
}
}
};
}
impl crate::Decoder for Decoder {
- type Error = DecoderError;
-
- fn read_nil(&mut self) -> DecodeResult<()> {
+ fn read_unit(&mut self) -> () {
expect!(self.pop(), Null)
}
@@ -2257,156 +2230,150 @@
read_primitive! { read_i64, i64 }
read_primitive! { read_i128, i128 }
- fn read_f32(&mut self) -> DecodeResult<f32> {
- self.read_f64().map(|x| x as f32)
+ fn read_f32(&mut self) -> f32 {
+ self.read_f64() as f32
}
- fn read_f64(&mut self) -> DecodeResult<f64> {
+ fn read_f64(&mut self) -> f64 {
match self.pop() {
- Json::I64(f) => Ok(f as f64),
- Json::U64(f) => Ok(f as f64),
- Json::F64(f) => Ok(f),
+ Json::I64(f) => f as f64,
+ Json::U64(f) => f as f64,
+ Json::F64(f) => f,
Json::String(s) => {
// re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
// is going to have a string here, as per JSON spec.
match s.parse().ok() {
- Some(f) => Ok(f),
- None => Err(ExpectedError("Number".to_owned(), s)),
+ Some(f) => f,
+ None => bad!(ExpectedError("Number".to_owned(), s)),
}
}
- Json::Null => Ok(f64::NAN),
- value => Err(ExpectedError("Number".to_owned(), value.to_string())),
+ Json::Null => f64::NAN,
+ value => bad!(ExpectedError("Number".to_owned(), value.to_string())),
}
}
- fn read_bool(&mut self) -> DecodeResult<bool> {
+ fn read_bool(&mut self) -> bool {
expect!(self.pop(), Boolean)
}
- fn read_char(&mut self) -> DecodeResult<char> {
- let s = self.read_str()?;
- {
- let mut it = s.chars();
- if let (Some(c), None) = (it.next(), it.next()) {
- // exactly one character
- return Ok(c);
- }
+ fn read_char(&mut self) -> char {
+ let s = self.read_str();
+ let mut it = s.chars();
+ if let (Some(c), None) = (it.next(), it.next()) {
+ // exactly one character
+ return c;
}
- Err(ExpectedError("single character string".to_owned(), s.to_string()))
+ bad!(ExpectedError("single character string".to_owned(), s.to_string()));
}
- fn read_str(&mut self) -> DecodeResult<Cow<'_, str>> {
- expect!(self.pop(), String).map(Cow::Owned)
+ fn read_str(&mut self) -> Cow<'_, str> {
+ Cow::Owned(expect!(self.pop(), String))
}
- fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error> {
+ fn read_raw_bytes_into(&mut self, s: &mut [u8]) {
for c in s.iter_mut() {
- *c = self.read_u8()?;
+ *c = self.read_u8();
}
- Ok(())
}
- fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_enum<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
f(self)
}
- fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> DecodeResult<T>
+ fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> T
where
- F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
+ F: FnMut(&mut Decoder, usize) -> T,
{
let name = match self.pop() {
Json::String(s) => s,
Json::Object(mut o) => {
let n = match o.remove("variant") {
Some(Json::String(s)) => s,
- Some(val) => return Err(ExpectedError("String".to_owned(), val.to_string())),
- None => return Err(MissingFieldError("variant".to_owned())),
+ Some(val) => bad!(ExpectedError("String".to_owned(), val.to_string())),
+ None => bad!(MissingFieldError("variant".to_owned())),
};
match o.remove("fields") {
Some(Json::Array(l)) => {
self.stack.extend(l.into_iter().rev());
}
- Some(val) => return Err(ExpectedError("Array".to_owned(), val.to_string())),
- None => return Err(MissingFieldError("fields".to_owned())),
+ Some(val) => bad!(ExpectedError("Array".to_owned(), val.to_string())),
+ None => bad!(MissingFieldError("fields".to_owned())),
}
n
}
- json => return Err(ExpectedError("String or Object".to_owned(), json.to_string())),
+ json => bad!(ExpectedError("String or Object".to_owned(), json.to_string())),
};
let idx = match names.iter().position(|n| *n == &name[..]) {
Some(idx) => idx,
- None => return Err(UnknownVariantError(name)),
+ None => bad!(UnknownVariantError(name)),
};
f(self, idx)
}
- fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_enum_variant_arg<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
f(self)
}
- fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_struct<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
- let value = f(self)?;
+ let value = f(self);
self.pop();
- Ok(value)
+ value
}
- fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
+ fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
- let mut obj = expect!(self.pop(), Object)?;
+ let mut obj = expect!(self.pop(), Object);
let value = match obj.remove(name) {
None => {
// Add a Null and try to parse it as an Option<_>
// to get None as a default value.
self.stack.push(Json::Null);
- match f(self) {
- Ok(x) => x,
- Err(_) => return Err(MissingFieldError(name.to_string())),
- }
+ f(self)
}
Some(json) => {
self.stack.push(json);
- f(self)?
+ f(self)
}
};
self.stack.push(Json::Object(obj));
- Ok(value)
+ value
}
- fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T>
+ fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
self.read_seq(move |d, len| {
if len == tuple_len {
f(d)
} else {
- Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len)))
+ bad!(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len)));
}
})
}
- fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_tuple_arg<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
self.read_seq_elt(f)
}
- fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
+ fn read_option<T, F>(&mut self, mut f: F) -> T
where
- F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
+ F: FnMut(&mut Decoder, bool) -> T,
{
match self.pop() {
Json::Null => f(self, false),
@@ -2417,28 +2384,28 @@
}
}
- fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_seq<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder, usize) -> T,
{
- let array = expect!(self.pop(), Array)?;
+ let array = expect!(self.pop(), Array);
let len = array.len();
self.stack.extend(array.into_iter().rev());
f(self, len)
}
- fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_seq_elt<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
f(self)
}
- fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_map<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder, usize) -> T,
{
- let obj = expect!(self.pop(), Object)?;
+ let obj = expect!(self.pop(), Object);
let len = obj.len();
for (key, value) in obj {
self.stack.push(value);
@@ -2447,23 +2414,19 @@
f(self, len)
}
- fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_map_elt_key<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
f(self)
}
- fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T>
+ fn read_map_elt_val<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+ F: FnOnce(&mut Decoder) -> T,
{
f(self)
}
-
- fn error(&mut self, err: &str) -> DecoderError {
- ApplicationError(err.to_string())
- }
}
/// A trait for converting values to JSON
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index ea2df80..08b3c05 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -53,16 +53,24 @@
macro_rules! impl_read_unsigned_leb128 {
($fn_name:ident, $int_ty:ty) => {
#[inline]
- pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
- let mut result = 0;
- let mut shift = 0;
- let mut position = 0;
+ pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
+ // The first iteration of this loop is unpeeled. This is a
+ // performance win because this code is hot and integer values less
+ // than 128 are very common, typically occurring 50-80% or more of
+ // the time, even for u64 and u128.
+ let byte = slice[*position];
+ *position += 1;
+ if (byte & 0x80) == 0 {
+ return byte as $int_ty;
+ }
+ let mut result = (byte & 0x7F) as $int_ty;
+ let mut shift = 7;
loop {
- let byte = slice[position];
- position += 1;
+ let byte = slice[*position];
+ *position += 1;
if (byte & 0x80) == 0 {
result |= (byte as $int_ty) << shift;
- return (result, position);
+ return result;
} else {
result |= ((byte & 0x7F) as $int_ty) << shift;
}
@@ -122,15 +130,14 @@
macro_rules! impl_read_signed_leb128 {
($fn_name:ident, $int_ty:ty) => {
#[inline]
- pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
+ pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
let mut result = 0;
let mut shift = 0;
- let mut position = 0;
let mut byte;
loop {
- byte = slice[position];
- position += 1;
+ byte = slice[*position];
+ *position += 1;
result |= <$int_ty>::from(byte & 0x7F) << shift;
shift += 7;
@@ -144,7 +151,7 @@
result |= (!0 << shift);
}
- (result, position)
+ result
}
};
}
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index f2ef148..7a05d2b 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -130,8 +130,7 @@
#[inline]
fn emit_i8(&mut self, v: i8) -> EncodeResult {
- let as_u8: u8 = unsafe { std::mem::transmute(v) };
- self.emit_u8(as_u8)
+ self.emit_u8(v as u8)
}
#[inline]
@@ -560,138 +559,126 @@
}
macro_rules! read_leb128 {
- ($dec:expr, $fun:ident) => {{
- let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position..]);
- $dec.position += bytes_read;
- Ok(value)
- }};
+ ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }};
}
impl<'a> serialize::Decoder for Decoder<'a> {
- type Error = String;
-
#[inline]
- fn read_nil(&mut self) -> Result<(), Self::Error> {
- Ok(())
+ fn read_unit(&mut self) -> () {
+ ()
}
#[inline]
- fn read_u128(&mut self) -> Result<u128, Self::Error> {
+ fn read_u128(&mut self) -> u128 {
read_leb128!(self, read_u128_leb128)
}
#[inline]
- fn read_u64(&mut self) -> Result<u64, Self::Error> {
+ fn read_u64(&mut self) -> u64 {
read_leb128!(self, read_u64_leb128)
}
#[inline]
- fn read_u32(&mut self) -> Result<u32, Self::Error> {
+ fn read_u32(&mut self) -> u32 {
read_leb128!(self, read_u32_leb128)
}
#[inline]
- fn read_u16(&mut self) -> Result<u16, Self::Error> {
+ fn read_u16(&mut self) -> u16 {
let bytes = [self.data[self.position], self.data[self.position + 1]];
let value = u16::from_le_bytes(bytes);
self.position += 2;
- Ok(value)
+ value
}
#[inline]
- fn read_u8(&mut self) -> Result<u8, Self::Error> {
+ fn read_u8(&mut self) -> u8 {
let value = self.data[self.position];
self.position += 1;
- Ok(value)
+ value
}
#[inline]
- fn read_usize(&mut self) -> Result<usize, Self::Error> {
+ fn read_usize(&mut self) -> usize {
read_leb128!(self, read_usize_leb128)
}
#[inline]
- fn read_i128(&mut self) -> Result<i128, Self::Error> {
+ fn read_i128(&mut self) -> i128 {
read_leb128!(self, read_i128_leb128)
}
#[inline]
- fn read_i64(&mut self) -> Result<i64, Self::Error> {
+ fn read_i64(&mut self) -> i64 {
read_leb128!(self, read_i64_leb128)
}
#[inline]
- fn read_i32(&mut self) -> Result<i32, Self::Error> {
+ fn read_i32(&mut self) -> i32 {
read_leb128!(self, read_i32_leb128)
}
#[inline]
- fn read_i16(&mut self) -> Result<i16, Self::Error> {
+ fn read_i16(&mut self) -> i16 {
let bytes = [self.data[self.position], self.data[self.position + 1]];
let value = i16::from_le_bytes(bytes);
self.position += 2;
- Ok(value)
+ value
}
#[inline]
- fn read_i8(&mut self) -> Result<i8, Self::Error> {
- let as_u8 = self.data[self.position];
+ fn read_i8(&mut self) -> i8 {
+ let value = self.data[self.position];
self.position += 1;
- unsafe { Ok(::std::mem::transmute(as_u8)) }
+ value as i8
}
#[inline]
- fn read_isize(&mut self) -> Result<isize, Self::Error> {
+ fn read_isize(&mut self) -> isize {
read_leb128!(self, read_isize_leb128)
}
#[inline]
- fn read_bool(&mut self) -> Result<bool, Self::Error> {
- let value = self.read_u8()?;
- Ok(value != 0)
+ fn read_bool(&mut self) -> bool {
+ let value = self.read_u8();
+ value != 0
}
#[inline]
- fn read_f64(&mut self) -> Result<f64, Self::Error> {
- let bits = self.read_u64()?;
- Ok(f64::from_bits(bits))
+ fn read_f64(&mut self) -> f64 {
+ let bits = self.read_u64();
+ f64::from_bits(bits)
}
#[inline]
- fn read_f32(&mut self) -> Result<f32, Self::Error> {
- let bits = self.read_u32()?;
- Ok(f32::from_bits(bits))
+ fn read_f32(&mut self) -> f32 {
+ let bits = self.read_u32();
+ f32::from_bits(bits)
}
#[inline]
- fn read_char(&mut self) -> Result<char, Self::Error> {
- let bits = self.read_u32()?;
- Ok(std::char::from_u32(bits).unwrap())
+ fn read_char(&mut self) -> char {
+ let bits = self.read_u32();
+ std::char::from_u32(bits).unwrap()
}
#[inline]
- fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> {
- let len = self.read_usize()?;
+ fn read_str(&mut self) -> Cow<'_, str> {
+ let len = self.read_usize();
let sentinel = self.data[self.position + len];
assert!(sentinel == STR_SENTINEL);
let s = unsafe {
std::str::from_utf8_unchecked(&self.data[self.position..self.position + len])
};
self.position += len + 1;
- Ok(Cow::Borrowed(s))
+ Cow::Borrowed(s)
}
#[inline]
- fn error(&mut self, err: &str) -> Self::Error {
- err.to_string()
- }
-
- #[inline]
- fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), String> {
+ fn read_raw_bytes_into(&mut self, s: &mut [u8]) {
let start = self.position;
self.position += s.len();
s.copy_from_slice(&self.data[start..self.position]);
- Ok(())
}
}
@@ -719,9 +706,9 @@
// Specialize decoding `Vec<u8>`. This specialization also applies to decoding `Box<[u8]>`s, etc.,
// since the default implementations call `decode` to produce a `Vec<u8>` internally.
impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> {
- fn decode(d: &mut Decoder<'a>) -> Result<Self, String> {
- let len = serialize::Decoder::read_usize(d)?;
- Ok(d.read_raw_bytes(len).to_owned())
+ fn decode(d: &mut Decoder<'a>) -> Self {
+ let len = serialize::Decoder::read_usize(d);
+ d.read_raw_bytes(len).to_owned()
}
}
@@ -756,13 +743,13 @@
impl<'a> serialize::Decodable<Decoder<'a>> for IntEncodedWithFixedSize {
#[inline]
- fn decode(decoder: &mut Decoder<'a>) -> Result<IntEncodedWithFixedSize, String> {
+ fn decode(decoder: &mut Decoder<'a>) -> IntEncodedWithFixedSize {
let _start_pos = decoder.position();
let bytes = decoder.read_raw_bytes(IntEncodedWithFixedSize::ENCODED_SIZE);
let _end_pos = decoder.position();
debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
let value = u64::from_le_bytes(bytes.try_into().unwrap());
- Ok(IntEncodedWithFixedSize(value))
+ IntEncodedWithFixedSize(value)
}
}
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 96a2231..a617240 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -173,144 +173,145 @@
}
}
+// Note: all the methods in this trait are infallible, which may be surprising.
+// They used to be fallible (i.e. return a `Result`) but many of the impls just
+// panicked when something went wrong, and for the cases that didn't the
+// top-level invocation would also just panic on failure. Switching to
+// infallibility made things faster and lots of code a little simpler and more
+// concise.
pub trait Decoder {
- type Error;
-
// Primitive types:
- fn read_nil(&mut self) -> Result<(), Self::Error>;
- fn read_usize(&mut self) -> Result<usize, Self::Error>;
- fn read_u128(&mut self) -> Result<u128, Self::Error>;
- fn read_u64(&mut self) -> Result<u64, Self::Error>;
- fn read_u32(&mut self) -> Result<u32, Self::Error>;
- fn read_u16(&mut self) -> Result<u16, Self::Error>;
- fn read_u8(&mut self) -> Result<u8, Self::Error>;
- fn read_isize(&mut self) -> Result<isize, Self::Error>;
- fn read_i128(&mut self) -> Result<i128, Self::Error>;
- fn read_i64(&mut self) -> Result<i64, Self::Error>;
- fn read_i32(&mut self) -> Result<i32, Self::Error>;
- fn read_i16(&mut self) -> Result<i16, Self::Error>;
- fn read_i8(&mut self) -> Result<i8, Self::Error>;
- fn read_bool(&mut self) -> Result<bool, Self::Error>;
- fn read_f64(&mut self) -> Result<f64, Self::Error>;
- fn read_f32(&mut self) -> Result<f32, Self::Error>;
- fn read_char(&mut self) -> Result<char, Self::Error>;
- fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error>;
- fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error>;
+ fn read_unit(&mut self) -> ();
+ fn read_usize(&mut self) -> usize;
+ fn read_u128(&mut self) -> u128;
+ fn read_u64(&mut self) -> u64;
+ fn read_u32(&mut self) -> u32;
+ fn read_u16(&mut self) -> u16;
+ fn read_u8(&mut self) -> u8;
+ fn read_isize(&mut self) -> isize;
+ fn read_i128(&mut self) -> i128;
+ fn read_i64(&mut self) -> i64;
+ fn read_i32(&mut self) -> i32;
+ fn read_i16(&mut self) -> i16;
+ fn read_i8(&mut self) -> i8;
+ fn read_bool(&mut self) -> bool;
+ fn read_f64(&mut self) -> f64;
+ fn read_f32(&mut self) -> f32;
+ fn read_char(&mut self) -> char;
+ fn read_str(&mut self) -> Cow<'_, str>;
+ fn read_raw_bytes_into(&mut self, s: &mut [u8]);
// Compound types:
#[inline]
- fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_enum<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
#[inline]
- fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> Result<T, Self::Error>
+ fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> T
where
- F: FnMut(&mut Self, usize) -> Result<T, Self::Error>,
+ F: FnMut(&mut Self, usize) -> T,
{
- let disr = self.read_usize()?;
+ let disr = self.read_usize();
f(self, disr)
}
#[inline]
- fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_enum_variant_arg<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
#[inline]
- fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_struct<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
#[inline]
- fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error>
+ fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
#[inline]
- fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> Result<T, Self::Error>
+ fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
#[inline]
- fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_tuple_arg<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
// Specialized types:
- fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
+ fn read_option<T, F>(&mut self, mut f: F) -> T
where
- F: FnMut(&mut Self, bool) -> Result<T, Self::Error>,
+ F: FnMut(&mut Self, bool) -> T,
{
self.read_enum(move |this| {
this.read_enum_variant(&["None", "Some"], move |this, idx| match idx {
0 => f(this, false),
1 => f(this, true),
- _ => Err(this.error("read_option: expected 0 for None or 1 for Some")),
+ _ => panic!("read_option: expected 0 for None or 1 for Some"),
})
})
}
- fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_seq<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self, usize) -> T,
{
- let len = self.read_usize()?;
+ let len = self.read_usize();
f(self, len)
}
#[inline]
- fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_seq_elt<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
- fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_map<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self, usize) -> T,
{
- let len = self.read_usize()?;
+ let len = self.read_usize();
f(self, len)
}
#[inline]
- fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_map_elt_key<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
#[inline]
- fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+ fn read_map_elt_val<T, F>(&mut self, f: F) -> T
where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+ F: FnOnce(&mut Self) -> T,
{
f(self)
}
-
- // Failure
- fn error(&mut self, err: &str) -> Self::Error;
}
/// Trait for types that can be serialized
@@ -340,7 +341,7 @@
/// * `TyDecodable` should be used for types that are only serialized in crate
/// metadata or the incremental cache. This is most types in `rustc_middle`.
pub trait Decodable<D: Decoder>: Sized {
- fn decode(d: &mut D) -> Result<Self, D::Error>;
+ fn decode(d: &mut D) -> Self;
}
macro_rules! direct_serialize_impls {
@@ -353,7 +354,7 @@
}
impl<D: Decoder> Decodable<D> for $ty {
- fn decode(d: &mut D) -> Result<$ty, D::Error> {
+ fn decode(d: &mut D) -> $ty {
d.$read_method()
}
}
@@ -387,7 +388,7 @@
}
impl<D: Decoder> Decodable<D> for ! {
- fn decode(_d: &mut D) -> Result<!, D::Error> {
+ fn decode(_d: &mut D) -> ! {
unreachable!()
}
}
@@ -399,8 +400,8 @@
}
impl<D: Decoder> Decodable<D> for ::std::num::NonZeroU32 {
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- d.read_u32().map(|d| ::std::num::NonZeroU32::new(d).unwrap())
+ fn decode(d: &mut D) -> Self {
+ ::std::num::NonZeroU32::new(d.read_u32()).unwrap()
}
}
@@ -423,8 +424,8 @@
}
impl<D: Decoder> Decodable<D> for String {
- fn decode(d: &mut D) -> Result<String, D::Error> {
- Ok(d.read_str()?.into_owned())
+ fn decode(d: &mut D) -> String {
+ d.read_str().into_owned()
}
}
@@ -435,8 +436,8 @@
}
impl<D: Decoder> Decodable<D> for () {
- fn decode(d: &mut D) -> Result<(), D::Error> {
- d.read_nil()
+ fn decode(d: &mut D) -> () {
+ d.read_unit()
}
}
@@ -447,16 +448,16 @@
}
impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
- fn decode(d: &mut D) -> Result<PhantomData<T>, D::Error> {
- d.read_nil()?;
- Ok(PhantomData)
+ fn decode(d: &mut D) -> PhantomData<T> {
+ d.read_unit();
+ PhantomData
}
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> {
- fn decode(d: &mut D) -> Result<Box<[T]>, D::Error> {
- let v: Vec<T> = Decodable::decode(d)?;
- Ok(v.into_boxed_slice())
+ fn decode(d: &mut D) -> Box<[T]> {
+ let v: Vec<T> = Decodable::decode(d);
+ v.into_boxed_slice()
}
}
@@ -467,8 +468,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<T> {
- fn decode(d: &mut D) -> Result<Rc<T>, D::Error> {
- Ok(Rc::new(Decodable::decode(d)?))
+ fn decode(d: &mut D) -> Rc<T> {
+ Rc::new(Decodable::decode(d))
}
}
@@ -491,13 +492,22 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
- default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
+ default fn decode(d: &mut D) -> Vec<T> {
d.read_seq(|d, len| {
- let mut v = Vec::with_capacity(len);
- for _ in 0..len {
- v.push(d.read_seq_elt(|d| Decodable::decode(d))?);
+ // SAFETY: we set the capacity in advance, only write elements, and
+ // only set the length at the end once the writing has succeeded.
+ let mut vec = Vec::with_capacity(len);
+ unsafe {
+ let ptr: *mut T = vec.as_mut_ptr();
+ for i in 0..len {
+ std::ptr::write(
+ ptr.offset(i as isize),
+ d.read_seq_elt(|d| Decodable::decode(d)),
+ );
+ }
+ vec.set_len(len);
}
- Ok(v)
+ vec
})
}
}
@@ -510,14 +520,14 @@
}
impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] {
- fn decode(d: &mut D) -> Result<[u8; N], D::Error> {
+ fn decode(d: &mut D) -> [u8; N] {
d.read_seq(|d, len| {
assert!(len == N);
let mut v = [0u8; N];
for i in 0..len {
- v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
+ v[i] = d.read_seq_elt(|d| Decodable::decode(d));
}
- Ok(v)
+ v
})
}
}
@@ -536,9 +546,9 @@
where
[T]: ToOwned<Owned = Vec<T>>,
{
- fn decode(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
- let v: Vec<T> = Decodable::decode(d)?;
- Ok(Cow::Owned(v))
+ fn decode(d: &mut D) -> Cow<'static, [T]> {
+ let v: Vec<T> = Decodable::decode(d);
+ Cow::Owned(v)
}
}
@@ -552,8 +562,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> {
- fn decode(d: &mut D) -> Result<Option<T>, D::Error> {
- d.read_option(|d, b| if b { Ok(Some(Decodable::decode(d)?)) } else { Ok(None) })
+ fn decode(d: &mut D) -> Option<T> {
+ d.read_option(|d, b| if b { Some(Decodable::decode(d)) } else { None })
}
}
@@ -571,17 +581,12 @@
}
impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
- fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
+ fn decode(d: &mut D) -> Result<T1, T2> {
d.read_enum(|d| {
d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr {
- 0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)),
- 1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)),
- _ => {
- panic!(
- "Encountered invalid discriminant while \
- decoding `Result`."
- );
- }
+ 0 => Ok(d.read_enum_variant_arg(|d| T1::decode(d))),
+ 1 => Err(d.read_enum_variant_arg(|d| T2::decode(d))),
+ _ => panic!("Encountered invalid discriminant while decoding `Result`."),
})
})
}
@@ -609,13 +614,13 @@
( $($name:ident,)+ ) => (
impl<D: Decoder, $($name: Decodable<D>),+> Decodable<D> for ($($name,)+) {
#[allow(non_snake_case)]
- fn decode(d: &mut D) -> Result<($($name,)+), D::Error> {
+ fn decode(d: &mut D) -> ($($name,)+) {
let len: usize = count!($($name)+);
d.read_tuple(len, |d| {
- let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> {
+ let ret = ($(d.read_tuple_arg(|d| -> $name {
Decodable::decode(d)
- })?,)+);
- Ok(ret)
+ }),)+);
+ ret
})
}
}
@@ -651,9 +656,9 @@
}
impl<D: Decoder> Decodable<D> for path::PathBuf {
- fn decode(d: &mut D) -> Result<path::PathBuf, D::Error> {
- let bytes: String = Decodable::decode(d)?;
- Ok(path::PathBuf::from(bytes))
+ fn decode(d: &mut D) -> path::PathBuf {
+ let bytes: String = Decodable::decode(d);
+ path::PathBuf::from(bytes)
}
}
@@ -664,8 +669,8 @@
}
impl<D: Decoder, T: Decodable<D> + Copy> Decodable<D> for Cell<T> {
- fn decode(d: &mut D) -> Result<Cell<T>, D::Error> {
- Ok(Cell::new(Decodable::decode(d)?))
+ fn decode(d: &mut D) -> Cell<T> {
+ Cell::new(Decodable::decode(d))
}
}
@@ -681,8 +686,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for RefCell<T> {
- fn decode(d: &mut D) -> Result<RefCell<T>, D::Error> {
- Ok(RefCell::new(Decodable::decode(d)?))
+ fn decode(d: &mut D) -> RefCell<T> {
+ RefCell::new(Decodable::decode(d))
}
}
@@ -693,8 +698,8 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> {
- fn decode(d: &mut D) -> Result<Arc<T>, D::Error> {
- Ok(Arc::new(Decodable::decode(d)?))
+ fn decode(d: &mut D) -> Arc<T> {
+ Arc::new(Decodable::decode(d))
}
}
@@ -704,7 +709,7 @@
}
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
- fn decode(d: &mut D) -> Result<Box<T>, D::Error> {
- Ok(Box::new(Decodable::decode(d)?))
+ fn decode(d: &mut D) -> Box<T> {
+ Box::new(Decodable::decode(d))
}
}
diff --git a/compiler/rustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs
index a759fa1..ede912b 100644
--- a/compiler/rustc_serialize/tests/json.rs
+++ b/compiler/rustc_serialize/tests/json.rs
@@ -1,14 +1,10 @@
#![allow(rustc::internal)]
-use json::DecoderError::*;
use json::ErrorCode::*;
use json::Json::*;
use json::JsonEvent::*;
use json::ParserError::*;
-use json::{
- from_str, DecodeResult, Decoder, DecoderError, Encoder, EncoderError, Json, JsonEvent, Parser,
- StackElement,
-};
+use json::{from_str, Decoder, Encoder, EncoderError, Json, JsonEvent, Parser, StackElement};
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::json;
use rustc_serialize::{Decodable, Encodable};
@@ -26,27 +22,27 @@
#[test]
fn test_decode_option_none() {
let s = "{}";
- let obj: OptionData = json::decode(s).unwrap();
+ let obj: OptionData = json::decode(s);
assert_eq!(obj, OptionData { opt: None });
}
#[test]
fn test_decode_option_some() {
let s = "{ \"opt\": 10 }";
- let obj: OptionData = json::decode(s).unwrap();
+ let obj: OptionData = json::decode(s);
assert_eq!(obj, OptionData { opt: Some(10) });
}
#[test]
-fn test_decode_option_malformed() {
- check_err::<OptionData>(
- "{ \"opt\": [] }",
- ExpectedError("Number".to_string(), "[]".to_string()),
- );
- check_err::<OptionData>(
- "{ \"opt\": false }",
- ExpectedError("Number".to_string(), "false".to_string()),
- );
+#[should_panic(expected = r#"ExpectedError("Number", "[]")"#)]
+fn test_decode_option_malformed1() {
+ check_err::<OptionData>(r#"{ "opt": [] }"#);
+}
+
+#[test]
+#[should_panic(expected = r#"ExpectedError("Number", "false")"#)]
+fn test_decode_option_malformed2() {
+ check_err::<OptionData>(r#"{ "opt": false }"#);
}
#[derive(PartialEq, Encodable, Decodable, Debug)]
@@ -329,13 +325,13 @@
#[test]
fn test_decode_identifiers() {
- let v: () = json::decode("null").unwrap();
+ let v: () = json::decode("null");
assert_eq!(v, ());
- let v: bool = json::decode("true").unwrap();
+ let v: bool = json::decode("true");
assert_eq!(v, true);
- let v: bool = json::decode("false").unwrap();
+ let v: bool = json::decode("false");
assert_eq!(v, false);
}
@@ -368,42 +364,42 @@
}
#[test]
+#[should_panic(expected = r#"ExpectedError("Integer", "765.25")"#)]
fn test_decode_numbers() {
- let v: f64 = json::decode("3").unwrap();
+ let v: f64 = json::decode("3");
assert_eq!(v, 3.0);
- let v: f64 = json::decode("3.1").unwrap();
+ let v: f64 = json::decode("3.1");
assert_eq!(v, 3.1);
- let v: f64 = json::decode("-1.2").unwrap();
+ let v: f64 = json::decode("-1.2");
assert_eq!(v, -1.2);
- let v: f64 = json::decode("0.4").unwrap();
+ let v: f64 = json::decode("0.4");
assert_eq!(v, 0.4);
- let v: f64 = json::decode("0.4e5").unwrap();
+ let v: f64 = json::decode("0.4e5");
assert_eq!(v, 0.4e5);
- let v: f64 = json::decode("0.4e15").unwrap();
+ let v: f64 = json::decode("0.4e15");
assert_eq!(v, 0.4e15);
- let v: f64 = json::decode("0.4e-01").unwrap();
+ let v: f64 = json::decode("0.4e-01");
assert_eq!(v, 0.4e-01);
- let v: u64 = json::decode("0").unwrap();
+ let v: u64 = json::decode("0");
assert_eq!(v, 0);
- let v: u64 = json::decode("18446744073709551615").unwrap();
+ let v: u64 = json::decode("18446744073709551615");
assert_eq!(v, u64::MAX);
- let v: i64 = json::decode("-9223372036854775808").unwrap();
+ let v: i64 = json::decode("-9223372036854775808");
assert_eq!(v, i64::MIN);
- let v: i64 = json::decode("9223372036854775807").unwrap();
+ let v: i64 = json::decode("9223372036854775807");
assert_eq!(v, i64::MAX);
- let res: DecodeResult<i64> = json::decode("765.25");
- assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25".to_string())));
+ json::decode::<i64>("765.25");
}
#[test]
@@ -438,7 +434,7 @@
];
for (i, o) in s {
- let v: string::String = json::decode(i).unwrap();
+ let v: string::String = json::decode(i);
assert_eq!(v, o);
}
}
@@ -463,39 +459,41 @@
#[test]
fn test_decode_array() {
- let v: Vec<()> = json::decode("[]").unwrap();
+ let v: Vec<()> = json::decode("[]");
assert_eq!(v, []);
- let v: Vec<()> = json::decode("[null]").unwrap();
+ let v: Vec<()> = json::decode("[null]");
assert_eq!(v, [()]);
- let v: Vec<bool> = json::decode("[true]").unwrap();
+ let v: Vec<bool> = json::decode("[true]");
assert_eq!(v, [true]);
- let v: Vec<isize> = json::decode("[3, 1]").unwrap();
+ let v: Vec<isize> = json::decode("[3, 1]");
assert_eq!(v, [3, 1]);
- let v: Vec<Vec<usize>> = json::decode("[[3], [1, 2]]").unwrap();
+ let v: Vec<Vec<usize>> = json::decode("[[3], [1, 2]]");
assert_eq!(v, [vec![3], vec![1, 2]]);
}
#[test]
fn test_decode_tuple() {
- let t: (usize, usize, usize) = json::decode("[1, 2, 3]").unwrap();
+ let t: (usize, usize, usize) = json::decode("[1, 2, 3]");
assert_eq!(t, (1, 2, 3));
- let t: (usize, string::String) = json::decode("[1, \"two\"]").unwrap();
+ let t: (usize, string::String) = json::decode("[1, \"two\"]");
assert_eq!(t, (1, "two".to_string()));
}
#[test]
+#[should_panic]
fn test_decode_tuple_malformed_types() {
- assert!(json::decode::<(usize, string::String)>("[1, 2]").is_err());
+ json::decode::<(usize, string::String)>("[1, 2]");
}
#[test]
+#[should_panic]
fn test_decode_tuple_malformed_length() {
- assert!(json::decode::<(usize, usize)>("[1, 2, 3]").is_err());
+ json::decode::<(usize, usize)>("[1, 2, 3]");
}
#[test]
@@ -562,7 +560,7 @@
]
}";
- let v: Outer = json::decode(s).unwrap();
+ let v: Outer = json::decode(s);
assert_eq!(
v,
Outer { inner: vec![Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }] }
@@ -577,7 +575,7 @@
#[test]
fn test_decode_struct_with_nan() {
let s = "{\"f\":null,\"a\":[null,123]}";
- let obj: FloatStruct = json::decode(s).unwrap();
+ let obj: FloatStruct = json::decode(s);
assert!(obj.f.is_nan());
assert!(obj.a[0].is_nan());
assert_eq!(obj.a[1], 123f64);
@@ -585,20 +583,20 @@
#[test]
fn test_decode_option() {
- let value: Option<string::String> = json::decode("null").unwrap();
+ let value: Option<string::String> = json::decode("null");
assert_eq!(value, None);
- let value: Option<string::String> = json::decode("\"jodhpurs\"").unwrap();
+ let value: Option<string::String> = json::decode("\"jodhpurs\"");
assert_eq!(value, Some("jodhpurs".to_string()));
}
#[test]
fn test_decode_enum() {
- let value: Animal = json::decode("\"Dog\"").unwrap();
+ let value: Animal = json::decode("\"Dog\"");
assert_eq!(value, Dog);
let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}";
- let value: Animal = json::decode(s).unwrap();
+ let value: Animal = json::decode(s);
assert_eq!(value, Frog("Henry".to_string(), 349));
}
@@ -606,7 +604,7 @@
fn test_decode_map() {
let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
\"fields\":[\"Henry\", 349]}}";
- let mut map: BTreeMap<string::String, Animal> = json::decode(s).unwrap();
+ let mut map: BTreeMap<string::String, Animal> = json::decode(s);
assert_eq!(map.remove(&"a".to_string()), Some(Dog));
assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349)));
@@ -630,59 +628,65 @@
A(f64),
B(string::String),
}
-fn check_err<T: Decodable<Decoder>>(to_parse: &'static str, expected: DecoderError) {
- let res: DecodeResult<T> = match from_str(to_parse) {
- Err(e) => Err(ParseError(e)),
- Ok(json) => Decodable::decode(&mut Decoder::new(json)),
- };
- match res {
- Ok(_) => panic!("`{:?}` parsed & decoded ok, expecting error `{:?}`", to_parse, expected),
- Err(ParseError(e)) => panic!("`{:?}` is not valid json: {:?}", to_parse, e),
- Err(e) => {
- assert_eq!(e, expected);
- }
- }
+fn check_err<T: Decodable<Decoder>>(to_parse: &str) {
+ let json = from_str(to_parse).unwrap();
+ let _: T = Decodable::decode(&mut Decoder::new(json));
}
#[test]
-fn test_decode_errors_struct() {
- check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
- check_err::<DecodeStruct>(
- "{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
- ExpectedError("Number".to_string(), "true".to_string()),
- );
- check_err::<DecodeStruct>(
- "{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}",
- ExpectedError("Boolean".to_string(), "[]".to_string()),
- );
- check_err::<DecodeStruct>(
- "{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}",
- ExpectedError("String".to_string(), "{}".to_string()),
- );
- check_err::<DecodeStruct>(
- "{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}",
- ExpectedError("Array".to_string(), "null".to_string()),
- );
- check_err::<DecodeStruct>(
- "{\"x\": 1, \"y\": true, \"z\": \"\"}",
- MissingFieldError("w".to_string()),
- );
+#[should_panic(expected = r#"ExpectedError("Object", "[]")"#)]
+fn test_decode_errors_struct1() {
+ check_err::<DecodeStruct>("[]");
}
#[test]
-fn test_decode_errors_enum() {
- check_err::<DecodeEnum>("{}", MissingFieldError("variant".to_string()));
- check_err::<DecodeEnum>(
- "{\"variant\": 1}",
- ExpectedError("String".to_string(), "1".to_string()),
- );
- check_err::<DecodeEnum>("{\"variant\": \"A\"}", MissingFieldError("fields".to_string()));
- check_err::<DecodeEnum>(
- "{\"variant\": \"A\", \"fields\": null}",
- ExpectedError("Array".to_string(), "null".to_string()),
- );
- check_err::<DecodeEnum>(
- "{\"variant\": \"C\", \"fields\": []}",
- UnknownVariantError("C".to_string()),
- );
+#[should_panic(expected = r#"ExpectedError("Number", "true")"#)]
+fn test_decode_errors_struct2() {
+ check_err::<DecodeStruct>(r#"{"x": true, "y": true, "z": "", "w": []}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Boolean", "[]")"#)]
+fn test_decode_errors_struct3() {
+ check_err::<DecodeStruct>(r#"{"x": 1, "y": [], "z": "", "w": []}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("String", "{}")"#)]
+fn test_decode_errors_struct4() {
+ check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": {}, "w": []}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Array", "null")"#)]
+fn test_decode_errors_struct5() {
+ check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": "", "w": null}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Array", "null")"#)]
+fn test_decode_errors_struct6() {
+ check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": ""}"#);
+}
+
+#[test]
+#[should_panic(expected = r#"MissingFieldError("variant")"#)]
+fn test_decode_errors_enum1() {
+ check_err::<DecodeEnum>(r#"{}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("String", "1")"#)]
+fn test_decode_errors_enum2() {
+ check_err::<DecodeEnum>(r#"{"variant": 1}"#);
+}
+#[test]
+#[should_panic(expected = r#"MissingFieldError("fields")"#)]
+fn test_decode_errors_enum3() {
+ check_err::<DecodeEnum>(r#"{"variant": "A"}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Array", "null")"#)]
+fn test_decode_errors_enum4() {
+ check_err::<DecodeEnum>(r#"{"variant": "A", "fields": null}"#);
+}
+#[test]
+#[should_panic(expected = r#"UnknownVariantError("C")"#)]
+fn test_decode_errors_enum5() {
+ check_err::<DecodeEnum>(r#"{"variant": "C", "fields": []}"#);
}
#[test]
@@ -944,7 +948,7 @@
map.insert(Enum::Foo, 0);
let result = json::encode(&map).unwrap();
assert_eq!(&result[..], r#"{"Foo":0}"#);
- let decoded: HashMap<Enum, _> = json::decode(&result).unwrap();
+ let decoded: HashMap<Enum, _> = json::decode(&result);
assert_eq!(map, decoded);
}
@@ -957,10 +961,11 @@
Ok(o) => o,
};
let mut decoder = Decoder::new(json_obj);
- let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder).unwrap();
+ let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder);
}
#[test]
+#[should_panic(expected = r#"ExpectedError("Number", "a")"#)]
fn test_hashmap_with_numeric_key_will_error_with_string_keys() {
use std::collections::HashMap;
let json_str = "{\"a\":true}";
@@ -969,8 +974,7 @@
Ok(o) => o,
};
let mut decoder = Decoder::new(json_obj);
- let result: Result<HashMap<usize, bool>, DecoderError> = Decodable::decode(&mut decoder);
- assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string())));
+ let _: HashMap<usize, bool> = Decodable::decode(&mut decoder);
}
fn assert_stream_equal(src: &str, expected: Vec<(JsonEvent, Vec<StackElement<'_>>)>) {
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index 3e2aab5..314c07d 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -30,9 +30,8 @@
let mut position = 0;
for &expected in &values {
- let (actual, bytes_read) = $read_fn_name(&stream[position..]);
+ let actual = $read_fn_name(&stream, &mut position);
assert_eq!(expected, actual);
- position += bytes_read;
}
assert_eq!(stream.len(), position);
}
@@ -77,9 +76,8 @@
let mut position = 0;
for &expected in &values {
- let (actual, bytes_read) = $read_fn_name(&stream[position..]);
+ let actual = $read_fn_name(&stream, &mut position);
assert_eq!(expected, actual);
- position += bytes_read;
}
assert_eq!(stream.len(), position);
}
diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs
index 13b3676..298eb11 100644
--- a/compiler/rustc_serialize/tests/opaque.rs
+++ b/compiler/rustc_serialize/tests/opaque.rs
@@ -41,7 +41,7 @@
let mut decoder = Decoder::new(&data[..], 0);
for value in values {
- let decoded = Decodable::decode(&mut decoder).unwrap();
+ let decoded = Decodable::decode(&mut decoder);
assert_eq!(value, decoded);
}
}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 08bcea2..7a0d9a2 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -12,11 +12,11 @@
use rustc_data_structures::impl_stable_hash_via_hash;
use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
+use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
use rustc_serialize::json;
-use crate::parse::CrateConfig;
+use crate::parse::{CrateCheckConfig, CrateConfig};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
use rustc_span::source_map::{FileName, FilePathMapping};
@@ -63,6 +63,22 @@
Checks,
}
+/// The different settings that the `-Z cf-protection` flag can have.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum CFProtection {
+ /// Do not enable control-flow protection
+ None,
+
+ /// Emit control-flow protection for branches (enables indirect branch tracking).
+ Branch,
+
+ /// Emit control-flow protection for returns.
+ Return,
+
+ /// Emit control-flow protection for both branches and returns.
+ Full,
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum OptLevel {
No, // -O0
@@ -127,16 +143,16 @@
Block,
}
-/// The different settings that the `-Z instrument-coverage` flag can have.
+/// The different settings that the `-C instrument-coverage` flag can have.
///
-/// Coverage instrumentation now supports combining `-Z instrument-coverage`
+/// Coverage instrumentation now supports combining `-C instrument-coverage`
/// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
/// and higher). Nevertheless, there are many variables, depending on options
/// selected, code structure, and enabled attributes. If errors are encountered,
/// either while compiling or when generating `llvm-cov show` reports, consider
/// lowering the optimization level, including or excluding `-C link-dead-code`,
-/// or using `-Z instrument-coverage=except-unused-functions` or `-Z
-/// instrument-coverage=except-unused-generics`.
+/// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
+/// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
///
/// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
/// coverage map, it will not attempt to generate synthetic functions for unused
@@ -148,13 +164,13 @@
/// unless the function has type parameters.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum InstrumentCoverage {
- /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
+ /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
All,
- /// `-Z instrument-coverage=except-unused-generics`
+ /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
ExceptUnusedGenerics,
- /// `-Z instrument-coverage=except-unused-functions`
+ /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
ExceptUnusedFunctions,
- /// `-Z instrument-coverage=off` (or `no`, etc.)
+ /// `-C instrument-coverage=off` (or `no`, etc.)
Off,
}
@@ -565,6 +581,7 @@
TargetSpec,
NativeStaticLibs,
StackProtectorStrategies,
+ LinkArgs,
}
#[derive(Copy, Clone)]
@@ -769,7 +786,6 @@
externs: Externs(BTreeMap::new()),
extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
crate_name: None,
- alt_std_name: None,
libs: Vec::new(),
unstable_features: UnstableFeatures::Disallow,
debug_assertions: true,
@@ -891,11 +907,36 @@
}
}
+#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+pub enum PAuthKey {
+ A,
+ B,
+}
+
+#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+pub struct PacRet {
+ pub leaf: bool,
+ pub key: PAuthKey,
+}
+
+#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+pub struct BranchProtection {
+ pub bti: bool,
+ pub pac_ret: Option<PacRet>,
+}
+
+impl Default for BranchProtection {
+ fn default() -> Self {
+ BranchProtection { bti: false, pac_ret: None }
+ }
+}
+
pub const fn default_lib_output() -> CrateType {
CrateType::Rlib
}
fn default_configuration(sess: &Session) -> CrateConfig {
+ // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
let end = &sess.target.endian;
let arch = &sess.target.arch;
let wordsz = sess.target.pointer_width.to_string();
@@ -980,6 +1021,91 @@
cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
}
+/// The parsed `--check-cfg` options
+pub struct CheckCfg<T = String> {
+ /// Set if `names()` checking is enabled
+ pub names_checked: bool,
+ /// The union of all `names()`
+ pub names_valid: FxHashSet<T>,
+ /// The set of names for which `values()` was used
+ pub values_checked: FxHashSet<T>,
+ /// The set of all (name, value) pairs passed in `values()`
+ pub values_valid: FxHashSet<(T, T)>,
+}
+
+impl<T> Default for CheckCfg<T> {
+ fn default() -> Self {
+ CheckCfg {
+ names_checked: false,
+ names_valid: FxHashSet::default(),
+ values_checked: FxHashSet::default(),
+ values_valid: FxHashSet::default(),
+ }
+ }
+}
+
+impl<T> CheckCfg<T> {
+ fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
+ CheckCfg {
+ names_checked: self.names_checked,
+ names_valid: self.names_valid.iter().map(|a| f(a)).collect(),
+ values_checked: self.values_checked.iter().map(|a| f(a)).collect(),
+ values_valid: self.values_valid.iter().map(|(a, b)| (f(a), f(b))).collect(),
+ }
+ }
+}
+
+/// Converts the crate `--check-cfg` options from `String` to `Symbol`.
+/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
+/// but the symbol interner is not yet set up then, so we must convert it later.
+pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
+ cfg.map_data(|s| Symbol::intern(s))
+}
+
+impl CrateCheckConfig {
+ /// Fills a `CrateCheckConfig` with well-known configuration names.
+ pub fn fill_well_known(&mut self) {
+ // NOTE: This should be kept in sync with `default_configuration`
+ const WELL_KNOWN_NAMES: &[Symbol] = &[
+ sym::unix,
+ sym::windows,
+ sym::target_os,
+ sym::target_family,
+ sym::target_arch,
+ sym::target_endian,
+ sym::target_pointer_width,
+ sym::target_env,
+ sym::target_abi,
+ sym::target_vendor,
+ sym::target_thread_local,
+ sym::target_has_atomic_load_store,
+ sym::target_has_atomic,
+ sym::target_has_atomic_equal_alignment,
+ sym::panic,
+ sym::sanitize,
+ sym::debug_assertions,
+ sym::proc_macro,
+ sym::test,
+ sym::doc,
+ sym::doctest,
+ sym::feature,
+ ];
+ for &name in WELL_KNOWN_NAMES {
+ self.names_valid.insert(name);
+ }
+ }
+
+ /// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
+ pub fn fill_actual(&mut self, cfg: &CrateConfig) {
+ for &(k, v) in cfg {
+ self.names_valid.insert(k);
+ if let Some(v) = v {
+ self.values_valid.insert((k, v));
+ }
+ }
+ }
+}
+
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items.
@@ -1123,6 +1249,7 @@
vec![
opt::flag_s("h", "help", "Display this message"),
opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
+ opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
opt::multi_s(
"L",
"",
@@ -1163,7 +1290,8 @@
"Compiler information to print on stdout",
"[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
target-cpus|target-features|relocation-models|code-models|\
- tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
+ tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
+ link-args]",
),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1595,6 +1723,7 @@
);
}
}
+ "link-args" => PrintRequest::LinkArgs,
req => early_error(error_format, &format!("unknown print request `{}`", req)),
}));
@@ -2102,12 +2231,7 @@
check_thread_count(&debugging_opts, error_format);
- let incremental =
- if std::env::var_os("RUSTC_FORCE_INCREMENTAL").map(|v| v == "1").unwrap_or(false) {
- cg.incremental.as_ref().map(PathBuf::from)
- } else {
- None
- };
+ let incremental = cg.incremental.as_ref().map(PathBuf::from);
let assert_incr_state =
parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
@@ -2173,18 +2297,44 @@
_ => {}
}
- if debugging_opts.instrument_coverage.is_some()
- && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
- {
+ // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
+ // precedence.
+ match (cg.instrument_coverage, debugging_opts.instrument_coverage) {
+ (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
+ early_error(
+ error_format,
+ "incompatible values passed for `-C instrument-coverage` \
+ and `-Z instrument-coverage`",
+ );
+ }
+ (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
+ (Some(_), _) if !debugging_opts.unstable_options => {
+ early_error(
+ error_format,
+ "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
+ );
+ }
+ (None, None) => {}
+ (None, ic) => {
+ early_warn(
+ error_format,
+ "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
+ );
+ cg.instrument_coverage = ic;
+ }
+ _ => {}
+ }
+
+ if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
early_error(
error_format,
- "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
+ "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
or `-C profile-generate`",
);
}
- // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
+ // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
// and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
// multiple runs, including some changes to source code; so mangled names must be consistent
// across compilations.
@@ -2193,7 +2343,7 @@
Some(SymbolManglingVersion::Legacy) => {
early_warn(
error_format,
- "-Z instrument-coverage requires symbol mangling version `v0`, \
+ "-C instrument-coverage requires symbol mangling version `v0`, \
but `-C symbol-mangling-version=legacy` was specified",
);
}
@@ -2215,6 +2365,16 @@
}
}
+ if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
+ && !nightly_options::is_unstable_enabled(matches)
+ {
+ early_error(
+ error_format,
+ "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
+ flag must also be passed to explicitly use it",
+ );
+ }
+
let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
let cg = cg;
@@ -2324,7 +2484,6 @@
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
extern_dep_specs,
crate_name,
- alt_std_name: None,
libs,
debug_assertions,
actually_rustdoc: false,
@@ -2574,11 +2733,11 @@
/// we have an opt-in scheme here, so one is hopefully forced to think about
/// how the hash should be calculated when adding a new command-line argument.
crate mod dep_tracking {
- use super::LdImpl;
use super::{
- CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
- LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
- SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
+ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
+ InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType,
+ OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion,
+ TrimmedDefPaths,
};
use crate::lint;
use crate::options::WasiExecModel;
@@ -2659,6 +2818,7 @@
NativeLibKind,
SanitizerSet,
CFGuard,
+ CFProtection,
TargetTriple,
Edition,
LinkerPluginLto,
@@ -2672,6 +2832,7 @@
OutputType,
RealFileName,
LocationDetail,
+ BranchProtection,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 3571901..9200be3 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -1,13 +1,11 @@
//! A module for searching for libraries
-pub use self::FileMatch::*;
-
use std::env;
use std::fs;
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
-use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
+use crate::search_paths::{PathKind, SearchPath};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use tracing::debug;
@@ -43,36 +41,6 @@
self.get_lib_path().join("self-contained")
}
- pub fn search<F>(&self, mut pick: F)
- where
- F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
- {
- for search_path in self.search_paths() {
- debug!("searching {}", search_path.dir.display());
- fn is_rlib(spf: &SearchPathFile) -> bool {
- if let Some(f) = &spf.file_name_str { f.ends_with(".rlib") } else { false }
- }
- // Reading metadata out of rlibs is faster, and if we find both
- // an rlib and a dylib we only read one of the files of
- // metadata, so in the name of speed, bring all rlib files to
- // the front of the search list.
- let files1 = search_path.files.iter().filter(|spf| is_rlib(&spf));
- let files2 = search_path.files.iter().filter(|spf| !is_rlib(&spf));
- for spf in files1.chain(files2) {
- debug!("testing {}", spf.path.display());
- let maybe_picked = pick(spf, search_path.kind);
- match maybe_picked {
- FileMatches => {
- debug!("picked {}", spf.path.display());
- }
- FileDoesntMatch => {
- debug!("rejected {}", spf.path.display());
- }
- }
- }
- }
- }
-
pub fn new(
sysroot: &'a Path,
triple: &'a str,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 399b616..c7a6ac1 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -2,7 +2,9 @@
#![feature(derive_default_enum)]
#![feature(min_specialization)]
#![feature(once_cell)]
+#![feature(option_get_or_insert_default)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c8ae005..658b07c 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -109,17 +109,16 @@
}
pub fn instrument_coverage(&self) -> bool {
- self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
- != InstrumentCoverage::Off
+ self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) != InstrumentCoverage::Off
}
pub fn instrument_coverage_except_unused_generics(&self) -> bool {
- self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
== InstrumentCoverage::ExceptUnusedGenerics
}
pub fn instrument_coverage_except_unused_functions(&self) -> bool {
- self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
== InstrumentCoverage::ExceptUnusedFunctions
}
}
@@ -185,10 +184,6 @@
externs: Externs [UNTRACKED],
extern_dep_specs: ExternDepSpecs [UNTRACKED],
crate_name: Option<String> [TRACKED],
- /// An optional name to use as the crate for std during std injection,
- /// written `extern crate name as std`. Defaults to `std`. Used by
- /// out-of-tree drivers.
- alt_std_name: Option<String> [TRACKED],
/// Indicates how the compiler should treat unstable features.
unstable_features: UnstableFeatures [TRACKED],
@@ -381,10 +376,11 @@
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
- pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`";
+ pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
+ pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
@@ -417,6 +413,8 @@
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
pub const parse_stack_protector: &str =
"one of (`none` (default), `basic`, `strong`, or `all`)";
+ pub const parse_branch_protection: &str =
+ "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
}
mod parse {
@@ -641,6 +639,7 @@
"cfi" => SanitizerSet::CFI,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
+ "memtag" => SanitizerSet::MEMTAG,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
_ => return false,
@@ -698,6 +697,25 @@
true
}
+ crate fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() { CFProtection::Full } else { CFProtection::None };
+ return true;
+ }
+ }
+
+ *slot = match v {
+ None | Some("none") => CFProtection::None,
+ Some("branch") => CFProtection::Branch,
+ Some("return") => CFProtection::Return,
+ Some("full") => CFProtection::Full,
+ Some(_) => return false,
+ };
+ true
+ }
+
crate fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
match v.and_then(LinkerFlavor::from_str) {
Some(lf) => *slot = Some(lf),
@@ -965,6 +983,33 @@
}
true
}
+
+ crate fn parse_branch_protection(slot: &mut Option<BranchProtection>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ let slot = slot.get_or_insert_default();
+ for opt in s.split(',') {
+ match opt {
+ "bti" => slot.bti = true,
+ "pac-ret" if slot.pac_ret.is_none() => {
+ slot.pac_ret = Some(PacRet { leaf: false, key: PAuthKey::A })
+ }
+ "leaf" => match slot.pac_ret.as_mut() {
+ Some(pac) => pac.leaf = true,
+ _ => return false,
+ },
+ "b-key" => match slot.pac_ret.as_mut() {
+ Some(pac) => pac.key = PAuthKey::B,
+ _ => return false,
+ },
+ _ => return false,
+ };
+ }
+ }
+ _ => return false,
+ }
+ true
+ }
}
options! {
@@ -1003,6 +1048,14 @@
"enable incremental compilation"),
inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
"set the threshold for inlining a function"),
+ instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
+ "instrument the generated code to support LLVM source-based code coverage \
+ reports (note, the compiler build config must include `profiler = true`); \
+ implies `-C symbol-mangling-version=v0`. Optional values are:
+ `=all` (implicit value)
+ `=except-unused-generics`
+ `=except-unused-functions`
+ `=off` (default)"),
link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to append to the linker invocation (can be used several times)"),
link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
@@ -1109,6 +1162,10 @@
(default: no)"),
borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED],
"select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"),
+ branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
+ "set options for branch target identification and pointer authentication on AArch64"),
+ cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
+ "instrument control-flow architecture protection"),
cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
"the codegen unit partitioning strategy to use"),
chalk: bool = (false, parse_bool, [TRACKED],
@@ -1131,9 +1188,13 @@
dep_tasks: bool = (false, parse_bool, [UNTRACKED],
"print tasks that execute and the color their dep node gets (requires debug build) \
(default: no)"),
+ dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+ "import library generation tool (windows-gnu only)"),
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
"emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
(default: no)"),
+ drop_tracking: bool = (false, parse_bool, [TRACKED],
+ "enables drop tracking in generators (default: no)"),
dual_proc_macros: bool = (false, parse_bool, [TRACKED],
"load proc macros for both target and host, but only link to the target (default: no)"),
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
@@ -1307,8 +1368,6 @@
See #77382 and #74551."),
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
"make rustc print the total optimization fuel used by a crate"),
- print_link_args: bool = (false, parse_bool, [UNTRACKED],
- "print the arguments passed to the linker (default: no)"),
print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
"print the LLVM optimization passes being run (default: no)"),
print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
@@ -1330,8 +1389,6 @@
"use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
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],
- "print some statistics about the query system (default: no)"),
randomize_layout: bool = (false, parse_bool, [TRACKED],
"randomize the layout of types (default: no)"),
layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index d5b5203..7113f9b 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -1,6 +1,7 @@
//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
//! It also serves as an input to the parser itself.
+use crate::config::CheckCfg;
use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -18,6 +19,7 @@
/// The set of keys (and, optionally, values) that define the compilation
/// environment of the crate, used to drive conditional compilation.
pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;
+pub type CrateCheckConfig = CheckCfg<Symbol>;
/// Collected spans during parsing for places where a certain feature was
/// used and should be feature gated accordingly in `check_crate`.
@@ -117,6 +119,7 @@
pub span_diagnostic: Handler,
pub unstable_features: UnstableFeatures,
pub config: CrateConfig,
+ pub check_config: CrateCheckConfig,
pub edition: Edition,
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
/// Places where raw identifiers were used. This is used to avoid complaining about idents
@@ -162,6 +165,7 @@
span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(None),
config: FxHashSet::default(),
+ check_config: CrateCheckConfig::default(),
edition: ExpnId::root().expn_data().edition,
missing_fragment_specifiers: Default::default(),
raw_identifier_spans: Lock::new(Vec::new()),
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index acb6c73..b6bde28 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -15,22 +15,15 @@
/// doable, but very slow, because it involves calls to `file_name` and
/// `extension` that are themselves slow.
///
-/// This type augments the `PathBuf` with an `Option<String>` containing the
+/// This type augments the `PathBuf` with an `String` containing the
/// `PathBuf`'s filename. The prefix and suffix checking is much faster on the
-/// `Option<String>` than the `PathBuf`. (It's an `Option` because
-/// `Path::file_name` can fail; if that happens then all subsequent checking
-/// will also fail, which is fine.)
+/// `String` than the `PathBuf`. (The filename must be valid UTF-8. If it's
+/// not, the entry should be skipped, because all Rust output files are valid
+/// UTF-8, and so a non-UTF-8 filename couldn't be one we're looking for.)
#[derive(Clone, Debug)]
pub struct SearchPathFile {
pub path: PathBuf,
- pub file_name_str: Option<String>,
-}
-
-impl SearchPathFile {
- fn new(path: PathBuf) -> SearchPathFile {
- let file_name_str = path.file_name().and_then(|f| f.to_str()).map(|s| s.to_string());
- SearchPathFile { path, file_name_str }
- }
+ pub file_name_str: String,
}
#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
@@ -85,7 +78,14 @@
// Get the files within the directory.
let files = match std::fs::read_dir(&dir) {
Ok(files) => files
- .filter_map(|e| e.ok().map(|e| SearchPathFile::new(e.path())))
+ .filter_map(|e| {
+ e.ok().and_then(|e| {
+ e.file_name().to_str().map(|s| SearchPathFile {
+ path: e.path(),
+ file_name_str: s.to_string(),
+ })
+ })
+ })
.collect::<Vec<_>>(),
Err(..) => vec![],
};
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 730e79a..9bcdd7f 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -476,10 +476,6 @@
&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>(
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 781fb8c..7227b19 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -16,6 +16,6 @@
unicode-width = "0.1.4"
cfg-if = "0.1.2"
tracing = "0.1"
-sha1 = { package = "sha-1", version = "0.9" }
-sha2 = "0.9"
-md5 = { package = "md-5", version = "0.9" }
+sha1 = { package = "sha-1", version = "0.10.0" }
+sha2 = "0.10.1"
+md5 = { package = "md-5", version = "0.10.0" }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 24d2a8a..147c1f9 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -47,8 +47,8 @@
}
impl<D: Decoder> Decodable<D> for CrateNum {
- default fn decode(d: &mut D) -> Result<CrateNum, D::Error> {
- Ok(CrateNum::from_u32(d.read_u32()?))
+ default fn decode(d: &mut D) -> CrateNum {
+ CrateNum::from_u32(d.read_u32())
}
}
@@ -176,9 +176,9 @@
// and no -Cmetadata, symbols from the same crate compiled with different versions of
// rustc are named the same.
//
- // RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER is used to inject rustc version information
+ // RUSTC_FORCE_RUSTC_VERSION is used to inject rustc version information
// during testing.
- if let Some(val) = std::env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+ if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
hasher.write(val.to_string_lossy().into_owned().as_bytes())
} else {
hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes());
@@ -209,7 +209,7 @@
}
impl<D: Decoder> Decodable<D> for DefIndex {
- default fn decode(_: &mut D) -> Result<DefIndex, D::Error> {
+ default fn decode(_: &mut D) -> DefIndex {
panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>());
}
}
@@ -221,10 +221,17 @@
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
// On below-64 bit systems we can simply use the derived `Hash` impl
#[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
-// Note that the order is essential here, see below why
+#[repr(C)]
+// We guarantee field order. Note that the order is essential here, see below why.
pub struct DefId {
+ // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
+ // the lower bits no matter the endianness. This allows the compiler to turn that `Hash` impl
+ // into a direct call to 'u64::hash(_)`.
+ #[cfg(not(all(target_pointer_width = "64", target_endian = "big")))]
pub index: DefIndex,
pub krate: CrateNum,
+ #[cfg(all(target_pointer_width = "64", target_endian = "big"))]
+ pub index: DefIndex,
}
// On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This
@@ -291,12 +298,10 @@
}
impl<D: Decoder> Decodable<D> for DefId {
- default fn decode(d: &mut D) -> Result<DefId, D::Error> {
- d.read_struct(|d| {
- Ok(DefId {
- krate: d.read_struct_field("krate", Decodable::decode)?,
- index: d.read_struct_field("index", Decodable::decode)?,
- })
+ default fn decode(d: &mut D) -> DefId {
+ d.read_struct(|d| DefId {
+ krate: d.read_struct_field("krate", Decodable::decode),
+ index: d.read_struct_field("index", Decodable::decode),
})
}
}
@@ -371,8 +376,8 @@
}
impl<D: Decoder> Decodable<D> for LocalDefId {
- fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
- DefId::decode(d).map(|d| d.expect_local())
+ fn decode(d: &mut D) -> LocalDefId {
+ DefId::decode(d).expect_local()
}
}
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 315b706..8265eb2 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -32,6 +32,7 @@
use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_data_structures::unhash::UnhashMap;
@@ -88,6 +89,33 @@
}
}
+/// Assert that the provided `HashStableContext` is configured with the 'default'
+/// `HashingControls`. We should always have bailed out before getting to here
+/// with a non-default mode. With this check in place, we can avoid the need
+/// to maintain separate versions of `ExpnData` hashes for each permutation
+/// of `HashingControls` settings.
+fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
+ match ctx.hashing_controls() {
+ // Ideally, we would also check that `node_id_hashing_mode` was always
+ // `NodeIdHashingMode::HashDefPath`. However, we currently end up hashing
+ // `Span`s in this mode, and there's not an easy way to change that.
+ // All of the span-related data that we hash is pretty self-contained
+ // (in particular, we don't hash any `HirId`s), so this shouldn't result
+ // in any caching problems.
+ // FIXME: Enforce that we don't end up transitively hashing any `HirId`s,
+ // or ensure that this method is always invoked with the same
+ // `NodeIdHashingMode`
+ //
+ // Note that we require that `hash_spans` be set according to the global
+ // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
+ // which will cause us to require that this method always be called with `Span` hashing
+ // enabled.
+ HashingControls { hash_spans, node_id_hashing_mode: _ }
+ if hash_spans == !ctx.debug_opts_incremental_ignore_spans() => {}
+ other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
+ }
+}
+
/// A unique hash value associated to an expansion.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
pub struct ExpnHash(Fingerprint);
@@ -144,10 +172,12 @@
/// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0);
+ #[inline]
pub fn from_raw(idx: ExpnIndex) -> LocalExpnId {
LocalExpnId::from_u32(idx.as_u32())
}
+ #[inline]
pub fn as_raw(self) -> ExpnIndex {
ExpnIndex::from_u32(self.as_u32())
}
@@ -1286,19 +1316,16 @@
// to track which `SyntaxContext`s we have already decoded.
// The provided closure will be invoked to deserialize a `SyntaxContextData`
// if we haven't already seen the id of the `SyntaxContext` we are deserializing.
-pub fn decode_syntax_context<
- D: Decoder,
- F: FnOnce(&mut D, u32) -> Result<SyntaxContextData, D::Error>,
->(
+pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>(
d: &mut D,
context: &HygieneDecodeContext,
decode_data: F,
-) -> Result<SyntaxContext, D::Error> {
- let raw_id: u32 = Decodable::decode(d)?;
+) -> SyntaxContext {
+ let raw_id: u32 = Decodable::decode(d);
if raw_id == 0 {
debug!("decode_syntax_context: deserialized root");
// The root is special
- return Ok(SyntaxContext::root());
+ return SyntaxContext::root();
}
let outer_ctxts = &context.remapped_ctxts;
@@ -1306,7 +1333,7 @@
// Ensure that the lock() temporary is dropped early
{
if let Some(ctxt) = outer_ctxts.lock().get(raw_id as usize).copied().flatten() {
- return Ok(ctxt);
+ return ctxt;
}
}
@@ -1336,7 +1363,7 @@
// Don't try to decode data while holding the lock, since we need to
// be able to recursively decode a SyntaxContext
- let mut ctxt_data = decode_data(d, raw_id)?;
+ let mut ctxt_data = decode_data(d, raw_id);
// Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`
// We don't care what the encoding crate set this to - we want to resolve it
// from the perspective of the current compilation session
@@ -1352,7 +1379,7 @@
assert_eq!(dummy.dollar_crate_name, kw::Empty);
});
- Ok(new_ctxt)
+ new_ctxt
}
fn for_all_ctxts_in<E, F: FnMut(u32, SyntaxContext, &SyntaxContextData) -> Result<(), E>>(
@@ -1394,13 +1421,13 @@
}
impl<D: Decoder> Decodable<D> for LocalExpnId {
- fn decode(d: &mut D) -> Result<Self, D::Error> {
- ExpnId::decode(d).map(ExpnId::expect_local)
+ fn decode(d: &mut D) -> Self {
+ ExpnId::expect_local(ExpnId::decode(d))
}
}
impl<D: Decoder> Decodable<D> for ExpnId {
- default fn decode(_: &mut D) -> Result<Self, D::Error> {
+ default fn decode(_: &mut D) -> Self {
panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>());
}
}
@@ -1423,7 +1450,7 @@
}
impl<D: Decoder> Decodable<D> for SyntaxContext {
- default fn decode(_: &mut D) -> Result<Self, D::Error> {
+ default fn decode(_: &mut D) -> Self {
panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>());
}
}
@@ -1444,6 +1471,7 @@
"Already set disambiguator for ExpnData: {:?}",
expn_data
);
+ assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
let mut expn_hash = expn_data.hash_expn(&mut ctx);
let disambiguator = HygieneData::with(|data| {
@@ -1493,6 +1521,7 @@
impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ assert_default_hashing_controls(ctx, "ExpnId");
let hash = if *self == ExpnId::root() {
// Avoid fetching TLS storage for a trivial often-used value.
Fingerprint::ZERO
diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs
index aed699e..93cf965 100644
--- a/compiler/rustc_span/src/lev_distance.rs
+++ b/compiler/rustc_span/src/lev_distance.rs
@@ -11,16 +11,21 @@
mod tests;
/// Finds the Levenshtein distance between two strings.
-pub fn lev_distance(a: &str, b: &str) -> usize {
- // cases which don't require further computation
- if a.is_empty() {
- return b.chars().count();
- } else if b.is_empty() {
- return a.chars().count();
+///
+/// Returns None if the distance exceeds the limit.
+pub fn lev_distance(a: &str, b: &str, limit: usize) -> Option<usize> {
+ let n = a.chars().count();
+ let m = b.chars().count();
+ let min_dist = if n < m { m - n } else { n - m };
+
+ if min_dist > limit {
+ return None;
+ }
+ if n == 0 || m == 0 {
+ return (min_dist <= limit).then_some(min_dist);
}
- let mut dcol: Vec<_> = (0..=b.len()).collect();
- let mut t_last = 0;
+ let mut dcol: Vec<_> = (0..=m).collect();
for (i, sc) in a.chars().enumerate() {
let mut current = i;
@@ -35,10 +40,10 @@
dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
}
current = next;
- t_last = j;
}
}
- dcol[t_last + 1]
+
+ (dcol[m] <= limit).then_some(dcol[m])
}
/// Finds the best match for a given word in the given iterator.
@@ -51,39 +56,38 @@
/// on an edge case with a lower(upper)case letters mismatch.
#[cold]
pub fn find_best_match_for_name(
- name_vec: &[Symbol],
+ candidates: &[Symbol],
lookup: Symbol,
dist: Option<usize>,
) -> Option<Symbol> {
let lookup = lookup.as_str();
- let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
+ let lookup_uppercase = lookup.to_uppercase();
// Priority of matches:
// 1. Exact case insensitive match
// 2. Levenshtein distance match
// 3. Sorted word match
- if let Some(case_insensitive_match) =
- name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase())
- {
- return Some(*case_insensitive_match);
+ if let Some(c) = candidates.iter().find(|c| c.as_str().to_uppercase() == lookup_uppercase) {
+ return Some(*c);
}
- let levenshtein_match = name_vec
- .iter()
- .filter_map(|&name| {
- let dist = lev_distance(lookup, name.as_str());
- if dist <= max_dist { Some((name, dist)) } else { None }
- })
- // Here we are collecting the next structure:
- // (levenshtein_match, levenshtein_distance)
- .fold(None, |result, (candidate, dist)| match result {
- None => Some((candidate, dist)),
- Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
- });
- if levenshtein_match.is_some() {
- levenshtein_match.map(|(candidate, _)| candidate)
- } else {
- find_match_by_sorted_words(name_vec, lookup)
+
+ let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
+ let mut best = None;
+ for c in candidates {
+ match lev_distance(lookup, c.as_str(), dist) {
+ Some(0) => return Some(*c),
+ Some(d) => {
+ dist = d - 1;
+ best = Some(*c);
+ }
+ None => {}
+ }
}
+ if best.is_some() {
+ return best;
+ }
+
+ find_match_by_sorted_words(candidates, lookup)
}
fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Symbol> {
diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs
index b32f8d3..4e34219 100644
--- a/compiler/rustc_span/src/lev_distance/tests.rs
+++ b/compiler/rustc_span/src/lev_distance/tests.rs
@@ -5,18 +5,26 @@
use std::char::{from_u32, MAX};
// Test bytelength agnosticity
for c in (0..MAX as u32).filter_map(from_u32).map(|i| i.to_string()) {
- assert_eq!(lev_distance(&c[..], &c[..]), 0);
+ assert_eq!(lev_distance(&c[..], &c[..], usize::MAX), Some(0));
}
let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
let c = "Mary häd ä little lämb\n\nLittle lämb\n";
- assert_eq!(lev_distance(a, b), 1);
- assert_eq!(lev_distance(b, a), 1);
- assert_eq!(lev_distance(a, c), 2);
- assert_eq!(lev_distance(c, a), 2);
- assert_eq!(lev_distance(b, c), 1);
- assert_eq!(lev_distance(c, b), 1);
+ assert_eq!(lev_distance(a, b, usize::MAX), Some(1));
+ assert_eq!(lev_distance(b, a, usize::MAX), Some(1));
+ assert_eq!(lev_distance(a, c, usize::MAX), Some(2));
+ assert_eq!(lev_distance(c, a, usize::MAX), Some(2));
+ assert_eq!(lev_distance(b, c, usize::MAX), Some(1));
+ assert_eq!(lev_distance(c, b, usize::MAX), Some(1));
+}
+
+#[test]
+fn test_lev_distance_limit() {
+ assert_eq!(lev_distance("abc", "abcd", 1), Some(1));
+ assert_eq!(lev_distance("abc", "abcd", 0), None);
+ assert_eq!(lev_distance("abc", "xyz", 3), Some(3));
+ assert_eq!(lev_distance("abc", "xyz", 2), None);
}
#[test]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 3bbf2a0..dea2fbf 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -15,11 +15,13 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(if_let_guard)]
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
@@ -42,6 +44,7 @@
use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
+use rustc_data_structures::stable_hasher::HashingControls;
pub mod def_id;
use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
pub mod lev_distance;
@@ -65,8 +68,8 @@
use std::path::{Path, PathBuf};
use std::str::FromStr;
+use md5::Digest;
use md5::Md5;
-use sha1::Digest;
use sha1::Sha1;
use sha2::Sha256;
@@ -610,7 +613,7 @@
#[inline]
/// Returns `true` if `hi == lo`.
- pub fn is_empty(&self) -> bool {
+ pub fn is_empty(self) -> bool {
let span = self.data_untracked();
span.hi == span.lo
}
@@ -638,7 +641,7 @@
///
/// Use this instead of `==` when either span could be generated code,
/// and you only care that they point to the same bytes of source text.
- pub fn source_equal(&self, other: &Span) -> bool {
+ pub fn source_equal(self, other: Span) -> bool {
let span = self.data();
let other = other.data();
span.lo == other.lo && span.hi == other.hi
@@ -679,17 +682,17 @@
}
#[inline]
- pub fn rust_2015(&self) -> bool {
+ pub fn rust_2015(self) -> bool {
self.edition() == edition::Edition::Edition2015
}
#[inline]
- pub fn rust_2018(&self) -> bool {
+ pub fn rust_2018(self) -> bool {
self.edition() >= edition::Edition::Edition2018
}
#[inline]
- pub fn rust_2021(&self) -> bool {
+ pub fn rust_2021(self) -> bool {
self.edition() >= edition::Edition::Edition2021
}
@@ -710,7 +713,7 @@
/// Checks if a span is "internal" to a macro in which `#[unstable]`
/// items can be used (that is, a macro marked with
/// `#[allow_internal_unstable]`).
- pub fn allows_unstable(&self, feature: Symbol) -> bool {
+ pub fn allows_unstable(self, feature: Symbol) -> bool {
self.ctxt()
.outer_expn_data()
.allow_internal_unstable
@@ -718,7 +721,7 @@
}
/// Checks if this span arises from a compiler desugaring of kind `kind`.
- pub fn is_desugaring(&self, kind: DesugaringKind) -> bool {
+ pub fn is_desugaring(self, kind: DesugaringKind) -> bool {
match self.ctxt().outer_expn_data().kind {
ExpnKind::Desugaring(k) => k == kind,
_ => false,
@@ -727,7 +730,7 @@
/// Returns the compiler desugaring that created this span, or `None`
/// if this span is not from a desugaring.
- pub fn desugaring_kind(&self) -> Option<DesugaringKind> {
+ pub fn desugaring_kind(self) -> Option<DesugaringKind> {
match self.ctxt().outer_expn_data().kind {
ExpnKind::Desugaring(k) => Some(k),
_ => None,
@@ -737,7 +740,7 @@
/// Checks if a span is "internal" to a macro in which `unsafe`
/// can be used without triggering the `unsafe_code` lint.
// (that is, a macro marked with `#[allow_internal_unsafe]`).
- pub fn allows_unsafe(&self) -> bool {
+ pub fn allows_unsafe(self) -> bool {
self.ctxt().outer_expn_data().allow_internal_unsafe
}
@@ -750,7 +753,7 @@
return None;
}
- let is_recursive = expn_data.call_site.source_equal(&prev_span);
+ let is_recursive = expn_data.call_site.source_equal(prev_span);
prev_span = self;
self = expn_data.call_site;
@@ -864,13 +867,13 @@
/// Equivalent of `Span::call_site` from the proc macro API,
/// except that the location is taken from the `self` span.
- pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span {
+ pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
}
/// Equivalent of `Span::mixed_site` from the proc macro API,
/// except that the location is taken from the `self` span.
- pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span {
+ pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
}
@@ -974,12 +977,12 @@
}
}
impl<D: Decoder> Decodable<D> for Span {
- default fn decode(s: &mut D) -> Result<Span, D::Error> {
+ default fn decode(s: &mut D) -> Span {
s.read_struct(|d| {
- let lo = d.read_struct_field("lo", Decodable::decode)?;
- let hi = d.read_struct_field("hi", Decodable::decode)?;
+ let lo = d.read_struct_field("lo", Decodable::decode);
+ let hi = d.read_struct_field("hi", Decodable::decode);
- Ok(Span::new(lo, hi, SyntaxContext::root(), None))
+ Span::new(lo, hi, SyntaxContext::root(), None)
})
}
}
@@ -1010,37 +1013,25 @@
f()
}
-pub fn debug_with_source_map(
- span: Span,
- f: &mut fmt::Formatter<'_>,
- source_map: &SourceMap,
-) -> fmt::Result {
- write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(span), span.ctxt())
-}
-
-pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- with_session_globals(|session_globals| {
- if let Some(source_map) = &*session_globals.source_map.borrow() {
- debug_with_source_map(span, f, source_map)
- } else {
- f.debug_struct("Span")
- .field("lo", &span.lo())
- .field("hi", &span.hi())
- .field("ctxt", &span.ctxt())
- .finish()
- }
- })
-}
-
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- (*SPAN_DEBUG)(*self, f)
+ with_session_globals(|session_globals| {
+ if let Some(source_map) = &*session_globals.source_map.borrow() {
+ write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
+ } else {
+ f.debug_struct("Span")
+ .field("lo", &self.lo())
+ .field("hi", &self.hi())
+ .field("ctxt", &self.ctxt())
+ .finish()
+ }
+ })
}
}
impl fmt::Debug for SpanData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
+ fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
}
}
@@ -1447,30 +1438,30 @@
}
impl<D: Decoder> Decodable<D> for SourceFile {
- fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
+ fn decode(d: &mut D) -> SourceFile {
d.read_struct(|d| {
- let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?;
+ let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d));
let src_hash: SourceFileHash =
- d.read_struct_field("src_hash", |d| Decodable::decode(d))?;
- let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?;
- let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?;
+ d.read_struct_field("src_hash", |d| Decodable::decode(d));
+ let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d));
+ let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d));
let lines: Vec<BytePos> = d.read_struct_field("lines", |d| {
- let num_lines: u32 = Decodable::decode(d)?;
+ let num_lines: u32 = Decodable::decode(d);
let mut lines = Vec::with_capacity(num_lines as usize);
if num_lines > 0 {
// Read the number of bytes used per diff.
- let bytes_per_diff: u8 = Decodable::decode(d)?;
+ let bytes_per_diff: u8 = Decodable::decode(d);
// Read the first element.
- let mut line_start: BytePos = Decodable::decode(d)?;
+ let mut line_start: BytePos = Decodable::decode(d);
lines.push(line_start);
for _ in 1..num_lines {
let diff = match bytes_per_diff {
- 1 => d.read_u8()? as u32,
- 2 => d.read_u16()? as u32,
- 4 => d.read_u32()?,
+ 1 => d.read_u8() as u32,
+ 2 => d.read_u16() as u32,
+ 4 => d.read_u32(),
_ => unreachable!(),
};
@@ -1480,17 +1471,17 @@
}
}
- Ok(lines)
- })?;
+ lines
+ });
let multibyte_chars: Vec<MultiByteChar> =
- d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?;
+ d.read_struct_field("multibyte_chars", |d| Decodable::decode(d));
let non_narrow_chars: Vec<NonNarrowChar> =
- d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?;
- let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?;
+ d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d));
+ let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d));
let normalized_pos: Vec<NormalizedPos> =
- d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?;
- let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?;
- Ok(SourceFile {
+ d.read_struct_field("normalized_pos", |d| Decodable::decode(d));
+ let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d));
+ SourceFile {
name,
start_pos,
end_pos,
@@ -1505,7 +1496,7 @@
normalized_pos,
name_hash,
cnum,
- })
+ }
})
}
}
@@ -1948,8 +1939,8 @@
}
impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos {
- fn decode(d: &mut D) -> Result<BytePos, D::Error> {
- Ok(BytePos(d.read_u32()?))
+ fn decode(d: &mut D) -> BytePos {
+ BytePos(d.read_u32())
}
}
@@ -2000,8 +1991,6 @@
pub lines: Vec<LineInfo>,
}
-pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
- AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
// _____________________________________________________________________________
@@ -2057,11 +2046,15 @@
pub trait HashStableContext {
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
fn hash_spans(&self) -> bool;
+ /// Accesses `sess.opts.debugging_opts.incremental_ignore_spans` since
+ /// we don't have easy access to a `Session`
+ fn debug_opts_incremental_ignore_spans(&self) -> bool;
fn def_span(&self, def_id: LocalDefId) -> Span;
fn span_data_to_lines_and_cols(
&mut self,
span: &SpanData,
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
+ fn hashing_controls(&self) -> HashingControls;
}
impl<CTX> HashStable<CTX> for Span
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 7414d20..9517710 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -629,26 +629,41 @@
}
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
- /// whitespace. Returns the same span if no character could be found or if an error occurred
- /// while retrieving the code snippet.
- pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span {
+ /// whitespace. Returns None if the pattern could not be found or if an error occurred while
+ /// retrieving the code snippet.
+ pub fn span_extend_to_prev_str(
+ &self,
+ sp: Span,
+ pat: &str,
+ accept_newlines: bool,
+ include_whitespace: bool,
+ ) -> Option<Span> {
// assure that the pattern is delimited, to avoid the following
// fn my_fn()
// ^^^^ returned span without the check
// ---------- correct span
+ let prev_source = self.span_to_prev_source(sp).ok()?;
for ws in &[" ", "\t", "\n"] {
let pat = pat.to_owned() + ws;
- if let Ok(prev_source) = self.span_to_prev_source(sp) {
- let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start();
- if prev_source.is_empty() && sp.lo().0 != 0 {
- return sp.with_lo(BytePos(sp.lo().0 - 1));
- } else if accept_newlines || !prev_source.contains('\n') {
- return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
+ if let Some(pat_pos) = prev_source.rfind(&pat) {
+ let just_after_pat_pos = pat_pos + pat.len() - 1;
+ let just_after_pat_plus_ws = if include_whitespace {
+ just_after_pat_pos
+ + prev_source[just_after_pat_pos..]
+ .find(|c: char| !c.is_whitespace())
+ .unwrap_or(0)
+ } else {
+ just_after_pat_pos
+ };
+ let len = prev_source.len() - just_after_pat_plus_ws;
+ let prev_source = &prev_source[just_after_pat_plus_ws..];
+ if accept_newlines || !prev_source.trim_start().contains('\n') {
+ return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
}
}
}
- sp
+ None
}
/// Returns the source snippet as `String` after the given `Span`.
@@ -927,7 +942,7 @@
}
pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
- let prev_span = self.span_extend_to_prev_str(span, "fn", true);
+ let prev_span = self.span_extend_to_prev_str(span, "fn", true, true).unwrap_or(span);
if let Ok(snippet) = self.span_to_snippet(prev_span) {
debug!(
"generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
@@ -968,8 +983,7 @@
pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
// Try to extend the span to the previous "fn" keyword to retrieve the function
// signature.
- let sugg_span = self.span_extend_to_prev_str(span, "fn", false);
- if sugg_span != span {
+ if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) {
if let Ok(snippet) = self.span_to_snippet(sugg_span) {
// Consume the function name.
let mut offset = snippet
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index e9120b9..61e4074 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -61,6 +61,15 @@
/// using the callback `SPAN_TRACK` to access the query engine.
///
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
+// FIXME(@lcnr): Enable this attribute once the bootstrap
+// compiler knows of `rustc_pass_by_value`.
+//
+// Right now, this lint would only trigger when compiling the
+// stage 2 compiler, which is fairly annoying as there are
+// a lot of places using `&Span` right now. After the next bootstrap bump,
+// the lint will already trigger when using stage 1, which is a lot less annoying.
+//
+// #[cfg_attr(not(bootstrap), rustc_pass_by_value)]
pub struct Span {
base_or_index: u32,
len_or_tag: u16,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e008224..c746255 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -184,6 +184,7 @@
Formatter,
From,
FromIterator,
+ FromResidual,
Future,
FxHashMap,
FxHashSet,
@@ -208,6 +209,7 @@
LinkedList,
LintPass,
Mutex,
+ N,
None,
Ok,
Option,
@@ -271,7 +273,6 @@
__H,
__S,
__try_var,
- _args,
_d,
_e,
_task_context,
@@ -315,18 +316,22 @@
allow_internal_unsafe,
allow_internal_unstable,
allowed,
+ alu32,
always,
and,
and_then,
any,
+ append_const_msg,
arbitrary_enum_discriminant,
arbitrary_self_types,
+ args,
arith_offset,
arm,
arm_target_feature,
array,
arrays,
as_ptr,
+ as_ref,
as_str,
asm,
asm_const,
@@ -334,11 +339,14 @@
asm_sym,
asm_unwind,
assert,
+ assert_eq_macro,
assert_inhabited,
assert_macro,
+ assert_ne_macro,
assert_receiver_is_total_eq,
assert_uninit_valid,
assert_zero_valid,
+ associated_const_equality,
associated_consts,
associated_type_bounds,
associated_type_defaults,
@@ -357,7 +365,10 @@
augmented_assignments,
auto_traits,
automatically_derived,
+ avx,
avx512_target_feature,
+ avx512bw,
+ avx512f,
await_macro,
bang,
begin_panic,
@@ -405,11 +416,14 @@
cfg_doctest,
cfg_eval,
cfg_hide,
+ cfg_macro,
cfg_panic,
cfg_sanitize,
cfg_target_abi,
cfg_target_feature,
cfg_target_has_atomic,
+ cfg_target_has_atomic_equal_alignment,
+ cfg_target_has_atomic_load_store,
cfg_target_thread_local,
cfg_target_vendor,
cfg_version,
@@ -432,21 +446,26 @@
coerce_unsized,
cold,
column,
+ column_macro,
compare_and_swap,
compare_exchange,
compare_exchange_weak,
compile_error,
+ compile_error_macro,
+ compiler,
compiler_builtins,
compiler_fence,
concat,
concat_bytes,
concat_idents,
+ concat_macro,
conservative_impl_trait,
console,
const_allocate,
const_async_blocks,
const_compare_raw_pointers,
const_constructor,
+ const_deallocate,
const_eval_limit,
const_eval_select,
const_eval_select_ct,
@@ -520,10 +539,13 @@
custom_inner_attributes,
custom_test_frameworks,
d,
+ dbg_macro,
dead_code,
dealloc,
debug,
+ debug_assert_eq_macro,
debug_assert_macro,
+ debug_assert_ne_macro,
debug_assertions,
debug_struct,
debug_trait_builder,
@@ -567,6 +589,7 @@
doc_spotlight,
doctest,
document_private_items,
+ dotdot: "..",
dotdot_in_tuple_patterns,
dotdoteq_in_patterns,
dreg,
@@ -580,6 +603,7 @@
dylib,
dyn_metadata,
dyn_trait,
+ e,
edition_macro_pats,
edition_panic,
eh_catch_typeinfo,
@@ -592,7 +616,11 @@
enable,
enclosing_scope,
encode,
+ end,
env,
+ env_macro,
+ eprint_macro,
+ eprintln_macro,
eq,
ermsb_target_feature,
exact_div,
@@ -640,9 +668,11 @@
field,
field_init_shorthand,
file,
+ file_macro,
fill,
finish,
flags,
+ float,
float_to_int_unchecked,
floorf32,
floorf64,
@@ -662,8 +692,10 @@
format,
format_args,
format_args_capture,
+ format_args_macro,
format_args_nl,
format_macro,
+ fp,
freeze,
freg,
frem_fast,
@@ -728,7 +760,10 @@
in_band_lifetimes,
include,
include_bytes,
+ include_bytes_macro,
+ include_macro,
include_str,
+ include_str_macro,
inclusive_range_syntax,
index,
index_mut,
@@ -741,6 +776,8 @@
inline_const_pat,
inout,
instruction_set,
+ integer_: "integer",
+ integral,
intel,
into_future,
into_iter,
@@ -776,6 +813,7 @@
lifetime,
likely,
line,
+ line_macro,
link,
link_args,
link_cfg,
@@ -784,9 +822,9 @@
link_ordinal,
link_section,
linkage,
+ linker,
lint_reasons,
literal,
- llvm_asm,
load,
loaded_from_disk,
local,
@@ -819,6 +857,7 @@
masked,
match_beginning_vert,
match_default_bindings,
+ matches_macro,
maxnumf32,
maxnumf64,
may_dangle,
@@ -837,6 +876,7 @@
mem_zeroed,
member_constraints,
memory,
+ memtag,
message,
meta,
metadata_type,
@@ -855,6 +895,7 @@
modifiers,
module,
module_path,
+ module_path_macro,
more_qualified_paths,
more_struct_aliases,
movbe_target_feature,
@@ -870,6 +911,7 @@
naked,
naked_functions,
name,
+ names,
native_link_modifiers,
native_link_modifiers_as_needed,
native_link_modifiers_bundle,
@@ -884,6 +926,7 @@
neg,
negate_unsigned,
negative_impls,
+ neon,
never,
never_type,
never_type_fallback,
@@ -938,6 +981,7 @@
optin_builtin_traits,
option,
option_env,
+ option_env_macro,
options,
or,
or_patterns,
@@ -958,6 +1002,7 @@
panic_implementation,
panic_info,
panic_location,
+ panic_no_unwind,
panic_runtime,
panic_str,
panic_unwind,
@@ -1001,6 +1046,8 @@
prelude_import,
preserves_flags,
primitive,
+ print_macro,
+ println_macro,
proc_dash_macro: "proc-macro",
proc_macro,
proc_macro_attribute,
@@ -1075,6 +1122,7 @@
repr_packed,
repr_simd,
repr_transparent,
+ reserved_r9: "reserved-r9",
residual,
result,
rhs,
@@ -1133,9 +1181,11 @@
rustc_layout_scalar_valid_range_end,
rustc_layout_scalar_valid_range_start,
rustc_legacy_const_generics,
+ rustc_lint_query_instability,
rustc_macro_transparency,
rustc_main,
rustc_mir,
+ rustc_must_implement_one_of,
rustc_nonnull_optimization_guaranteed,
rustc_object_lifetime_default,
rustc_on_unimplemented,
@@ -1143,6 +1193,7 @@
rustc_paren_sugar,
rustc_partition_codegened,
rustc_partition_reused,
+ rustc_pass_by_value,
rustc_peek,
rustc_peek_definite_init,
rustc_peek_liveness,
@@ -1186,6 +1237,7 @@
simd,
simd_add,
simd_and,
+ simd_as,
simd_bitmask,
simd_cast,
simd_ceil,
@@ -1267,6 +1319,7 @@
sqrtf64,
sreg,
sreg_low16,
+ sse,
sse4a_target_feature,
stable,
staged_api,
@@ -1288,6 +1341,7 @@
str,
str_alloc,
stringify,
+ stringify_macro,
struct_field_attributes,
struct_inherit,
struct_variant,
@@ -1331,6 +1385,10 @@
then_with,
thread,
thread_local,
+ thread_local_macro,
+ thumb2,
+ thumb_mode: "thumb-mode",
+ todo_macro,
tool_attributes,
tool_lints,
trace_macros,
@@ -1381,6 +1439,7 @@
underscore_imports,
underscore_lifetimes,
uniform_paths,
+ unimplemented_macro,
unit,
universal_impl_trait,
unix,
@@ -1399,6 +1458,7 @@
unsafe_block_in_unsafe_fn,
unsafe_cell,
unsafe_no_drop_flag,
+ unsafe_pin_internals,
unsize,
unsized_fn_params,
unsized_locals,
@@ -1414,6 +1474,7 @@
use_extern_macros,
use_nested_groups,
used,
+ used_with_arg,
usize,
v1,
va_arg,
@@ -1422,10 +1483,13 @@
va_list,
va_start,
val,
+ values,
var,
variant_count,
vec,
+ vec_macro,
version,
+ vfp2,
vis,
visible_private_types,
volatile,
@@ -1444,12 +1508,15 @@
width,
windows,
windows_subsystem,
+ with_negative_coherence,
wrapping_add,
wrapping_mul,
wrapping_sub,
wreg,
write_bytes,
+ write_macro,
write_str,
+ writeln_macro,
x87_reg,
xer,
xmm_reg,
@@ -1711,8 +1778,8 @@
impl<D: Decoder> Decodable<D> for Symbol {
#[inline]
- fn decode(d: &mut D) -> Result<Symbol, D::Error> {
- Ok(Symbol::intern(&d.read_str()?))
+ fn decode(d: &mut D) -> Symbol {
+ Symbol::intern(&d.read_str())
}
}
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index eebf618..cec1d4b 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -107,35 +107,35 @@
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 `definitely_needs_subst` may not hold, but this item-type
+ // assertions about `needs_subst` may not hold, but this item-type
// ought to be the same for every reference anyway.
- assert!(!item_type.has_erasable_regions(tcx));
+ assert!(!item_type.has_erasable_regions());
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
item_type.hash_stable(hcx, &mut hasher);
+
+ // If this is a function, we hash the signature as well.
+ // This is not *strictly* needed, but it may help in some
+ // situations, see the `run-make/a-b-a-linker-guard` test.
+ if let ty::FnDef(..) = item_type.kind() {
+ item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
+ }
+
+ // also include any type parameters (for generic items)
+ substs.hash_stable(hcx, &mut hasher);
+
+ if let Some(instantiating_crate) = instantiating_crate {
+ tcx.def_path_hash(instantiating_crate.as_def_id())
+ .stable_crate_id()
+ .hash_stable(hcx, &mut hasher);
+ }
+
+ // We want to avoid accidental collision between different types of instances.
+ // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+ // instances without this.
+ discriminant(&instance.def).hash_stable(hcx, &mut hasher);
});
});
-
- // If this is a function, we hash the signature as well.
- // This is not *strictly* needed, but it may help in some
- // situations, see the `run-make/a-b-a-linker-guard` test.
- if let ty::FnDef(..) = item_type.kind() {
- item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher);
- }
-
- // also include any type parameters (for generic items)
- substs.hash_stable(&mut hcx, &mut hasher);
-
- if let Some(instantiating_crate) = instantiating_crate {
- tcx.def_path_hash(instantiating_crate.as_def_id())
- .stable_crate_id()
- .hash_stable(&mut hcx, &mut hasher);
- }
-
- // We want to avoid accidental collision between different types of instances.
- // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
- // instances without this.
- discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
});
// 64 bits should be enough to avoid collisions.
@@ -243,10 +243,10 @@
Ok(self)
}
- fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(self, ct: 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() {
+ if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val() {
+ if ct.ty().is_integral() {
return self.pretty_print_const(ct, true);
}
}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 1f38240..f4d1f41 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)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
@@ -173,8 +174,7 @@
let stable_crate_id = tcx.sess.local_stable_crate_id();
return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- matches!(tcx.hir().get(hir_id), Node::ForeignItem(_))
+ matches!(tcx.hir().get_by_def_id(def_id), Node::ForeignItem(_))
} else {
tcx.is_foreign_item(def_id)
};
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index c2519ad..c21c3d3 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -116,7 +116,7 @@
/// 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>,
+ consts: FxHashMap<ty::Const<'tcx>, usize>,
}
impl<'tcx> SymbolMangler<'tcx> {
@@ -317,9 +317,7 @@
// 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.definitely_has_param_types_or_consts(self.tcx))
- {
+ if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
self = self.path_generic_args(
|this| {
this.path_append_ns(
@@ -422,7 +420,7 @@
hir::Mutability::Not => "R",
hir::Mutability::Mut => "Q",
});
- if *r != ty::ReErased {
+ if !r.is_erased() {
self = r.print(self)?;
}
self = ty.print(self)?;
@@ -558,10 +556,13 @@
cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?;
}
ty::ExistentialPredicate::Projection(projection) => {
- let name = cx.tcx.associated_item(projection.item_def_id).ident;
+ let name = cx.tcx.associated_item(projection.item_def_id).name;
cx.push("p");
cx.push_ident(name.as_str());
- cx = projection.ty.print(cx)?;
+ cx = match projection.term {
+ ty::Term::Ty(ty) => ty.print(cx),
+ ty::Term::Const(c) => c.print(cx),
+ }?;
}
ty::ExistentialPredicate::AutoTrait(def_id) => {
cx = cx.print_def_path(*def_id, &[])?;
@@ -575,10 +576,10 @@
Ok(self)
}
- fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
// 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 {
+ match ct.val() {
ty::ConstKind::Value(_) => {}
// Placeholders (should be demangled as `_`).
@@ -602,14 +603,14 @@
}
let start = self.out.len();
- match ct.ty.kind() {
+ match ct.ty().kind() {
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
- self = ct.ty.print(self)?;
+ self = ct.ty().print(self)?;
- let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty);
+ 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() {
+ 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 {
@@ -626,7 +627,7 @@
// 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 {
+ 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
@@ -670,7 +671,7 @@
Ok(this)
};
- match *ct.ty.kind() {
+ match *ct.ty().kind() {
ty::Array(..) => {
self.push("A");
self = print_field_list(self)?;
@@ -720,7 +721,7 @@
}
_ => {
- bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
+ bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct);
}
}
@@ -771,9 +772,9 @@
disambiguated_data: &DisambiguatedDefPathData,
) -> Result<Self::Path, Self::Error> {
let ns = match disambiguated_data.data {
- // FIXME: It shouldn't be necessary to add anything for extern block segments,
- // but we add 't' for backward compatibility.
- DefPathData::ForeignMod => 't',
+ // Extern block segments can be skipped, names from extern blocks
+ // are effectively living in their parent modules.
+ DefPathData::ForeignMod => return print_prefix(self),
// Uppercase categories are more stable than lowercase ones.
DefPathData::TypeNs(_) => 't',
@@ -810,7 +811,7 @@
) -> Result<Self::Path, Self::Error> {
// Don't print any regions if they're all erased.
let print_regions = args.iter().any(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+ GenericArgKind::Lifetime(r) => !r.is_erased(),
_ => false,
});
let args = args.iter().cloned().filter(|arg| match arg.unpack() {
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 735b7e7..34324a5 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -1,6 +1,7 @@
use crate::abi::{self, Abi, Align, FieldsShape, Size};
use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::{self, HasTargetSpec};
+use rustc_span::Symbol;
use std::fmt;
mod aarch64;
@@ -73,6 +74,7 @@
// or not to actually emit the attribute. It can also be controlled
// with the `-Zmutable-noalias` debugging option.
const NoAliasMutRef = 1 << 6;
+ const NoUndef = 1 << 7;
}
}
}
@@ -494,7 +496,11 @@
// For non-immediate arguments the callee gets its own copy of
// the value on the stack, so there are no aliases. It's also
// program-invisible so can't possibly capture
- attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
+ attrs
+ .set(ArgAttribute::NoAlias)
+ .set(ArgAttribute::NoCapture)
+ .set(ArgAttribute::NonNull)
+ .set(ArgAttribute::NoUndef);
attrs.pointee_size = layout.size;
// FIXME(eddyb) We should be doing this, but at least on
// i686-pc-windows-msvc, it results in wrong stack offsets.
@@ -623,10 +629,10 @@
}
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
-#[derive(Clone, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum AdjustForForeignAbiError {
/// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
- Unsupported { arch: String, abi: spec::abi::Abi },
+ Unsupported { arch: Symbol, abi: spec::abi::Abi },
}
impl fmt::Display for AdjustForForeignAbiError {
@@ -658,22 +664,24 @@
match &cx.target_spec().arch[..] {
"x86" => {
- let flavor = if abi == spec::abi::Abi::Fastcall {
+ let flavor = if let spec::abi::Abi::Fastcall { .. } = abi {
x86::Flavor::Fastcall
} else {
x86::Flavor::General
};
x86::compute_abi_info(cx, self, flavor);
}
- "x86_64" => {
- if abi == spec::abi::Abi::SysV64 {
- x86_64::compute_abi_info(cx, self);
- } else if abi == spec::abi::Abi::Win64 || cx.target_spec().is_like_windows {
- x86_win64::compute_abi_info(self);
- } else {
- x86_64::compute_abi_info(cx, self);
+ "x86_64" => match abi {
+ spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
+ spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self),
+ _ => {
+ if cx.target_spec().is_like_windows {
+ x86_win64::compute_abi_info(self)
+ } else {
+ x86_64::compute_abi_info(cx, self)
+ }
}
- }
+ },
"aarch64" => aarch64::compute_abi_info(cx, self),
"amdgpu" => amdgpu::compute_abi_info(cx, self),
"arm" => arm::compute_abi_info(cx, self),
@@ -701,7 +709,10 @@
"asmjs" => wasm::compute_c_abi_info(cx, self),
"bpf" => bpf::compute_abi_info(self),
arch => {
- return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
+ return Err(AdjustForForeignAbiError::Unsupported {
+ arch: Symbol::intern(arch),
+ abi,
+ });
}
}
diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs
index 38aaee6..13706e8 100644
--- a/compiler/rustc_target/src/abi/call/s390x.rs
+++ b/compiler/rustc_target/src/abi/call/s390x.rs
@@ -2,7 +2,7 @@
// for a pre-z13 machine or using -mno-vx.
use crate::abi::call::{ArgAbi, FnAbi, Reg};
-use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout};
+use crate::abi::{HasDataLayout, TyAbiInterface};
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
@@ -12,24 +12,6 @@
}
}
-fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
-where
- Ty: TyAbiInterface<'a, C>,
- C: HasDataLayout,
-{
- match layout.abi {
- abi::Abi::Scalar(scalar) => scalar.value.is_float(),
- abi::Abi::Aggregate { .. } => {
- if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
- is_single_fp_element(cx, layout.field(cx, 0))
- } else {
- false
- }
- }
- _ => false,
- }
-}
-
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
Ty: TyAbiInterface<'a, C> + Copy,
@@ -40,7 +22,7 @@
return;
}
- if is_single_fp_element(cx, arg.layout) {
+ if arg.layout.is_single_fp_element(cx) {
match arg.layout.size.bytes() {
4 => arg.cast_to(Reg::f32()),
8 => arg.cast_to(Reg::f64()),
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index 28064d8..d169087 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, TyAbiInterface, TyAndLayout};
+use crate::abi::{HasDataLayout, TyAbiInterface};
use crate::spec::HasTargetSpec;
#[derive(PartialEq)]
@@ -8,24 +8,6 @@
Fastcall,
}
-fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
-where
- Ty: TyAbiInterface<'a, C> + Copy,
- C: HasDataLayout,
-{
- match layout.abi {
- abi::Abi::Scalar(scalar) => scalar.value.is_float(),
- abi::Abi::Aggregate { .. } => {
- if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
- is_single_fp_element(cx, layout.field(cx, 0))
- } else {
- false
- }
- }
- _ => false,
- }
-}
-
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
where
Ty: TyAbiInterface<'a, C> + Copy,
@@ -44,7 +26,7 @@
if t.abi_return_struct_as_int {
// According to Clang, everyone but MSVC returns single-element
// float aggregates directly in a floating-point register.
- if !t.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) {
+ if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {
match fn_abi.ret.layout.size.bytes() {
4 => fn_abi.ret.cast_to(Reg::f32()),
8 => fn_abi.ret.cast_to(Reg::f64()),
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index a57ad8f..7f1fd28 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1276,6 +1276,24 @@
{
Ty::ty_and_layout_pointee_info_at(self, cx, offset)
}
+
+ pub fn is_single_fp_element<C>(self, cx: &C) -> bool
+ where
+ Ty: TyAbiInterface<'a, C>,
+ C: HasDataLayout,
+ {
+ match self.abi {
+ Abi::Scalar(scalar) => scalar.value.is_float(),
+ Abi::Aggregate { .. } => {
+ if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
+ self.field(cx, 0).is_single_fp_element(cx)
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
}
impl<'a, Ty> TyAndLayout<'a, Ty> {
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 4bf909c..d184ad4 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,6 +1,8 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -58,11 +60,11 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
Self::vreg | Self::vreg_low16 => types! {
- "fp": I8, I16, I32, I64, F32, F64,
+ fp: I8, I16, I32, I64, F32, F64,
VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
},
@@ -73,8 +75,9 @@
pub fn reserved_x18(
_arch: InlineAsmArch,
- _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &FxHashSet<Symbol>,
target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
if target.os == "android"
|| target.is_like_fuchsia
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index b03594b..b2d5bb3 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -1,6 +1,8 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
use std::fmt;
def_reg_class! {
@@ -44,31 +46,34 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => types! { _: I8, I16, I32, F32; },
- Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; },
+ Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; },
Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
- "vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
+ vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
},
Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
- "neon": VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
+ neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
},
}
}
}
// This uses the same logic as useR7AsFramePointer in LLVM
-fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
- target.is_like_osx || (!target.is_like_windows && has_feature("thumb-mode"))
+fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) -> bool {
+ target.is_like_osx || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
}
fn frame_pointer_r11(
- _arch: InlineAsmArch,
- has_feature: impl FnMut(&str) -> bool,
+ arch: InlineAsmArch,
+ target_features: &FxHashSet<Symbol>,
target: &Target,
+ is_clobber: bool,
) -> Result<(), &'static str> {
- if !frame_pointer_is_r7(has_feature, target) {
+ not_thumb1(arch, target_features, target, is_clobber)?;
+
+ if !frame_pointer_is_r7(target_features, target) {
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
} else {
Ok(())
@@ -77,10 +82,11 @@
fn frame_pointer_r7(
_arch: InlineAsmArch,
- has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
- if frame_pointer_is_r7(has_feature, target) {
+ if frame_pointer_is_r7(target_features, target) {
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
} else {
Ok(())
@@ -89,11 +95,15 @@
fn not_thumb1(
_arch: InlineAsmArch,
- mut has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
_target: &Target,
+ is_clobber: bool,
) -> Result<(), &'static str> {
- if has_feature("thumb-mode") && !has_feature("thumb2") {
- Err("high registers (r8+) cannot be used in Thumb-1 code")
+ if !is_clobber
+ && target_features.contains(&sym::thumb_mode)
+ && !target_features.contains(&sym::thumb2)
+ {
+ Err("high registers (r8+) can only be used as clobbers in Thumb-1 code")
} else {
Ok(())
}
@@ -101,14 +111,15 @@
fn reserved_r9(
arch: InlineAsmArch,
- mut has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
target: &Target,
+ is_clobber: bool,
) -> Result<(), &'static str> {
- not_thumb1(arch, &mut has_feature, target)?;
+ not_thumb1(arch, target_features, target, is_clobber)?;
// We detect this using the reserved-r9 feature instead of using the target
// because the relocation model can be changed with compiler options.
- if has_feature("reserved-r9") {
+ if target_features.contains(&sym::reserved_r9) {
Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
} else {
Ok(())
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
index 82a4f8b..9a96a61 100644
--- a/compiler/rustc_target/src/asm/avr.rs
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -39,7 +40,7 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => types! { _: I8; },
Self::reg_upper => types! { _: I8; },
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
index ecb6bdc..b4d982f 100644
--- a/compiler/rustc_target/src/asm/bpf.rs
+++ b/compiler/rustc_target/src/asm/bpf.rs
@@ -1,5 +1,7 @@
use super::{InlineAsmArch, InlineAsmType, Target};
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
use std::fmt;
def_reg_class! {
@@ -33,20 +35,21 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => types! { _: I8, I16, I32, I64; },
- Self::wreg => types! { "alu32": I8, I16, I32; },
+ Self::wreg => types! { alu32: I8, I16, I32; },
}
}
}
fn only_alu32(
_arch: InlineAsmArch,
- mut has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
_target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
- if !has_feature("alu32") {
+ if !target_features.contains(&sym::alu32) {
Err("register can't be used without the `alu32` target feature")
} else {
Ok(())
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index 74afddb..d20270a 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -32,7 +33,7 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => types! { _: I8, I16, I32, F32; },
}
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index b19489a..b1e8737 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -33,7 +34,7 @@
pub fn supported_types(
self,
arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match (self, arch) {
(Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; },
(Self::reg, _) => types! { _: I8, I16, I32, F32; },
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 9128e54..fd95b03 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -81,14 +81,15 @@
pub fn parse(
_arch: super::InlineAsmArch,
- mut _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
_target: &crate::spec::Target,
+ _is_clobber: bool,
name: &str,
) -> Result<Self, &'static str> {
match name {
$(
$($alias)|* | $reg_name => {
- $($filter(_arch, &mut _has_feature, _target)?;)?
+ $($filter(_arch, _target_features, _target, _is_clobber)?;)?
Ok(Self::$reg)
}
)*
@@ -102,7 +103,7 @@
pub(super) fn fill_reg_map(
_arch: super::InlineAsmArch,
- mut _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
_target: &crate::spec::Target,
_map: &mut rustc_data_structures::fx::FxHashMap<
super::InlineAsmRegClass,
@@ -112,7 +113,7 @@
#[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass};
$(
- if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
+ if $($filter(_arch, _target_features, _target, false).is_ok() &&)? true {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
}
@@ -130,7 +131,7 @@
macro_rules! types {
(
$(_ : $($ty:expr),+;)?
- $($feature:literal: $($ty2:expr),+;)*
+ $($feature:ident: $($ty2:expr),+;)*
) => {
{
use super::InlineAsmType::*;
@@ -139,7 +140,7 @@
($ty, None),
)*)?
$($(
- ($ty2, Some($feature)),
+ ($ty2, Some(rustc_span::sym::$feature)),
)*)*
]
}
@@ -152,6 +153,7 @@
mod bpf;
mod hexagon;
mod mips;
+mod msp430;
mod nvptx;
mod powerpc;
mod riscv;
@@ -166,6 +168,7 @@
pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
+pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
@@ -194,6 +197,7 @@
Wasm64,
Bpf,
Avr,
+ Msp430,
}
impl FromStr for InlineAsmArch {
@@ -219,6 +223,7 @@
"wasm64" => Ok(Self::Wasm64),
"bpf" => Ok(Self::Bpf),
"avr" => Ok(Self::Avr),
+ "msp430" => Ok(Self::Msp430),
_ => Err(()),
}
}
@@ -250,6 +255,7 @@
Wasm(WasmInlineAsmReg),
Bpf(BpfInlineAsmReg),
Avr(AvrInlineAsmReg),
+ Msp430(Msp430InlineAsmReg),
// Placeholder for invalid register constraints for the current target
Err,
}
@@ -267,6 +273,7 @@
Self::S390x(r) => r.name(),
Self::Bpf(r) => r.name(),
Self::Avr(r) => r.name(),
+ Self::Msp430(r) => r.name(),
Self::Err => "<reg>",
}
}
@@ -283,14 +290,16 @@
Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
+ Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
Self::Err => InlineAsmRegClass::Err,
}
}
pub fn parse(
arch: InlineAsmArch,
- has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
target: &Target,
+ is_clobber: bool,
name: Symbol,
) -> Result<Self, &'static str> {
// FIXME: use direct symbol comparison for register names
@@ -298,44 +307,79 @@
let name = name.as_str();
Ok(match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
- Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, name)?)
+ Self::X86(X86InlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
}
InlineAsmArch::Arm => {
- Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, name)?)
+ Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
}
- InlineAsmArch::AArch64 => {
- Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, name)?)
- }
- InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
- Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, name)?)
- }
- InlineAsmArch::Nvptx64 => {
- Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, name)?)
- }
- InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
- Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, name)?)
- }
- InlineAsmArch::Hexagon => {
- Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, name)?)
- }
- 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)?)
- }
- InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
- Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, name)?)
- }
+ InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => Self::RiscV(
+ RiscVInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?,
+ ),
+ InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
+ InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => Self::PowerPC(
+ PowerPCInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?,
+ ),
+ InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
+ InlineAsmArch::Mips | InlineAsmArch::Mips64 => Self::Mips(MipsInlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
+ InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
+ InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => Self::Wasm(WasmInlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
InlineAsmArch::Bpf => {
- Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, name)?)
+ Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
}
InlineAsmArch::Avr => {
- Self::Avr(AvrInlineAsmReg::parse(arch, has_feature, target, name)?)
+ Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
}
+ InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(
+ arch,
+ target_features,
+ target,
+ is_clobber,
+ name,
+ )?),
})
}
@@ -358,6 +402,7 @@
Self::S390x(r) => r.emit(out, arch, modifier),
Self::Bpf(r) => r.emit(out, arch, modifier),
Self::Avr(r) => r.emit(out, arch, modifier),
+ Self::Msp430(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
@@ -374,6 +419,7 @@
Self::S390x(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
+ Self::Msp430(_) => cb(self),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
@@ -405,6 +451,7 @@
Wasm(WasmInlineAsmRegClass),
Bpf(BpfInlineAsmRegClass),
Avr(AvrInlineAsmRegClass),
+ Msp430(Msp430InlineAsmRegClass),
// Placeholder for invalid register constraints for the current target
Err,
}
@@ -425,12 +472,13 @@
Self::Wasm(r) => r.name(),
Self::Bpf(r) => r.name(),
Self::Avr(r) => r.name(),
+ Self::Msp430(r) => r.name(),
Self::Err => rustc_span::symbol::sym::reg,
}
}
/// Returns a suggested register class to use for this type. This is called
- /// after type checking via `supported_types` fails to give a better error
+ /// when `supported_types` fails to give a better error
/// message to the user.
pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
match self {
@@ -447,6 +495,7 @@
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
+ Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -476,6 +525,7 @@
Self::Wasm(r) => r.suggest_modifier(arch, ty),
Self::Bpf(r) => r.suggest_modifier(arch, ty),
Self::Avr(r) => r.suggest_modifier(arch, ty),
+ Self::Msp430(r) => r.suggest_modifier(arch, ty),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -501,6 +551,7 @@
Self::Wasm(r) => r.default_modifier(arch),
Self::Bpf(r) => r.default_modifier(arch),
Self::Avr(r) => r.default_modifier(arch),
+ Self::Msp430(r) => r.default_modifier(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -510,7 +561,7 @@
pub fn supported_types(
self,
arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::X86(r) => r.supported_types(arch),
Self::Arm(r) => r.supported_types(arch),
@@ -525,6 +576,7 @@
Self::Wasm(r) => r.supported_types(arch),
Self::Bpf(r) => r.supported_types(arch),
Self::Avr(r) => r.supported_types(arch),
+ Self::Msp430(r) => r.supported_types(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -554,6 +606,7 @@
}
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
+ InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?),
})
}
@@ -574,6 +627,7 @@
Self::Wasm(r) => r.valid_modifiers(arch),
Self::Bpf(r) => r.valid_modifiers(arch),
Self::Avr(r) => r.valid_modifiers(arch),
+ Self::Msp430(r) => r.valid_modifiers(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -695,73 +749,78 @@
// falling back to an external assembler.
pub fn allocatable_registers(
arch: InlineAsmArch,
- has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
target: &crate::spec::Target,
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
let mut map = x86::regclass_map();
- x86::fill_reg_map(arch, has_feature, target, &mut map);
+ x86::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Arm => {
let mut map = arm::regclass_map();
- arm::fill_reg_map(arch, has_feature, target, &mut map);
+ arm::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::AArch64 => {
let mut map = aarch64::regclass_map();
- aarch64::fill_reg_map(arch, has_feature, target, &mut map);
+ aarch64::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
let mut map = riscv::regclass_map();
- riscv::fill_reg_map(arch, has_feature, target, &mut map);
+ riscv::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Nvptx64 => {
let mut map = nvptx::regclass_map();
- nvptx::fill_reg_map(arch, has_feature, target, &mut map);
+ nvptx::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
let mut map = powerpc::regclass_map();
- powerpc::fill_reg_map(arch, has_feature, target, &mut map);
+ powerpc::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Hexagon => {
let mut map = hexagon::regclass_map();
- hexagon::fill_reg_map(arch, has_feature, target, &mut map);
+ hexagon::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
let mut map = mips::regclass_map();
- mips::fill_reg_map(arch, has_feature, target, &mut map);
+ mips::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::S390x => {
let mut map = s390x::regclass_map();
- s390x::fill_reg_map(arch, has_feature, target, &mut map);
+ s390x::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::SpirV => {
let mut map = spirv::regclass_map();
- spirv::fill_reg_map(arch, has_feature, target, &mut map);
+ spirv::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
let mut map = wasm::regclass_map();
- wasm::fill_reg_map(arch, has_feature, target, &mut map);
+ wasm::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Bpf => {
let mut map = bpf::regclass_map();
- bpf::fill_reg_map(arch, has_feature, target, &mut map);
+ bpf::fill_reg_map(arch, target_features, target, &mut map);
map
}
InlineAsmArch::Avr => {
let mut map = avr::regclass_map();
- avr::fill_reg_map(arch, has_feature, target, &mut map);
+ avr::fill_reg_map(arch, target_features, target, &mut map);
+ map
+ }
+ InlineAsmArch::Msp430 => {
+ let mut map = msp430::regclass_map();
+ msp430::fill_reg_map(arch, target_features, target, &mut map);
map
}
}
@@ -794,7 +853,7 @@
/// clobber ABIs for the target.
pub fn parse(
arch: InlineAsmArch,
- has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
target: &Target,
name: Symbol,
) -> Result<Self, &'static [&'static str]> {
@@ -819,7 +878,7 @@
},
InlineAsmArch::AArch64 => match name {
"C" | "system" | "efiapi" => {
- Ok(if aarch64::reserved_x18(arch, has_feature, target).is_err() {
+ Ok(if aarch64::reserved_x18(arch, target_features, target, true).is_err() {
InlineAsmClobberAbi::AArch64NoX18
} else {
InlineAsmClobberAbi::AArch64
diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs
new file mode 100644
index 0000000..a27d639
--- /dev/null
+++ b/compiler/rustc_target/src/asm/msp430.rs
@@ -0,0 +1,81 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ Msp430 Msp430InlineAsmRegClass {
+ reg,
+ }
+}
+
+impl Msp430InlineAsmRegClass {
+ 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<Symbol>)] {
+ match (self, arch) {
+ (Self::reg, _) => types! { _: I8, I16; },
+ }
+ }
+}
+
+// The reserved registers are taken from:
+// https://github.com/llvm/llvm-project/blob/36cb29cbbe1b22dcd298ad65e1fabe899b7d7249/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp#L73.
+def_regs! {
+ Msp430 Msp430InlineAsmReg Msp430InlineAsmRegClass {
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r11: reg = ["r11"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ r15: reg = ["r15"],
+
+ #error = ["r0", "pc"] =>
+ "the program counter cannot be used as an operand for inline asm",
+ #error = ["r1", "sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r2", "sr"] =>
+ "the status register cannot be used as an operand for inline asm",
+ #error = ["r3", "cg"] =>
+ "the constant generator cannot be used as an operand for inline asm",
+ #error = ["r4", "fp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ }
+}
+
+impl Msp430InlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs
index 43d16ae..8e1e91e 100644
--- a/compiler/rustc_target/src/asm/nvptx.rs
+++ b/compiler/rustc_target/src/asm/nvptx.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
def_reg_class! {
Nvptx NvptxInlineAsmRegClass {
@@ -33,7 +34,7 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg16 => types! { _: I8, I16; },
Self::reg32 => types! { _: I8, I16, I32, F32; },
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index 51a4303..d3ccb30 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -36,7 +37,7 @@
pub fn supported_types(
self,
arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg | Self::reg_nonzero => {
if arch == InlineAsmArch::PowerPC {
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index 314bd01..e145ba8 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -1,6 +1,8 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
use std::fmt;
def_reg_class! {
@@ -35,7 +37,7 @@
pub fn supported_types(
self,
arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => {
if arch == InlineAsmArch::RiscV64 {
@@ -44,7 +46,7 @@
types! { _: I8, I16, I32, F32; }
}
}
- Self::freg => types! { "f": F32; "d": F64; },
+ Self::freg => types! { f: F32; d: F64; },
Self::vreg => &[],
}
}
@@ -52,10 +54,11 @@
fn not_e(
_arch: InlineAsmArch,
- mut has_feature: impl FnMut(&str) -> bool,
+ target_features: &FxHashSet<Symbol>,
_target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
- if has_feature("e") {
+ if target_features.contains(&sym::e) {
Err("register can't be used with the `e` target feature")
} else {
Ok(())
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index a74873f..0a50064 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -33,7 +34,7 @@
pub fn supported_types(
self,
arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match (self, arch) {
(Self::reg, _) => types! { _: I8, I16, I32, I64; },
(Self::freg, _) => types! { _: F32, F64; },
diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs
index da82749..31073da 100644
--- a/compiler/rustc_target/src/asm/spirv.rs
+++ b/compiler/rustc_target/src/asm/spirv.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
def_reg_class! {
SpirV SpirVInlineAsmRegClass {
@@ -31,7 +32,7 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg => {
types! { _: I8, I16, I32, I64, F32, F64; }
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
index 1b33f8f..f095b7c 100644
--- a/compiler/rustc_target/src/asm/wasm.rs
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -1,5 +1,6 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
def_reg_class! {
Wasm WasmInlineAsmRegClass {
@@ -31,7 +32,7 @@
pub fn supported_types(
self,
_arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::local => {
types! { _: I8, I16, I32, I64, F32, F64; }
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 5e3828d..a8ee80e 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -1,6 +1,8 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@@ -101,7 +103,7 @@
pub fn supported_types(
self,
arch: InlineAsmArch,
- ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg | Self::reg_abcd => {
if arch == InlineAsmArch::X86_64 {
@@ -112,23 +114,23 @@
}
Self::reg_byte => types! { _: I8; },
Self::xmm_reg => types! {
- "sse": I32, I64, F32, F64,
+ sse: I32, I64, F32, F64,
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
},
Self::ymm_reg => types! {
- "avx": I32, I64, F32, F64,
+ avx: I32, I64, F32, F64,
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4);
},
Self::zmm_reg => types! {
- "avx512f": I32, I64, F32, F64,
+ avx512f: I32, I64, F32, F64,
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4),
VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8);
},
Self::kreg => types! {
- "avx512f": I8, I16;
- "avx512bw": I32, I64;
+ avx512f: I8, I16;
+ avx512bw: I32, I64;
},
Self::mmx_reg | Self::x87_reg => &[],
}
@@ -137,8 +139,9 @@
fn x86_64_only(
arch: InlineAsmArch,
- _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &FxHashSet<Symbol>,
_target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
match arch {
InlineAsmArch::X86 => Err("register is only available on x86_64"),
@@ -149,8 +152,9 @@
fn high_byte(
arch: InlineAsmArch,
- _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &FxHashSet<Symbol>,
_target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
match arch {
InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
@@ -160,8 +164,9 @@
fn rbx_reserved(
arch: InlineAsmArch,
- _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &FxHashSet<Symbol>,
_target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
match arch {
InlineAsmArch::X86 => Ok(()),
@@ -174,8 +179,9 @@
fn esi_reserved(
arch: InlineAsmArch,
- _has_feature: impl FnMut(&str) -> bool,
+ _target_features: &FxHashSet<Symbol>,
_target: &Target,
+ _is_clobber: bool,
) -> Result<(), &'static str> {
match arch {
InlineAsmArch::X86 => {
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index 1e9abbb..5692925 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -14,7 +14,9 @@
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
features: "+neon,+fp-armv8".to_string(),
- supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
+ supported_sanitizers: SanitizerSet::CFI
+ | SanitizerSet::HWADDRESS
+ | SanitizerSet::MEMTAG,
..super::android_base::opts()
},
}
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
index 44beb2f..f8e1e1b 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
@@ -3,6 +3,7 @@
pub fn target() -> Target {
let mut base = super::hermit_base::opts();
base.max_atomic_width = Some(128);
+ base.features = "+strict-align,+neon,+fp-armv8".to_string();
Target {
llvm_target: "aarch64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
index 850381f..974a5b8 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -14,6 +14,7 @@
| SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
+ | SanitizerSet::MEMTAG
| SanitizerSet::THREAD
| SanitizerSet::HWADDRESS,
..super::linux_gnu_base::opts()
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_hermitkernel.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_hermitkernel.rs
new file mode 100644
index 0000000..6e9d6c6
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_hermitkernel.rs
@@ -0,0 +1,16 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+ let mut base = super::hermit_kernel_base::opts();
+ base.max_atomic_width = Some(128);
+ base.abi = "softfloat".to_string();
+ base.features = "+strict-align,-neon,-fp-armv8".to_string();
+
+ Target {
+ llvm_target: "aarch64-unknown-hermit".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: base,
+ }
+}
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index e3a2226..d9e571c 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -13,14 +13,14 @@
// churn. The specific values are meaningless.
Rust,
C { unwind: bool },
- Cdecl,
+ Cdecl { unwind: bool },
Stdcall { unwind: bool },
- Fastcall,
- Vectorcall,
+ Fastcall { unwind: bool },
+ Vectorcall { unwind: bool },
Thiscall { unwind: bool },
- Aapcs,
- Win64,
- SysV64,
+ Aapcs { unwind: bool },
+ Win64 { unwind: bool },
+ SysV64 { unwind: bool },
PtxKernel,
Msp430Interrupt,
X86Interrupt,
@@ -50,16 +50,22 @@
AbiData { abi: Abi::Rust, name: "Rust" },
AbiData { abi: Abi::C { unwind: false }, name: "C" },
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
- AbiData { abi: Abi::Cdecl, name: "cdecl" },
+ AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
+ AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
- AbiData { abi: Abi::Fastcall, name: "fastcall" },
- AbiData { abi: Abi::Vectorcall, name: "vectorcall" },
+ AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
+ AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
+ AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
+ AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
- AbiData { abi: Abi::Aapcs, name: "aapcs" },
- AbiData { abi: Abi::Win64, name: "win64" },
- AbiData { abi: Abi::SysV64, name: "sysv64" },
+ AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
+ AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
+ AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
+ AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
+ AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
+ AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
@@ -101,32 +107,38 @@
C { unwind: false } => 1,
C { unwind: true } => 2,
// Platform-specific ABIs
- Cdecl => 3,
- Stdcall { unwind: false } => 4,
- Stdcall { unwind: true } => 5,
- Fastcall => 6,
- Vectorcall => 7,
- Thiscall { unwind: false } => 8,
- Thiscall { unwind: true } => 9,
- Aapcs => 10,
- Win64 => 11,
- SysV64 => 12,
- PtxKernel => 13,
- Msp430Interrupt => 14,
- X86Interrupt => 15,
- AmdGpuKernel => 16,
- EfiApi => 17,
- AvrInterrupt => 18,
- AvrNonBlockingInterrupt => 19,
- CCmseNonSecureCall => 20,
- Wasm => 21,
+ Cdecl { unwind: false } => 3,
+ Cdecl { unwind: true } => 4,
+ Stdcall { unwind: false } => 5,
+ Stdcall { unwind: true } => 6,
+ Fastcall { unwind: false } => 7,
+ Fastcall { unwind: true } => 8,
+ Vectorcall { unwind: false } => 9,
+ Vectorcall { unwind: true } => 10,
+ Thiscall { unwind: false } => 11,
+ Thiscall { unwind: true } => 12,
+ Aapcs { unwind: false } => 13,
+ Aapcs { unwind: true } => 14,
+ Win64 { unwind: false } => 15,
+ Win64 { unwind: true } => 16,
+ SysV64 { unwind: false } => 17,
+ SysV64 { unwind: true } => 18,
+ PtxKernel => 19,
+ Msp430Interrupt => 20,
+ X86Interrupt => 21,
+ AmdGpuKernel => 22,
+ EfiApi => 23,
+ AvrInterrupt => 24,
+ AvrNonBlockingInterrupt => 25,
+ CCmseNonSecureCall => 26,
+ Wasm => 27,
// Cross-platform ABIs
- System { unwind: false } => 22,
- System { unwind: true } => 23,
- RustIntrinsic => 24,
- RustCall => 25,
- PlatformIntrinsic => 26,
- Unadjusted => 27,
+ System { unwind: false } => 28,
+ System { unwind: true } => 29,
+ RustIntrinsic => 30,
+ RustCall => 31,
+ PlatformIntrinsic => 32,
+ Unadjusted => 33,
};
debug_assert!(
AbiDatas
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index e982b35..dc14d26 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -1,14 +1,8 @@
-use crate::spec::{LinkerFlavor, TargetOptions};
+use crate::spec::TargetOptions;
pub fn opts() -> TargetOptions {
let mut base = super::linux_base::opts();
base.os = "android".to_string();
- // Many of the symbols defined in compiler-rt are also defined in libgcc.
- // Android's linker doesn't like that by default.
- base.pre_link_args
- .entry(LinkerFlavor::Gcc)
- .or_default()
- .push("-Wl,--allow-multiple-definition".to_string());
base.dwarf_version = Some(2);
base.position_independent_executables = true;
base.has_thread_local = false;
diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
index afe8bbb..3e3a6ac 100644
--- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
+++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
@@ -36,6 +36,7 @@
features: "+vfp2".to_string(),
pre_link_args,
exe_suffix: ".elf".to_string(),
+ no_default_libraries: false,
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabi.rs
new file mode 100644
index 0000000..7faa8ed
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabi.rs
@@ -0,0 +1,23 @@
+use crate::spec::{Target, TargetOptions};
+
+// This target is for uclibc Linux on ARMv7 without NEON,
+// thumb-mode or hardfloat.
+
+pub fn target() -> Target {
+ let base = super::linux_uclibc_base::opts();
+ Target {
+ llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+ arch: "arm".to_string(),
+
+ options: TargetOptions {
+ features: "+v7,+thumb2,+soft-float,-neon".to_string(),
+ cpu: "generic".to_string(),
+ max_atomic_width: Some(64),
+ mcount: "_mcount".to_string(),
+ abi: "eabi".to_string(),
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 2cb2661..a6c1b34 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -17,12 +17,10 @@
linker: Some("avr-gcc".to_owned()),
executables: true,
eh_frame_header: false,
- pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
+ pre_link_args: [(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
.into_iter()
.collect(),
- late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])]
- .into_iter()
- .collect(),
+ late_link_args: [(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])].into_iter().collect(),
max_atomic_width: Some(0),
atomic_cas: false,
..TargetOptions::default()
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
index 74074cf..1742948 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
@@ -24,7 +24,7 @@
llvm_target: "i686-pc-windows-msvc".to_string(),
pointer_width: 32,
data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
- i64:64-f80:32-n8:16:32-a:0:32-S32"
+ i64:64-f80:128-n8:16:32-a:0:32-S32"
.to_string(),
arch: "x86".to_string(),
options: base,
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
index 05f204c..e2f65e7 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
@@ -9,7 +9,7 @@
llvm_target: "i686-pc-windows-msvc".to_string(),
pointer_width: 32,
data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
- i64:64-f80:32-n8:16:32-a:0:32-S32"
+ i64:64-f80:128-n8:16:32-a:0:32-S32"
.to_string(),
arch: "x86".to_string(),
options: base,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index f6e3102..9e7973f 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -1,25 +1,14 @@
use crate::spec::{LinkerFlavor, PanicStrategy, TargetOptions};
-//use std::process::Command;
-
-// Use GCC to locate code for crt* libraries from the host, not from L4Re. Note
-// that a few files also come from L4Re, for these, the function shouldn't be
-// used. This uses GCC for the location of the file, but GCC is required for L4Re anyway.
-//fn get_path_or(filename: &str) -> String {
-// let child = Command::new("gcc")
-// .arg(format!("-print-file-name={}", filename)).output()
-// .expect("Failed to execute GCC");
-// String::from_utf8(child.stdout)
-// .expect("Couldn't read path from GCC").trim().into()
-//}
+use std::default::Default;
pub fn opts() -> TargetOptions {
TargetOptions {
os: "l4re".to_string(),
env: "uclibc".to_string(),
- linker_flavor: LinkerFlavor::Ld,
+ linker_flavor: LinkerFlavor::L4Bender,
executables: true,
panic_strategy: PanicStrategy::Abort,
- linker: Some("ld".to_string()),
+ linker: Some("l4-bender".to_string()),
linker_is_gnu: false,
families: vec!["unix".to_string()],
..Default::default()
diff --git a/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs
new file mode 100644
index 0000000..5991cd8
--- /dev/null
+++ b/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs
@@ -0,0 +1,26 @@
+/// A target tuple for OpenWrt MIPS64 targets
+///
+use crate::abi::Endian;
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = super::linux_musl_base::opts();
+ base.cpu = "mips64r2".to_string();
+ base.features = "+mips64r2,+soft-float".to_string();
+ base.max_atomic_width = Some(64);
+ base.crt_static_default = false;
+
+ Target {
+ // LLVM doesn't recognize "muslabi64" yet.
+ llvm_target: "mips64-unknown-linux-musl".to_string(),
+ pointer_width: 64,
+ data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
+ arch: "mips64".to_string(),
+ options: TargetOptions {
+ abi: "abi64".to_string(),
+ endian: Endian::Big,
+ mcount: "_mcount".to_string(),
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ca1949b..92678ae 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -90,6 +90,7 @@
pub enum LinkerFlavor {
Em,
Gcc,
+ L4Bender,
Ld,
Msvc,
Lld(LldFlavor),
@@ -160,6 +161,7 @@
flavor_mappings! {
((LinkerFlavor::Em), "em"),
((LinkerFlavor::Gcc), "gcc"),
+ ((LinkerFlavor::L4Bender), "l4-bender"),
((LinkerFlavor::Ld), "ld"),
((LinkerFlavor::Msvc), "msvc"),
((LinkerFlavor::PtxLinker), "ptx-linker"),
@@ -574,15 +576,15 @@
fn to_json(&self) -> Json {
Json::Object(match self {
StackProbeType::None => {
- vec![(String::from("kind"), "none".to_json())].into_iter().collect()
+ [(String::from("kind"), "none".to_json())].into_iter().collect()
}
StackProbeType::Inline => {
- vec![(String::from("kind"), "inline".to_json())].into_iter().collect()
+ [(String::from("kind"), "inline".to_json())].into_iter().collect()
}
StackProbeType::Call => {
- vec![(String::from("kind"), "call".to_json())].into_iter().collect()
+ [(String::from("kind"), "call".to_json())].into_iter().collect()
}
- StackProbeType::InlineOrCall { min_llvm_version_for_inline } => vec![
+ StackProbeType::InlineOrCall { min_llvm_version_for_inline } => [
(String::from("kind"), "inline-or-call".to_json()),
(
String::from("min-llvm-version-for-inline"),
@@ -604,6 +606,7 @@
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
const CFI = 1 << 5;
+ const MEMTAG = 1 << 6;
}
}
@@ -617,6 +620,7 @@
SanitizerSet::CFI => "cfi",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
+ SanitizerSet::MEMTAG => "memtag",
SanitizerSet::THREAD => "thread",
SanitizerSet::HWADDRESS => "hwaddress",
_ => return None,
@@ -650,6 +654,7 @@
SanitizerSet::CFI,
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
+ SanitizerSet::MEMTAG,
SanitizerSet::THREAD,
SanitizerSet::HWADDRESS,
]
@@ -962,6 +967,7 @@
("aarch64-unknown-hermit", aarch64_unknown_hermit),
("x86_64-unknown-hermit", x86_64_unknown_hermit),
+ ("aarch64-unknown-none-hermitkernel", aarch64_unknown_none_hermitkernel),
("x86_64-unknown-none-hermitkernel", x86_64_unknown_none_hermitkernel),
("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
@@ -1011,9 +1017,12 @@
("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
+ ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
("x86_64-unknown-none", x86_64_unknown_none),
+
+ ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
}
/// Warnings encountered when parsing the target `json`.
@@ -1535,11 +1544,13 @@
impl Deref for Target {
type Target = TargetOptions;
+ #[inline]
fn deref(&self) -> &Self::Target {
&self.options
}
}
impl DerefMut for Target {
+ #[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.options
}
@@ -1554,15 +1565,15 @@
Abi::Stdcall { unwind }
}
Abi::System { unwind } => Abi::C { unwind },
- Abi::EfiApi if self.arch == "x86_64" => Abi::Win64,
+ Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
Abi::EfiApi => Abi::C { unwind: false },
// See commentary in `is_abi_supported`.
Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
- Abi::Fastcall if self.arch == "x86" => abi,
- Abi::Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
- Abi::Fastcall | Abi::Vectorcall => Abi::C { unwind: false },
+ Abi::Fastcall { .. } if self.arch == "x86" => abi,
+ Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
+ Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
abi => abi,
}
@@ -1579,12 +1590,12 @@
| RustCall
| PlatformIntrinsic
| Unadjusted
- | Cdecl
+ | Cdecl { .. }
| EfiApi => true,
X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
- Aapcs => "arm" == self.arch,
+ Aapcs { .. } => "arm" == self.arch,
CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
- Win64 | SysV64 => self.arch == "x86_64",
+ Win64 { .. } | SysV64 { .. } => self.arch == "x86_64",
PtxKernel => self.arch == "nvptx64",
Msp430Interrupt => self.arch == "msp430",
AmdGpuKernel => self.arch == "amdgcn",
@@ -1621,13 +1632,13 @@
// > convention is used.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
- Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true,
+ Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
// Outside of Windows we want to only support these calling conventions for the
// architectures for which these calling conventions are actually well defined.
- Stdcall { .. } | Fastcall if self.arch == "x86" => true,
- Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
+ Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
+ Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
// Return a `None` for other cases so that we know to emit a future compat lint.
- Stdcall { .. } | Fastcall | Vectorcall => return None,
+ Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None,
})
}
@@ -1875,6 +1886,7 @@
Some("cfi") => SanitizerSet::CFI,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
+ Some("memtag") => SanitizerSet::MEMTAG,
Some("thread") => SanitizerSet::THREAD,
Some("hwaddress") => SanitizerSet::HWADDRESS,
Some(s) => return Err(format!("unknown sanitizer {}", s)),
@@ -2143,8 +2155,8 @@
use std::fs;
fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
- let contents = fs::read(path).map_err(|e| e.to_string())?;
- let obj = json::from_reader(&mut &contents[..]).map_err(|e| e.to_string())?;
+ let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
+ let obj = json::from_str(&contents).map_err(|e| e.to_string())?;
Target::from_json(obj)
}
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 69a404e..8fcdbc1 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -43,7 +43,8 @@
Target {
llvm_target: "wasm32-unknown-emscripten".to_string(),
pointer_width: 32,
- data_layout: "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20".to_string(),
+ data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-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 134c680..e50cf97 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-ni:1:10:20".to_string(),
+ data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-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 2dab206..a4b81c9 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-ni:1:10:20".to_string(),
+ data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".to_string(),
arch: "wasm32".to_string(),
options,
}
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
index 1fbd0bb..64c7c1c 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
@@ -1,9 +1,12 @@
-use crate::spec::Target;
+use crate::spec::{PanicStrategy, Target};
pub fn target() -> Target {
let mut base = super::l4re_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
+ base.crt_static_allows_dylibs = false;
+ base.dynamic_linking = false;
+ base.panic_strategy = PanicStrategy::Abort;
Target {
llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index c2484f2..aefbb39 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -7,6 +7,7 @@
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.static_position_independent_executables = true;
base.supported_sanitizers = SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::LEAK
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 17e7b48..0041f59 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -22,6 +22,7 @@
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] // For rustdoc
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index ea0ac63..c93ff0a 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -141,7 +141,7 @@
#[instrument(skip(self), level = "debug")]
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match r {
+ match *r {
// Ignore bound regions and `'static` regions that appear in the
// type, we only need to remap regions that reference lifetimes
// from the function declaraion.
@@ -287,10 +287,10 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
trace!("checking const {:?}", ct);
// Find a const parameter
- match ct.val {
+ match ct.val() {
ty::ConstKind::Param(..) => {
// Look it up in the substitution list.
match self.map.get(&ct.into()).map(|k| k.unpack()) {
@@ -311,7 +311,7 @@
)
.emit();
- self.tcx().const_error(ct.ty)
+ self.tcx().const_error(ct.ty())
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 05d2a37..5fe7b62 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,7 +6,7 @@
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{Region, RegionVid, Term};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -437,16 +437,12 @@
for (new_region, old_region) in
iter::zip(new_substs.regions(), old_substs.regions())
{
- match (new_region, old_region) {
+ match (*new_region, *old_region) {
// If both predicates have an `ReLateBound` (a HRTB) in the
// same spot, we do nothing.
- (
- ty::RegionKind::ReLateBound(_, _),
- ty::RegionKind::ReLateBound(_, _),
- ) => {}
+ (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {}
- (ty::RegionKind::ReLateBound(_, _), _)
- | (_, ty::RegionKind::ReVar(_)) => {
+ (ty::ReLateBound(_, _), _) | (_, ty::ReVar(_)) => {
// One of these is true:
// The new predicate has a HRTB in a spot where the old
// predicate does not (if they both had a HRTB, the previous
@@ -472,8 +468,7 @@
// `user_computed_preds`.
return false;
}
- (_, ty::RegionKind::ReLateBound(_, _))
- | (ty::RegionKind::ReVar(_), _) => {
+ (_, ty::ReLateBound(_, _)) | (ty::ReVar(_), _) => {
// This is the opposite situation as the previous arm.
// One of these is true:
//
@@ -606,7 +601,11 @@
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
- matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
+ if let Term::Ty(ty) = p.term().skip_binder() {
+ matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
+ } else {
+ false
+ }
}
fn evaluate_nested_obligations(
@@ -663,7 +662,7 @@
// Additionally, we check if we've seen this predicate before,
// to avoid rendering duplicate bounds to the user.
if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
- && !p.ty().skip_binder().has_infer_types()
+ && !p.term().skip_binder().has_infer_types()
&& is_new_pred
{
debug!(
@@ -752,7 +751,7 @@
// when we started out trying to unify
// some inference variables. See the comment above
// for more infomration
- if p.ty().skip_binder().has_infer_types() {
+ if p.term().skip_binder().has_infer_types() {
if !self.evaluate_nested_obligations(
ty,
v.into_iter(),
@@ -774,7 +773,7 @@
// However, we should always make progress (either by generating
// subobligations or getting an error) when we started off with
// inference variables
- if p.ty().skip_binder().has_infer_types() {
+ if p.term().skip_binder().has_infer_types() {
panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
}
}
@@ -810,14 +809,14 @@
};
}
ty::PredicateKind::ConstEquate(c1, c2) => {
- let evaluate = |c: &'tcx ty::Const<'tcx>| {
- if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
+ let evaluate = |c: ty::Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
match select.infcx().const_eval_resolve(
obligation.param_env,
unevaluated,
Some(obligation.cause.span),
) {
- Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty)),
+ Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty())),
Err(err) => Err(err),
}
} else {
@@ -876,8 +875,8 @@
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- (match r {
- ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
+ (match *r {
+ ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
_ => None,
})
.unwrap_or_else(|| r.super_fold_with(self))
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 34fc4ca..93c2f20 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -8,7 +8,7 @@
PredicateObligation, SelectionError, TraitEngine,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
pub struct FulfillmentContext<'tcx> {
obligations: FxIndexSet<PredicateObligation<'tcx>>,
@@ -91,7 +91,12 @@
let environment = obligation.param_env.caller_bounds();
let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
let mut orig_values = OriginalQueryValues::default();
- let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
+ if goal.references_error() {
+ continue;
+ }
+
+ let canonical_goal =
+ infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
match infcx.tcx.evaluate_goal(canonical_goal) {
Ok(response) => {
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 848aba7..bf6e6a4 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -18,12 +18,11 @@
/// that type check should guarantee to us that all nested
/// obligations *could be* resolved if we wanted to.
///
-/// Assumes that this is run after the entire crate has been successfully type-checked.
/// This also expects that `trait_ref` is fully normalized.
pub fn codegen_fulfill_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
-) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
+) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorReported> {
// Remove any references to regions; this helps improve caching.
let trait_ref = tcx.erase_regions(trait_ref);
// We expect the input to be fully normalized.
@@ -65,6 +64,8 @@
Err(Unimplemented) => {
// This can trigger when we probe for the source of a `'static` lifetime requirement
// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+ // This can also trigger when we have a global bound that is not actually satisfied,
+ // but was included during typeck due to the trivial_bounds feature.
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!(
@@ -92,7 +93,7 @@
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
- Ok(impl_source)
+ Ok(&*tcx.arena.alloc(impl_source))
})
}
@@ -101,7 +102,7 @@
/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
-/// for use after type-check has completed, if any errors occur,
+/// for use outside of type inference, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
@@ -124,7 +125,10 @@
if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
- &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
+ &format!(
+ "Encountered errors `{:?}` resolving bounds outside of type inference",
+ errors
+ ),
);
}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 290426a..b2aa72e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -4,15 +4,22 @@
//! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
-use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::{CombinedSnapshot, InferOk, RegionckMode};
use crate::traits::select::IntercrateAmbiguityCause;
+use crate::traits::util::impl_trait_ref_and_oblig;
use crate::traits::SkipLeakCheck;
use crate::traits::{
- self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
+ self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
+ PredicateObligations, SelectionContext,
};
+//use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_hir::CRATE_HIR_ID;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::TraitEngine;
+use rustc_middle::traits::specialization_graph::OverlapMode;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -53,11 +60,13 @@
/// If there are types that satisfy both impls, invokes `on_overlap`
/// with a suitably-freshened `ImplHeader` with those types
/// substituted. Otherwise, invokes `no_overlap`.
+#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
pub fn overlapping_impls<F1, F2, R>(
tcx: TyCtxt<'_>,
impl1_def_id: DefId,
impl2_def_id: DefId,
skip_leak_check: SkipLeakCheck,
+ overlap_mode: OverlapMode,
on_overlap: F1,
no_overlap: F2,
) -> R
@@ -65,12 +74,6 @@
F1: FnOnce(OverlapResult<'_>) -> R,
F2: FnOnce() -> R,
{
- debug!(
- "overlapping_impls(\
- impl1_def_id={:?}, \
- impl2_def_id={:?})",
- impl1_def_id, impl2_def_id,
- );
// Before doing expensive operations like entering an inference context, do
// a quick check via fast_reject to tell if the impl headers could possibly
// unify.
@@ -83,8 +86,9 @@
impl2_ref.iter().flat_map(|tref| tref.substs.types()),
)
.any(|(ty1, ty2)| {
- let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
- let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
+ let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No);
+ let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No);
+
if let (Some(t1), Some(t2)) = (t1, t2) {
// Simplified successfully
t1 != t2
@@ -100,7 +104,7 @@
let overlaps = tcx.infer_ctxt().enter(|infcx| {
let selcx = &mut SelectionContext::intercrate(&infcx);
- overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()
+ overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
});
if !overlaps {
@@ -113,7 +117,9 @@
tcx.infer_ctxt().enter(|infcx| {
let selcx = &mut SelectionContext::intercrate(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
- on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap())
+ on_overlap(
+ overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
+ )
})
}
@@ -144,40 +150,43 @@
fn overlap<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
skip_leak_check: SkipLeakCheck,
- a_def_id: DefId,
- b_def_id: DefId,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ overlap_mode: OverlapMode,
) -> Option<OverlapResult<'tcx>> {
- debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
+ debug!(
+ "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})",
+ impl1_def_id, impl2_def_id, overlap_mode
+ );
selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
- overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
+ overlap_within_probe(
+ selcx,
+ skip_leak_check,
+ impl1_def_id,
+ impl2_def_id,
+ overlap_mode,
+ snapshot,
+ )
})
}
fn overlap_within_probe<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
skip_leak_check: SkipLeakCheck,
- a_def_id: DefId,
- b_def_id: DefId,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ overlap_mode: OverlapMode,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Option<OverlapResult<'tcx>> {
- fn loose_check<'cx, 'tcx>(
- selcx: &mut SelectionContext<'cx, 'tcx>,
- o: &PredicateObligation<'tcx>,
- ) -> bool {
- !selcx.predicate_may_hold_fatal(o)
- }
+ let infcx = selcx.infcx();
- fn strict_check<'cx, 'tcx>(
- selcx: &SelectionContext<'cx, 'tcx>,
- o: &PredicateObligation<'tcx>,
- ) -> bool {
- let infcx = selcx.infcx();
- let tcx = infcx.tcx;
- o.flip_polarity(tcx)
- .as_ref()
- .map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
- .unwrap_or(false)
+ if overlap_mode.use_negative_impl() {
+ if negative_impl(selcx, impl1_def_id, impl2_def_id)
+ || negative_impl(selcx, impl2_def_id, impl1_def_id)
+ {
+ return None;
+ }
}
// For the purposes of this check, we don't bring any placeholder
@@ -186,26 +195,59 @@
// empty environment.
let param_env = ty::ParamEnv::empty();
- let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id);
- let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id);
+ let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
+ let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
- debug!("overlap: a_impl_header={:?}", a_impl_header);
- debug!("overlap: b_impl_header={:?}", b_impl_header);
-
- // Do `a` and `b` unify? If not, no overlap.
- let obligations = match selcx
- .infcx()
- .at(&ObligationCause::dummy(), param_env)
- .eq_impl_headers(&a_impl_header, &b_impl_header)
- {
- Ok(InferOk { obligations, value: () }) => obligations,
- Err(_) => {
- return None;
- }
- };
-
+ let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded");
+ if overlap_mode.use_implicit_negative() {
+ if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) {
+ return None;
+ }
+ }
+
+ if !skip_leak_check.is_yes() {
+ if infcx.leak_check(true, snapshot).is_err() {
+ debug!("overlap: leak check failed");
+ return None;
+ }
+ }
+
+ let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+ debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+
+ let involves_placeholder =
+ matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
+
+ let impl_header = selcx.infcx().resolve_vars_if_possible(impl1_header);
+ Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
+}
+
+fn equate_impl_headers<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ impl1_header: &ty::ImplHeader<'tcx>,
+ impl2_header: &ty::ImplHeader<'tcx>,
+) -> Option<PredicateObligations<'tcx>> {
+ // Do `a` and `b` unify? If not, no overlap.
+ debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
+ selcx
+ .infcx()
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .eq_impl_headers(impl1_header, impl2_header)
+ .map(|infer_ok| infer_ok.obligations)
+ .ok()
+}
+
+/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
+/// where-clauses) If so, return false, otherwise return true, they are disjoint.
+fn implicit_negative<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ impl1_header: &ty::ImplHeader<'tcx>,
+ impl2_header: ty::ImplHeader<'tcx>,
+ obligations: PredicateObligations<'tcx>,
+) -> bool {
// There's no overlap if obligations are unsatisfiable or if the obligation negated is
// satisfied.
//
@@ -227,13 +269,16 @@
// If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
// hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
// at some point an impl for `&'?a str: Error` could be added.
+ debug!(
+ "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})",
+ impl1_header, impl2_header, obligations
+ );
let infcx = selcx.infcx();
- let tcx = infcx.tcx;
- let opt_failing_obligation = a_impl_header
+ let opt_failing_obligation = impl1_header
.predicates
.iter()
.copied()
- .chain(b_impl_header.predicates)
+ .chain(impl2_header.predicates)
.map(|p| infcx.resolve_vars_if_possible(p))
.map(|p| Obligation {
cause: ObligationCause::dummy(),
@@ -242,41 +287,125 @@
predicate: p,
})
.chain(obligations)
- .find(|o| {
- // if both impl headers are set to strict coherence it means that this will be accepted
- // only if it's stated that T: !Trait. So only prove that the negated obligation holds.
- if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
- && tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
- {
- strict_check(selcx, o)
- } else {
- loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o)
- }
- });
- // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
- // to the canonical trait query form, `infcx.predicate_may_hold`, once
- // the new system supports intercrate mode (which coherence needs).
+ .find(|o| !selcx.predicate_may_hold_fatal(o));
if let Some(failing_obligation) = opt_failing_obligation {
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
- return None;
+ true
+ } else {
+ false
}
+}
- if !skip_leak_check.is_yes() {
- if infcx.leak_check(true, snapshot).is_err() {
- debug!("overlap: leak check failed");
- return None;
+/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
+/// where-clauses) If so, return true, they are disjoint and false otherwise.
+fn negative_impl<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+) -> bool {
+ debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
+ let tcx = selcx.infcx().tcx;
+
+ // create a parameter environment corresponding to a (placeholder) instantiation of impl1
+ let impl1_env = tcx.param_env(impl1_def_id);
+ let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
+
+ // 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.
+ let impl1_trait_ref = match traits::fully_normalize(
+ &infcx,
+ FulfillmentContext::new(),
+ ObligationCause::dummy(),
+ impl1_env,
+ impl1_trait_ref,
+ ) {
+ Ok(impl1_trait_ref) => impl1_trait_ref,
+ Err(err) => {
+ bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
+ }
+ };
+
+ // Attempt to prove that impl2 applies, given all of the above.
+ let selcx = &mut SelectionContext::new(&infcx);
+ let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
+ let (impl2_trait_ref, obligations) =
+ impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
+
+ // do the impls unify? If not, not disjoint.
+ let more_obligations = match infcx
+ .at(&ObligationCause::dummy(), impl1_env)
+ .eq(impl1_trait_ref, impl2_trait_ref)
+ {
+ Ok(InferOk { obligations, .. }) => obligations,
+ Err(_) => {
+ debug!(
+ "explicit_disjoint: {:?} does not unify with {:?}",
+ impl1_trait_ref, impl2_trait_ref
+ );
+ return false;
+ }
+ };
+
+ let opt_failing_obligation = obligations
+ .into_iter()
+ .chain(more_obligations)
+ .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
+
+ if let Some(failing_obligation) = opt_failing_obligation {
+ debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
+ true
+ } else {
+ false
}
- }
+ })
+}
- let impl_header = selcx.infcx().resolve_vars_if_possible(a_impl_header);
- let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
- debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+fn negative_impl_exists<'cx, 'tcx>(
+ selcx: &SelectionContext<'cx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ region_context: DefId,
+ o: &PredicateObligation<'tcx>,
+) -> bool {
+ let infcx = &selcx.infcx().fork();
+ let tcx = infcx.tcx;
+ o.flip_polarity(tcx)
+ .map(|o| {
+ let mut fulfillment_cx = FulfillmentContext::new();
+ fulfillment_cx.register_predicate_obligation(infcx, o);
- let involves_placeholder =
- matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
+ let errors = fulfillment_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ return false;
+ }
- Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
+ let mut outlives_env = OutlivesEnvironment::new(param_env);
+ // FIXME -- add "assumed to be well formed" types into the `outlives_env`
+
+ // "Save" the accumulated implied bounds into the outlives environment
+ // (due to the FIXME above, there aren't any, but this step is still needed).
+ // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used
+ // by the "dummy" causes elsewhere (body-id is only relevant when checking
+ // function bodies with closures).
+ outlives_env.save_implied_bounds(CRATE_HIR_ID);
+
+ infcx.process_registered_region_obligations(
+ outlives_env.region_bound_pairs_map(),
+ Some(tcx.lifetimes.re_root_empty),
+ param_env,
+ );
+
+ let errors =
+ infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
+ if !errors.is_empty() {
+ return false;
+ }
+
+ true
+ })
+ .unwrap_or(false)
}
pub fn trait_ref_is_knowable<'tcx>(
@@ -444,7 +573,7 @@
) -> Result<(), OrphanCheckErr<'tcx>> {
debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
- if trait_ref.needs_infer() && trait_ref.definitely_needs_subst(tcx) {
+ if trait_ref.needs_infer() && trait_ref.needs_subst() {
bug!(
"can't orphan check a trait ref with both params and inference variables {:?}",
trait_ref
@@ -497,7 +626,7 @@
.substs
.types()
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
- .find(|ty| ty_is_local_constructor(ty, in_crate));
+ .find(|ty| ty_is_local_constructor(*ty, in_crate));
debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 0ea3a18..1994fae 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -8,6 +8,7 @@
//! In this case we try to build an abstract representation of this constant using
//! `thir_abstract_const` which can then be checked for structural equality with other
//! generic constants mentioned in the `caller_bounds` of the current environment.
+use rustc_data_structures::intern::Interned;
use rustc_errors::ErrorReported;
use rustc_hir::def::DefKind;
use rustc_index::vec::IndexVec;
@@ -84,7 +85,7 @@
Node::Leaf(leaf) => {
if leaf.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
- } else if leaf.definitely_has_param_types_or_consts(tcx) {
+ } else if leaf.has_param_types_or_consts() {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
}
@@ -93,7 +94,7 @@
Node::Cast(_, _, ty) => {
if ty.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
- } else if ty.definitely_has_param_types_or_consts(tcx) {
+ } else if ty.has_param_types_or_consts() {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
}
@@ -149,7 +150,7 @@
// See #74595 for more details about this.
let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
- if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
+ if concrete.is_ok() && uv.substs.has_param_types_or_consts() {
match infcx.tcx.def_kind(uv.def.did) {
DefKind::AnonConst | DefKind::InlineConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
@@ -196,14 +197,14 @@
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
- Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
+ Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs }))
}
pub fn from_const(
tcx: TyCtxt<'tcx>,
- ct: &ty::Const<'tcx>,
+ ct: ty::Const<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
- match ct.val {
+ match ct.val() {
ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
ty::ConstKind::Error(_) => Err(ErrorReported),
_ => Ok(None),
@@ -271,7 +272,6 @@
struct IsThirPolymorphic<'a, 'tcx> {
is_poly: bool,
thir: &'a thir::Thir<'tcx>,
- tcx: TyCtxt<'tcx>,
}
use thir::visit;
@@ -281,25 +281,25 @@
}
fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
- self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
+ self.is_poly |= expr.ty.has_param_types_or_consts();
if !self.is_poly {
visit::walk_expr(self, expr)
}
}
fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
- self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx);
+ self.is_poly |= pat.ty.has_param_types_or_consts();
if !self.is_poly {
visit::walk_pat(self, pat);
}
}
- fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
- self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx);
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) {
+ self.is_poly |= ct.has_param_types_or_consts();
}
}
- let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
+ let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
visit::walk_expr(&mut is_poly_vis, &body[body_id]);
debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
if !is_poly_vis.is_poly {
@@ -335,7 +335,11 @@
self.recurse_build(self.body_id)?;
for n in self.nodes.iter() {
- if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n {
+ if let Node::Leaf(ty::Const(Interned(
+ ty::ConstS { val: ty::ConstKind::Unevaluated(ct), ty: _ },
+ _,
+ ))) = n
+ {
// `AbstractConst`s should not contain any promoteds as they require references which
// are not allowed.
assert_eq!(ct.promoted, None);
@@ -480,7 +484,7 @@
// let expressions imply control flow
ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
self.error(node.span, "control flow is not supported in generic constants")?,
- ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => {
+ ExprKind::InlineAsm { .. } => {
self.error(node.span, "assembly is not supported in generic constants")?
}
@@ -603,11 +607,11 @@
match (a.root(tcx), b.root(tcx)) {
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
- if a_ct.ty != b_ct.ty {
+ if a_ct.ty() != b_ct.ty() {
return false;
}
- match (a_ct.val, b_ct.val) {
+ match (a_ct.val(), b_ct.val()) {
// We can just unify errors with everything to reduce the amount of
// emitted errors here.
(ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index a9ae0ec..c3df17c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -21,10 +21,9 @@
use rustc_hir::Node;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::{
- self, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
+ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_session::DiagnosticMessageId;
use rustc_span::symbol::{kw, sym};
@@ -40,6 +39,22 @@
pub use rustc_infer::traits::error_reporting::*;
+// When outputting impl candidates, prefer showing those that are more similar.
+//
+// We also compare candidates after skipping lifetimes, which has a lower
+// priority than exact matches.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CandidateSimilarity {
+ Exact { ignoring_lifetimes: bool },
+ Fuzzy { ignoring_lifetimes: bool },
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct ImplCandidate<'tcx> {
+ pub trait_ref: ty::TraitRef<'tcx>,
+ pub similarity: CandidateSimilarity,
+}
+
pub trait InferCtxtExt<'tcx> {
fn report_fulfillment_errors(
&self,
@@ -205,6 +220,7 @@
self.note_obligation_cause_code(
&mut err,
&obligation.predicate,
+ obligation.param_env,
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
@@ -261,7 +277,7 @@
.tcx
.diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc))
{
- obligation.cause = cause;
+ obligation.cause = cause.clone();
span = obligation.cause.span;
}
}
@@ -288,7 +304,11 @@
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(trait_predicate) => {
let trait_predicate = bound_predicate.rebind(trait_predicate);
- let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+ let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+
+ trait_predicate.remap_constness_diag(obligation.param_env);
+ let predicate_is_const = ty::BoundConstness::ConstIfConst
+ == trait_predicate.skip_binder().constness;
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
return;
@@ -305,13 +325,18 @@
})
.unwrap_or_default();
- let OnUnimplementedNote { message, label, note, enclosing_scope } =
- self.on_unimplemented_note(trait_ref, &obligation);
+ let OnUnimplementedNote {
+ message,
+ label,
+ note,
+ enclosing_scope,
+ append_const_msg,
+ } = self.on_unimplemented_note(trait_ref, &obligation);
let have_alt_message = message.is_some() || label.is_some();
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
let is_unsize =
{ Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
- let (message, note) = if is_try_conversion {
+ let (message, note, append_const_msg) = if is_try_conversion {
(
Some(format!(
"`?` couldn't convert the error to `{}`",
@@ -322,9 +347,10 @@
conversion on the error value using the `From` trait"
.to_owned(),
),
+ Some(None),
)
} else {
- (message, note)
+ (message, note, append_const_msg)
};
let mut err = struct_span_err!(
@@ -332,11 +358,27 @@
span,
E0277,
"{}",
- message.unwrap_or_else(|| format!(
- "the trait bound `{}` is not satisfied{}",
- trait_ref.without_const().to_predicate(tcx),
- post_message,
- ))
+ message
+ .and_then(|cannot_do_this| {
+ match (predicate_is_const, append_const_msg) {
+ // do nothing if predicate is not const
+ (false, _) => Some(cannot_do_this),
+ // suggested using default post message
+ (true, Some(None)) => {
+ Some(format!("{cannot_do_this} in const contexts"))
+ }
+ // overriden post message
+ (true, Some(Some(post_message))) => {
+ Some(format!("{cannot_do_this}{post_message}"))
+ }
+ // fallback to generic message
+ (true, None) => None,
+ }
+ })
+ .unwrap_or_else(|| format!(
+ "the trait bound `{}` is not satisfied{}",
+ trait_predicate, post_message,
+ ))
);
if is_try_conversion {
@@ -384,7 +426,7 @@
format!(
"{}the trait `{}` is not implemented for `{}`",
pre_message,
- trait_ref.print_only_trait_path(),
+ trait_predicate.print_modifiers_and_trait_path(),
trait_ref.skip_binder().self_ty(),
)
};
@@ -392,7 +434,7 @@
if self.suggest_add_reference_to_arg(
&obligation,
&mut err,
- &trait_ref,
+ trait_predicate,
have_alt_message,
) {
self.note_obligation_cause(&mut err, &obligation);
@@ -412,6 +454,28 @@
} else {
err.span_label(span, explanation);
}
+
+ if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+ let non_const_predicate = trait_ref.without_const();
+ let non_const_obligation = Obligation {
+ cause: obligation.cause.clone(),
+ param_env: obligation.param_env.without_const(),
+ predicate: non_const_predicate.to_predicate(tcx),
+ recursion_depth: obligation.recursion_depth,
+ };
+ if self.predicate_may_hold(&non_const_obligation) {
+ err.span_note(
+ span,
+ &format!(
+ "the trait `{}` is implemented for `{}`, \
+ but that implementation is not `const`",
+ non_const_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ );
+ }
+ }
+
if let Some((msg, span)) = type_def {
err.span_label(span, &msg);
}
@@ -435,18 +499,28 @@
err.span_label(enclosing_scope_span, s.as_str());
}
- self.suggest_dereferences(&obligation, &mut err, trait_ref);
- self.suggest_fn_call(&obligation, &mut err, trait_ref);
- self.suggest_remove_reference(&obligation, &mut err, trait_ref);
- self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref);
+ self.suggest_dereferences(&obligation, &mut err, trait_predicate);
+ self.suggest_fn_call(&obligation, &mut err, trait_predicate);
+ self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
+ self.suggest_semicolon_removal(
+ &obligation,
+ &mut err,
+ span,
+ trait_predicate,
+ );
self.note_version_mismatch(&mut err, &trait_ref);
self.suggest_remove_await(&obligation, &mut err);
if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
- self.suggest_await_before_try(&mut err, &obligation, trait_ref, span);
+ self.suggest_await_before_try(
+ &mut err,
+ &obligation,
+ trait_predicate,
+ span,
+ );
}
- if self.suggest_impl_trait(&mut err, span, &obligation, trait_ref) {
+ if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
err.emit();
return;
}
@@ -494,7 +568,7 @@
// which is somewhat confusing.
self.suggest_restricting_param_bound(
&mut err,
- trait_ref,
+ trait_predicate,
obligation.cause.body_id,
);
} else if !have_alt_message {
@@ -506,7 +580,7 @@
// Changing mutability doesn't make a difference to whether we have
// an `Unsize` impl (Fixes ICE in #71036)
if !is_unsize {
- self.suggest_change_mut(&obligation, &mut err, trait_ref);
+ self.suggest_change_mut(&obligation, &mut err, trait_predicate);
}
// If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -616,8 +690,6 @@
self.tcx.sess.source_map().guess_head_span(
self.tcx.hir().span_if_local(closure_def_id).unwrap(),
);
- let hir_id =
- self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
let mut err = struct_span_err!(
self.tcx.sess,
closure_span,
@@ -640,6 +712,10 @@
// Additional context information explaining why the closure only implements
// a particular trait.
if let Some(typeck_results) = self.in_progress_typeck_results {
+ let hir_id = self
+ .tcx
+ .hir()
+ .local_def_id_to_hir_id(closure_def_id.expect_local());
let typeck_results = typeck_results.borrow();
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
(ty::ClosureKind::FnOnce, Some((span, place))) => {
@@ -1082,18 +1158,23 @@
error: &MismatchedProjectionTypes<'tcx>,
);
- fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool;
+ fn fuzzy_match_tys(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ ignoring_lifetimes: bool,
+ ) -> Option<CandidateSimilarity>;
fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>;
fn find_similar_impl_candidates(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
- ) -> Vec<ty::TraitRef<'tcx>>;
+ ) -> Vec<ImplCandidate<'tcx>>;
fn report_similar_impl_candidates(
&self,
- impl_candidates: Vec<ty::TraitRef<'tcx>>,
+ impl_candidates: Vec<ImplCandidate<'tcx>>,
err: &mut DiagnosticBuilder<'_>,
);
@@ -1119,7 +1200,7 @@
fn mk_trait_obligation_with_new_self_ty(
&self,
param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_ref: ty::PolyTraitPredicate<'tcx>,
new_self_ty: Ty<'tcx>,
) -> PredicateObligation<'tcx>;
@@ -1170,7 +1251,7 @@
fn is_recursive_obligation(
&self,
- obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ obligated_types: &mut Vec<Ty<'tcx>>,
cause_code: &ObligationCauseCode<'tcx>,
) -> bool;
}
@@ -1302,7 +1383,7 @@
debug!(
"report_projection_error normalized_ty={:?} data.ty={:?}",
- normalized_ty, data.ty
+ normalized_ty, data.term,
);
let is_normalized_ty_expected = !matches!(
@@ -1312,18 +1393,16 @@
| ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType
);
-
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected,
normalized_ty,
- data.ty,
+ data.term,
) {
- values = Some(infer::ValuePairs::Types(ExpectedFound::new(
+ values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
- data.ty,
+ data.term,
)));
-
err_buf = error;
err = &err_buf;
}
@@ -1350,6 +1429,7 @@
.map(|id| (trait_assoc_item, id))
})
.and_then(|(trait_assoc_item, id)| {
+ let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
self.tcx.find_map_relevant_impl(
id,
proj.projection_ty.self_ty(),
@@ -1357,8 +1437,7 @@
self.tcx
.associated_items(did)
.in_definition_order()
- .filter(|assoc| assoc.ident == trait_assoc_item.ident)
- .next()
+ .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
},
)
})
@@ -1386,45 +1465,80 @@
});
}
- fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+ fn fuzzy_match_tys(
+ &self,
+ mut a: Ty<'tcx>,
+ mut b: Ty<'tcx>,
+ ignoring_lifetimes: bool,
+ ) -> Option<CandidateSimilarity> {
/// returns the fuzzy category of a given type, or None
/// if the type can be equated to any type.
- fn type_category(t: Ty<'_>) -> Option<u32> {
+ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
match t.kind() {
ty::Bool => Some(0),
ty::Char => Some(1),
ty::Str => Some(2),
- ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3),
- ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4),
+ ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did) => Some(2),
+ ty::Int(..)
+ | ty::Uint(..)
+ | ty::Float(..)
+ | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),
ty::Ref(..) | ty::RawPtr(..) => Some(5),
ty::Array(..) | ty::Slice(..) => Some(6),
ty::FnDef(..) | ty::FnPtr(..) => Some(7),
ty::Dynamic(..) => Some(8),
ty::Closure(..) => Some(9),
ty::Tuple(..) => Some(10),
- ty::Projection(..) => Some(11),
- ty::Param(..) => Some(12),
+ ty::Param(..) => Some(11),
+ ty::Projection(..) => Some(12),
ty::Opaque(..) => Some(13),
ty::Never => Some(14),
- ty::Adt(adt, ..) => match adt.adt_kind() {
- AdtKind::Struct => Some(15),
- AdtKind::Union => Some(16),
- AdtKind::Enum => Some(17),
- },
- ty::Generator(..) => Some(18),
- ty::Foreign(..) => Some(19),
- ty::GeneratorWitness(..) => Some(20),
+ ty::Adt(..) => Some(15),
+ ty::Generator(..) => Some(16),
+ ty::Foreign(..) => Some(17),
+ ty::GeneratorWitness(..) => Some(18),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
- match (type_category(a), type_category(b)) {
- (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) {
- (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
- _ => cat_a == cat_b,
- },
- // infer and error can be equated to all types
- _ => true,
+ let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
+ loop {
+ match t.kind() {
+ ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => {
+ t = *inner
+ }
+ _ => break t,
+ }
+ }
+ };
+
+ if !ignoring_lifetimes {
+ a = strip_references(a);
+ b = strip_references(b);
+ }
+
+ let cat_a = type_category(self.tcx, a)?;
+ let cat_b = type_category(self.tcx, b)?;
+ if a == b {
+ Some(CandidateSimilarity::Exact { ignoring_lifetimes })
+ } else if cat_a == cat_b {
+ match (a.kind(), b.kind()) {
+ (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
+ // Matching on references results in a lot of unhelpful
+ // suggestions, so let's just not do that for now.
+ //
+ // We still upgrade successful matches to `ignoring_lifetimes: true`
+ // to prioritize that impl.
+ (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {
+ self.fuzzy_match_tys(a, b, true).is_some()
+ }
+ _ => true,
+ }
+ .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })
+ } else if ignoring_lifetimes {
+ None
+ } else {
+ self.fuzzy_match_tys(a, b, true)
}
}
@@ -1440,58 +1554,25 @@
fn find_similar_impl_candidates(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
- ) -> Vec<ty::TraitRef<'tcx>> {
- // We simplify params and strip references here.
- //
- // This both removes a lot of unhelpful suggestions, e.g.
- // when searching for `&Foo: Trait` it doesn't suggestion `impl Trait for &Bar`,
- // while also suggesting impls for `&Foo` when we're looking for `Foo: Trait`.
- //
- // The second thing isn't necessarily always a good thing, but
- // any other simple setup results in a far worse output, so 🤷
- let simp = fast_reject::simplify_type(
- self.tcx,
- trait_ref.skip_binder().self_ty(),
- SimplifyParams::Yes,
- StripReferences::Yes,
- );
- let all_impls = self.tcx.all_impls(trait_ref.def_id());
+ ) -> Vec<ImplCandidate<'tcx>> {
+ self.tcx
+ .all_impls(trait_ref.def_id())
+ .filter_map(|def_id| {
+ if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
+ return None;
+ }
- match simp {
- Some(simp) => all_impls
- .filter_map(|def_id| {
- let imp = self.tcx.impl_trait_ref(def_id).unwrap();
- let imp_simp = fast_reject::simplify_type(
- self.tcx,
- imp.self_ty(),
- SimplifyParams::Yes,
- StripReferences::Yes,
- );
- if let Some(imp_simp) = imp_simp {
- if simp != imp_simp {
- return None;
- }
- }
- if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
- return None;
- }
- Some(imp)
- })
- .collect(),
- None => all_impls
- .filter_map(|def_id| {
- if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
- return None;
- }
- self.tcx.impl_trait_ref(def_id)
- })
- .collect(),
- }
+ let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+
+ self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false)
+ .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
+ })
+ .collect()
}
fn report_similar_impl_candidates(
&self,
- impl_candidates: Vec<ty::TraitRef<'tcx>>,
+ impl_candidates: Vec<ImplCandidate<'tcx>>,
err: &mut DiagnosticBuilder<'_>,
) {
if impl_candidates.is_empty() {
@@ -1515,13 +1596,24 @@
};
// Sort impl candidates so that ordering is consistent for UI tests.
- let mut normalized_impl_candidates =
- impl_candidates.iter().copied().map(normalize).collect::<Vec<String>>();
-
- // Sort before taking the `..end` range,
// because the ordering of `impl_candidates` may not be deterministic:
// https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
- normalized_impl_candidates.sort();
+ //
+ // Prefer more similar candidates first, then sort lexicographically
+ // by their normalized string representation.
+ let mut normalized_impl_candidates_and_similarities = impl_candidates
+ .into_iter()
+ .map(|ImplCandidate { trait_ref, similarity }| {
+ let normalized = normalize(trait_ref);
+ (similarity, normalized)
+ })
+ .collect::<Vec<_>>();
+ normalized_impl_candidates_and_similarities.sort();
+
+ let normalized_impl_candidates = normalized_impl_candidates_and_similarities
+ .into_iter()
+ .map(|(_, normalized)| normalized)
+ .collect::<Vec<_>>();
err.help(&format!(
"the following implementations were found:{}{}",
@@ -1537,7 +1629,7 @@
) -> Option<(String, Option<Span>)> {
match code {
ObligationCauseCode::BuiltinDerivedObligation(data) => {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
match self.get_parent_trait_ref(&data.parent_code) {
Some(t) => Some(t),
None => {
@@ -1590,21 +1682,20 @@
fn mk_trait_obligation_with_new_self_ty(
&self,
param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_ref: ty::PolyTraitPredicate<'tcx>,
new_self_ty: Ty<'tcx>,
) -> PredicateObligation<'tcx> {
assert!(!new_self_ty.has_escaping_bound_vars());
- let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef {
- substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]),
+ let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
+ ..tr.trait_ref
+ },
..*tr
});
- Obligation::new(
- ObligationCause::dummy(),
- param_env,
- trait_ref.without_const().to_predicate(self.tcx),
- )
+ Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx))
}
#[instrument(skip(self), level = "debug")]
@@ -1685,7 +1776,11 @@
return;
}
- let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+ let impl_candidates = self
+ .find_similar_impl_candidates(trait_ref)
+ .into_iter()
+ .map(|candidate| candidate.trait_ref)
+ .collect();
let mut err = self.emit_inference_failure_err(
body_id,
span,
@@ -1801,11 +1896,11 @@
}
ty::PredicateKind::Projection(data) => {
let self_ty = data.projection_ty.self_ty();
- let ty = data.ty;
+ let term = data.term;
if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
- if self_ty.needs_infer() && ty.needs_infer() {
+ if self_ty.needs_infer() && term.needs_infer() {
// We do this for the `foo.collect()?` case to produce a suggestion.
let mut err = self.emit_inference_failure_err(
body_id,
@@ -1958,7 +2053,7 @@
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
let infcx = self.infcx;
- self.var_map.entry(ty).or_insert_with(|| {
+ *self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
span: DUMMY_SP,
@@ -2005,6 +2100,7 @@
self.note_obligation_cause_code(
err,
&obligation.predicate,
+ obligation.param_env,
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
@@ -2148,11 +2244,11 @@
fn is_recursive_obligation(
&self,
- obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ obligated_types: &mut Vec<Ty<'tcx>>,
cause_code: &ObligationCauseCode<'tcx>,
) -> bool {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
let self_ty = parent_trait_ref.skip_binder().self_ty();
if obligated_types.iter().any(|ot| ot == &self_ty) {
return true;
@@ -2182,12 +2278,6 @@
}
impl<'v> Visitor<'v> for FindTypeParam {
- type Map = rustc_hir::intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::None
- }
-
fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
// Skip where-clauses, to avoid suggesting indirection for type parameters found there.
}
@@ -2247,7 +2337,7 @@
spans
.iter()
.flat_map(|&span| {
- vec![
+ [
(span.shrink_to_lo(), "Box<".to_string()),
(span.shrink_to_hi(), ">".to_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 1540725..6c8a08c 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
@@ -56,7 +56,7 @@
trait_ref.substs.types().skip(1),
impl_trait_ref.substs.types().skip(1),
)
- .all(|(u, v)| self.fuzzy_match_tys(u, v))
+ .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
{
fuzzy_match_impls.push(def_id);
}
@@ -77,7 +77,7 @@
/// Used to set on_unimplemented's `ItemContext`
/// to be the enclosing (async) block/function/closure
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
- let hir = &self.tcx.hir();
+ let hir = self.tcx.hir();
let node = hir.find(hir_id)?;
match &node {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
@@ -211,7 +211,8 @@
let type_string = self.tcx.type_of(def.did).to_string();
flags.push((sym::_Self, Some(format!("[{}]", type_string))));
- let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+ let len =
+ len.val().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
let string = match len {
Some(n) => format!("[{}; {}]", type_string, n),
None => format!("[{}; _]", type_string),
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 0f27671..7df880a7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -48,7 +48,7 @@
fn suggest_restricting_param_bound(
&self,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
body_id: hir::HirId,
);
@@ -56,7 +56,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
);
fn get_closure_name(
@@ -70,14 +70,14 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
);
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
has_custom_message: bool,
) -> bool;
@@ -85,7 +85,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
);
fn suggest_remove_await(
@@ -98,7 +98,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
);
fn suggest_semicolon_removal(
@@ -106,7 +106,7 @@
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
span: Span,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
);
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
@@ -116,7 +116,7 @@
err: &mut DiagnosticBuilder<'_>,
span: Span,
obligation: &PredicateObligation<'tcx>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
fn point_at_returns_when_relevant(
@@ -154,7 +154,7 @@
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
inner_generator_body: Option<&hir::Body<'tcx>>,
outer_generator: Option<DefId>,
- trait_ref: ty::TraitRef<'tcx>,
+ trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
@@ -165,8 +165,9 @@
&self,
err: &mut DiagnosticBuilder<'_>,
predicate: &T,
+ param_env: ty::ParamEnv<'tcx>,
cause_code: &ObligationCauseCode<'tcx>,
- obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
) where
T: fmt::Display;
@@ -178,7 +179,7 @@
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
span: Span,
);
}
@@ -204,7 +205,7 @@
err: &mut DiagnosticBuilder<'_>,
fn_sig: Option<&hir::FnSig<'_>>,
projection: Option<&ty::ProjectionTy<'_>>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
) {
// When we are dealing with a trait, `super_traits` will be `Some`:
@@ -257,9 +258,9 @@
// The type param `T: Trait` we will suggest to introduce.
let type_param = format!("{}: {}", type_param_name, bound_str);
- // FIXME: modify the `trait_ref` instead of string shenanigans.
+ // FIXME: modify the `trait_pred` instead of string shenanigans.
// Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
- let pred = trait_ref.without_const().to_predicate(tcx).to_string();
+ let pred = trait_pred.to_predicate(tcx).to_string();
let pred = pred.replace(&impl_trait_str, &type_param_name);
let mut sugg = vec![
// Find the last of the generic parameters contained within the span of
@@ -301,19 +302,19 @@
.find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
super_traits,
) {
- (_, None) => predicate_constraint(
- generics,
- trait_ref.without_const().to_predicate(tcx).to_string(),
+ (_, None) => predicate_constraint(generics, trait_pred.to_predicate(tcx).to_string()),
+ (None, Some((ident, []))) => (
+ ident.span.shrink_to_hi(),
+ format!(": {}", trait_pred.print_modifiers_and_trait_path()),
),
- (None, Some((ident, []))) => {
- (ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
- }
- (_, Some((_, [.., bounds]))) => {
- (bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path()))
- }
- (Some(_), Some((_, []))) => {
- (generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
- }
+ (_, Some((_, [.., bounds]))) => (
+ bounds.span().shrink_to_hi(),
+ format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
+ ),
+ (Some(_), Some((_, []))) => (
+ generics.span.shrink_to_hi(),
+ format!(": {}", trait_pred.print_modifiers_and_trait_path()),
+ ),
};
err.span_suggestion_verbose(
@@ -329,10 +330,10 @@
fn suggest_restricting_param_bound(
&self,
mut err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
body_id: hir::HirId,
) {
- let self_ty = trait_ref.skip_binder().self_ty();
+ let self_ty = trait_pred.skip_binder().self_ty();
let (param_ty, projection) = match self_ty.kind() {
ty::Param(_) => (true, None),
ty::Projection(projection) => (false, Some(projection)),
@@ -358,7 +359,7 @@
err,
None,
projection,
- trait_ref,
+ trait_pred,
Some((ident, bounds)),
);
return;
@@ -372,7 +373,7 @@
assert!(param_ty);
// Restricting `Self` for a single method.
suggest_restriction(
- self.tcx, &generics, "`Self`", err, None, projection, trait_ref, None,
+ self.tcx, &generics, "`Self`", err, None, projection, trait_pred, None,
);
return;
}
@@ -398,7 +399,7 @@
err,
Some(fn_sig),
projection,
- trait_ref,
+ trait_pred,
None,
);
return;
@@ -417,7 +418,7 @@
err,
None,
projection,
- trait_ref,
+ trait_pred,
None,
);
return;
@@ -442,15 +443,16 @@
{
// Missing generic type parameter bound.
let param_name = self_ty.to_string();
- let constraint =
- with_no_trimmed_paths(|| trait_ref.print_only_trait_path().to_string());
+ let constraint = with_no_trimmed_paths(|| {
+ trait_pred.print_modifiers_and_trait_path().to_string()
+ });
if suggest_constraining_type_param(
self.tcx,
generics,
&mut err,
¶m_name,
&constraint,
- Some(trait_ref.def_id()),
+ Some(trait_pred.def_id()),
) {
return;
}
@@ -471,7 +473,7 @@
}) if !param_ty => {
// Missing generic type parameter bound.
let param_name = self_ty.to_string();
- let constraint = trait_ref.print_only_trait_path().to_string();
+ let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) {
return;
}
@@ -481,7 +483,7 @@
_ => {}
}
- hir_id = self.tcx.hir().get_parent_item(hir_id);
+ hir_id = self.tcx.hir().local_def_id_to_hir_id(self.tcx.hir().get_parent_item(hir_id));
}
}
@@ -492,7 +494,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
// It only make sense when suggesting dereferences for arguments
let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
@@ -505,13 +507,13 @@
let param_env = obligation.param_env;
let body_id = obligation.cause.body_id;
let span = obligation.cause.span;
- let real_trait_ref = match &*code {
+ let real_trait_pred = match &*code {
ObligationCauseCode::ImplDerivedObligation(cause)
| ObligationCauseCode::DerivedObligation(cause)
- | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref,
- _ => trait_ref,
+ | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred,
+ _ => trait_pred,
};
- let real_ty = match real_trait_ref.self_ty().no_bound_vars() {
+ let real_ty = match real_trait_pred.self_ty().no_bound_vars() {
Some(ty) => ty,
None => return,
};
@@ -522,7 +524,7 @@
// Re-add the `&`
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
let obligation =
- self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty);
+ self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
}) {
if steps > 0 {
@@ -589,9 +591,9 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
- let self_ty = match trait_ref.self_ty().no_bound_vars() {
+ let self_ty = match trait_pred.self_ty().no_bound_vars() {
None => return,
Some(ty) => ty,
};
@@ -611,7 +613,7 @@
};
let new_obligation =
- self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_ref, output_ty);
+ self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
match self.evaluate_obligation(&new_obligation) {
Ok(
@@ -682,7 +684,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- poly_trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ poly_trait_pred: ty::PolyTraitPredicate<'tcx>,
has_custom_message: bool,
) -> bool {
let span = obligation.cause.span;
@@ -715,24 +717,18 @@
let param_env = obligation.param_env;
// Try to apply the original trait binding obligation by borrowing.
- let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
blacklist: &[DefId]|
-> bool {
- if blacklist.contains(&old_ref.def_id()) {
+ if blacklist.contains(&old_pred.def_id()) {
return false;
}
- let orig_ty = old_ref.self_ty().skip_binder();
+ let orig_ty = old_pred.self_ty().skip_binder();
let mk_result = |new_ty| {
- let new_ref = old_ref.rebind(ty::TraitRef::new(
- old_ref.def_id(),
- self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]),
- ));
- self.predicate_must_hold_modulo_regions(&Obligation::new(
- ObligationCause::dummy(),
- param_env,
- new_ref.without_const().to_predicate(self.tcx),
- ))
+ let obligation =
+ self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
+ self.predicate_must_hold_modulo_regions(&obligation)
};
let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
@@ -748,7 +744,7 @@
let msg = format!(
"the trait bound `{}: {}` is not satisfied",
orig_ty,
- old_ref.print_only_trait_path(),
+ old_pred.print_modifiers_and_trait_path(),
);
if has_custom_message {
err.note(&msg);
@@ -764,7 +760,7 @@
span,
&format!(
"expected an implementor of trait `{}`",
- old_ref.print_only_trait_path(),
+ old_pred.print_modifiers_and_trait_path(),
),
);
@@ -806,11 +802,11 @@
};
if let ObligationCauseCode::ImplDerivedObligation(obligation) = code {
- try_borrowing(obligation.parent_trait_ref, &[])
+ try_borrowing(obligation.parent_trait_pred, &[])
} else if let ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ItemObligation(_) = code
{
- try_borrowing(*poly_trait_ref, &never_suggest_borrow)
+ try_borrowing(poly_trait_pred, &never_suggest_borrow)
} else {
false
}
@@ -822,7 +818,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
let span = obligation.cause.span;
@@ -834,45 +830,44 @@
return;
}
- let mut suggested_ty = match trait_ref.self_ty().no_bound_vars() {
+ let mut suggested_ty = match trait_pred.self_ty().no_bound_vars() {
Some(ty) => ty,
None => return,
};
for refs_remaining in 0..refs_number {
- if let ty::Ref(_, inner_ty, _) = suggested_ty.kind() {
- suggested_ty = inner_ty;
+ let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
+ break;
+ };
+ suggested_ty = *inner_ty;
- let new_obligation = self.mk_trait_obligation_with_new_self_ty(
- obligation.param_env,
- trait_ref,
- suggested_ty,
+ let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env,
+ trait_pred,
+ suggested_ty,
+ );
+
+ if self.predicate_may_hold(&new_obligation) {
+ let sp = self
+ .tcx
+ .sess
+ .source_map()
+ .span_take_while(span, |c| c.is_whitespace() || *c == '&');
+
+ let remove_refs = refs_remaining + 1;
+
+ let msg = if remove_refs == 1 {
+ "consider removing the leading `&`-reference".to_string()
+ } else {
+ format!("consider removing {} leading `&`-references", remove_refs)
+ };
+
+ err.span_suggestion_short(
+ sp,
+ &msg,
+ String::new(),
+ Applicability::MachineApplicable,
);
-
- if self.predicate_may_hold(&new_obligation) {
- let sp = self
- .tcx
- .sess
- .source_map()
- .span_take_while(span, |c| c.is_whitespace() || *c == '&');
-
- let remove_refs = refs_remaining + 1;
-
- let msg = if remove_refs == 1 {
- "consider removing the leading `&`-reference".to_string()
- } else {
- format!("consider removing {} leading `&`-references", remove_refs)
- };
-
- err.span_suggestion_short(
- sp,
- &msg,
- String::new(),
- Applicability::MachineApplicable,
- );
- break;
- }
- } else {
break;
}
}
@@ -942,7 +937,7 @@
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
let points_at_arg = matches!(
obligation.cause.code(),
@@ -957,14 +952,15 @@
// Do not suggest removal of borrow from type arguments.
return;
}
- let trait_ref = self.resolve_vars_if_possible(trait_ref);
- if trait_ref.has_infer_types_or_consts() {
+ let trait_pred = self.resolve_vars_if_possible(trait_pred);
+ if trait_pred.has_infer_types_or_consts() {
// Do not ICE while trying to find if a reborrow would succeed on a trait with
// unresolved bindings.
return;
}
- if let ty::Ref(region, t_type, mutability) = *trait_ref.skip_binder().self_ty().kind() {
+ if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
+ {
if region.is_late_bound() || t_type.has_escaping_bound_vars() {
// Avoid debug assertion in `mk_obligation_for_def_id`.
//
@@ -981,7 +977,7 @@
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
obligation.param_env,
- trait_ref,
+ trait_pred,
suggested_ty,
);
let suggested_ty_would_satisfy_obligation = self
@@ -1003,9 +999,9 @@
} else {
err.note(&format!(
"`{}` is implemented for `{:?}`, but not for `{:?}`",
- trait_ref.print_only_trait_path(),
+ trait_pred.print_modifiers_and_trait_path(),
suggested_ty,
- trait_ref.skip_binder().self_ty(),
+ trait_pred.skip_binder().self_ty(),
));
}
}
@@ -1018,7 +1014,7 @@
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
span: Span,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
let is_empty_tuple =
|ty: ty::Binder<'tcx, Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty());
@@ -1034,7 +1030,7 @@
if let hir::ExprKind::Block(blk, _) = &body.value.kind {
if sig.decl.output.span().overlaps(span)
&& blk.expr.is_none()
- && is_empty_tuple(trait_ref.self_ty())
+ && is_empty_tuple(trait_pred.self_ty())
{
// FIXME(estebank): When encountering a method with a trait
// bound not satisfied in the return type with a body that has
@@ -1070,7 +1066,7 @@
err: &mut DiagnosticBuilder<'_>,
span: Span,
obligation: &PredicateObligation<'tcx>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
match obligation.cause.code().peel_derives() {
// Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
@@ -1089,8 +1085,8 @@
return false;
};
let body = hir.body(*body_id);
- let trait_ref = self.resolve_vars_if_possible(trait_ref);
- let ty = trait_ref.skip_binder().self_ty();
+ let trait_pred = self.resolve_vars_if_possible(trait_pred);
+ let ty = trait_pred.skip_binder().self_ty();
let is_object_safe = match ty.kind() {
ty::Dynamic(predicates, _) => {
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
@@ -1103,9 +1099,7 @@
_ => return false,
};
- let ret_ty = if let hir::FnRetTy::Return(ret_ty) = sig.decl.output {
- ret_ty
- } else {
+ let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
return false;
};
@@ -1172,7 +1166,7 @@
};
let sm = self.tcx.sess.source_map();
- let snippet = if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = (
+ let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = (
// Verify that we're dealing with a return `dyn Trait`
ret_ty.span.overlaps(span),
&ret_ty.kind,
@@ -1180,9 +1174,7 @@
// If any of the return types does not conform to the trait, then we can't
// suggest `impl Trait` nor trait objects: it is a type mismatch error.
all_returns_conform_to_trait,
- ) {
- snippet
- } else {
+ ) else {
return false;
};
err.code(error_code!(E0746));
@@ -1226,7 +1218,7 @@
.returns
.iter()
.flat_map(|expr| {
- vec![
+ [
(expr.span.shrink_to_lo(), "Box::new(".to_string()),
(expr.span.shrink_to_hi(), ")".to_string()),
]
@@ -1327,9 +1319,9 @@
trait_ref.rebind(sig).to_string()
}
- let argument_kind = match expected_ref.skip_binder().substs.type_at(0) {
- t if t.is_closure() => "closure",
- t if t.is_generator() => "generator",
+ let argument_kind = match expected_ref.skip_binder().self_ty().kind() {
+ ty::Closure(..) => "closure",
+ ty::Generator(..) => "generator",
_ => "function",
};
let mut err = struct_span_err!(
@@ -1368,7 +1360,7 @@
err.span_suggestion(
span,
"use the fully qualified path to an implementation",
- format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident),
+ format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name),
Applicability::HasPlaceholders,
);
}
@@ -1456,7 +1448,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), Some(p.self_ty())),
_ => (None, None),
};
let mut generator = None;
@@ -1474,11 +1466,11 @@
ObligationCauseCode::DerivedObligation(derived_obligation)
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
| ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
- let ty = derived_obligation.parent_trait_ref.skip_binder().self_ty();
+ let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
debug!(
"maybe_note_obligation_cause_for_async_await: \
parent_trait_ref={:?} self_ty.kind={:?}",
- derived_obligation.parent_trait_ref,
+ derived_obligation.parent_trait_pred,
ty.kind()
);
@@ -1496,7 +1488,7 @@
seen_upvar_tys_infer_tuple = true;
}
_ if generator.is_none() => {
- trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
+ trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder());
target_ty = Some(ty);
}
_ => {}
@@ -1559,7 +1551,7 @@
// `erase_late_bound_regions`.
let ty_erased = self.tcx.erase_late_bound_regions(ty);
let ty_erased = self.tcx.erase_regions(ty_erased);
- let eq = ty::TyS::same_type(ty_erased, target_ty_erased);
+ let eq = ty_erased == target_ty_erased;
debug!(
"maybe_note_obligation_cause_for_async_await: ty_erased={:?} \
target_ty_erased={:?} eq={:?}",
@@ -1601,7 +1593,7 @@
if let Some(cause) =
typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
|ty::GeneratorInteriorTypeCause { ty, .. }| {
- ty_matches(typeck_results.generator_interior_types.rebind(ty))
+ ty_matches(typeck_results.generator_interior_types.rebind(*ty))
},
)
{
@@ -1652,7 +1644,7 @@
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
inner_generator_body: Option<&hir::Body<'tcx>>,
outer_generator: Option<DefId>,
- trait_ref: ty::TraitRef<'tcx>,
+ trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
@@ -1672,7 +1664,7 @@
// not implemented.
let hir = self.tcx.hir();
let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
- self.tcx.get_diagnostic_name(trait_ref.def_id)
+ self.tcx.get_diagnostic_name(trait_pred.def_id())
{
let (trait_name, trait_verb) =
if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
@@ -1714,7 +1706,7 @@
format!("is not {}", trait_name)
} else {
- format!("does not implement `{}`", trait_ref.print_only_trait_path())
+ format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
};
let mut explain_yield = |interior_span: Span,
@@ -1895,6 +1887,7 @@
self.note_obligation_cause_code(
err,
&obligation.predicate,
+ obligation.param_env,
next_code.unwrap(),
&mut Vec::new(),
&mut Default::default(),
@@ -1905,8 +1898,9 @@
&self,
err: &mut DiagnosticBuilder<'_>,
predicate: &T,
+ param_env: ty::ParamEnv<'tcx>,
cause_code: &ObligationCauseCode<'tcx>,
- obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
) where
T: fmt::Display,
@@ -1934,7 +1928,8 @@
| ObligationCauseCode::AwaitableExpr(_)
| ObligationCauseCode::ForLoopIterator
| ObligationCauseCode::QuestionMark
- | ObligationCauseCode::LetElse => {}
+ | ObligationCauseCode::LetElse
+ | ObligationCauseCode::CheckAssociatedTypeBounds { .. } => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
@@ -2135,7 +2130,7 @@
err.note("shared static variables must have a type that implements `Sync`");
}
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
let ty = parent_trait_ref.skip_binder().self_ty();
if parent_trait_ref.references_error() {
err.cancel();
@@ -2150,7 +2145,8 @@
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
*data.parent_code
{
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+ let parent_trait_ref =
+ self.resolve_vars_if_possible(data.parent_trait_pred);
let ty = parent_trait_ref.skip_binder().self_ty();
matches!(ty.kind(), ty::Generator(..))
|| matches!(ty.kind(), ty::Closure(..))
@@ -2173,13 +2169,14 @@
obligated_types.push(ty);
- let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+ let parent_predicate = parent_trait_ref.to_predicate(tcx);
if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
&parent_predicate,
+ param_env,
&data.parent_code,
obligated_types,
seen_requirements,
@@ -2190,6 +2187,7 @@
self.note_obligation_cause_code(
err,
&parent_predicate,
+ param_env,
&cause_code.peel_derives(),
obligated_types,
seen_requirements,
@@ -2198,17 +2196,18 @@
}
}
ObligationCauseCode::ImplDerivedObligation(ref data) => {
- let mut parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
- let parent_def_id = parent_trait_ref.def_id();
+ let mut parent_trait_pred = self.resolve_vars_if_possible(data.parent_trait_pred);
+ parent_trait_pred.remap_constness_diag(param_env);
+ let parent_def_id = parent_trait_pred.def_id();
let msg = format!(
"required because of the requirements on the impl of `{}` for `{}`",
- parent_trait_ref.print_only_trait_path(),
- parent_trait_ref.skip_binder().self_ty()
+ parent_trait_pred.print_modifiers_and_trait_path(),
+ parent_trait_pred.skip_binder().self_ty()
);
let mut candidates = vec![];
self.tcx.for_each_relevant_impl(
parent_def_id,
- parent_trait_ref.self_ty().skip_binder(),
+ parent_trait_pred.self_ty().skip_binder(),
|impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { .. }),
@@ -2237,21 +2236,21 @@
_ => err.note(&msg),
};
- let mut parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+ let mut parent_predicate = parent_trait_pred.to_predicate(tcx);
let mut data = data;
let mut count = 0;
seen_requirements.insert(parent_def_id);
while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
// Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
- let child_trait_ref = self.resolve_vars_if_possible(child.parent_trait_ref);
- let child_def_id = child_trait_ref.def_id();
+ let child_trait_pred = self.resolve_vars_if_possible(child.parent_trait_pred);
+ let child_def_id = child_trait_pred.def_id();
if seen_requirements.insert(child_def_id) {
break;
}
count += 1;
data = child;
- parent_predicate = child_trait_ref.without_const().to_predicate(tcx);
- parent_trait_ref = child_trait_ref;
+ parent_predicate = child_trait_pred.to_predicate(tcx);
+ parent_trait_pred = child_trait_pred;
}
if count > 0 {
err.note(&format!(
@@ -2261,8 +2260,8 @@
));
err.note(&format!(
"required because of the requirements on the impl of `{}` for `{}`",
- parent_trait_ref.print_only_trait_path(),
- parent_trait_ref.skip_binder().self_ty()
+ parent_trait_pred.print_modifiers_and_trait_path(),
+ parent_trait_pred.skip_binder().self_ty()
));
}
// #74711: avoid a stack overflow
@@ -2270,6 +2269,7 @@
self.note_obligation_cause_code(
err,
&parent_predicate,
+ param_env,
&data.parent_code,
obligated_types,
seen_requirements,
@@ -2277,13 +2277,14 @@
});
}
ObligationCauseCode::DerivedObligation(ref data) => {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
- let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
+ let parent_predicate = parent_trait_ref.to_predicate(tcx);
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
&parent_predicate,
+ param_env,
&data.parent_code,
obligated_types,
seen_requirements,
@@ -2301,7 +2302,7 @@
{
let in_progress_typeck_results =
self.in_progress_typeck_results.map(|t| t.borrow());
- let parent_id = hir.local_def_id(hir.get_parent_item(arg_hir_id));
+ let parent_id = hir.get_parent_item(arg_hir_id);
let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
Some(t) if t.hir_owner == parent_id => t,
_ => self.tcx.typeck(parent_id),
@@ -2322,7 +2323,10 @@
if let Some(Node::Expr(hir::Expr {
kind:
hir::ExprKind::Call(hir::Expr { span, .. }, _)
- | hir::ExprKind::MethodCall(_, span, ..),
+ | hir::ExprKind::MethodCall(
+ hir::PathSegment { ident: Ident { span, .. }, .. },
+ ..,
+ ),
..
})) = hir.find(call_hir_id)
{
@@ -2334,6 +2338,7 @@
self.note_obligation_cause_code(
err,
predicate,
+ param_env,
&parent_code,
obligated_types,
seen_requirements,
@@ -2424,15 +2429,15 @@
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
span: Span,
) {
debug!(
- "suggest_await_before_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
+ "suggest_await_before_try: obligation={:?}, span={:?}, trait_pred={:?}, trait_pred_self_ty={:?}",
obligation,
span,
- trait_ref,
- trait_ref.self_ty()
+ trait_pred,
+ trait_pred.self_ty()
);
let body_hir_id = obligation.cause.body_id;
let item_id = self.tcx.hir().get_parent_node(body_hir_id);
@@ -2442,7 +2447,7 @@
if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
- let self_ty = self.resolve_vars_if_possible(trait_ref.self_ty());
+ let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
// Do not check on infer_types to avoid panic in evaluate_obligation.
if self_ty.has_infer_types() {
@@ -2462,8 +2467,8 @@
let projection_ty = ty::ProjectionTy {
// `T`
substs: self.tcx.mk_substs_trait(
- trait_ref.self_ty().skip_binder(),
- self.fresh_substs_for_item(span, item_def_id),
+ trait_pred.self_ty().skip_binder(),
+ &self.fresh_substs_for_item(span, item_def_id)[1..],
),
// `Future::Output`
item_def_id,
@@ -2487,8 +2492,8 @@
);
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
obligation.param_env,
- trait_ref,
- normalized_ty,
+ trait_pred,
+ normalized_ty.ty().unwrap(),
);
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
if self.predicate_may_hold(&try_obligation)
@@ -2519,12 +2524,6 @@
}
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
- type Map = hir::intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
// Visit every expression to detect `return` paths, either through the function's tail
// expression or `return` statements. We walk all nodes to find `return` statements, but
@@ -2581,12 +2580,6 @@
}
impl<'v> Visitor<'v> for AwaitsVisitor {
- type Map = hir::intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind {
self.awaits.push(id)
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 42e3f0d..1989184 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -200,7 +200,7 @@
debug!(?normalized_ty);
- normalized_ty
+ normalized_ty.ty().unwrap()
}
fn register_predicate_obligation(
@@ -538,7 +538,7 @@
Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend(
- uv.substs(infcx.tcx)
+ uv.substs
.iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
@@ -562,7 +562,7 @@
//
// Let's just see where this breaks :shrug:
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
- (c1.val, c2.val)
+ (c1.val(), c2.val())
{
if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
return ProcessResult::Changed(vec![]);
@@ -572,18 +572,18 @@
let stalled_on = &mut pending_obligation.stalled_on;
- let mut evaluate = |c: &'tcx Const<'tcx>| {
- if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
+ let mut evaluate = |c: Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
match self.selcx.infcx().const_eval_resolve(
obligation.param_env,
unevaluated,
Some(obligation.cause.span),
) {
- Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)),
+ Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty())),
Err(ErrorHandled::TooGeneric) => {
stalled_on.extend(
unevaluated
- .substs(tcx)
+ .substs
.iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
@@ -654,7 +654,7 @@
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx();
- if obligation.predicate.is_known_global() {
+ if obligation.predicate.is_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if infcx.predicate_must_hold_considering_regions(obligation) {
@@ -708,7 +708,7 @@
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx();
- if obligation.predicate.is_global(tcx) {
+ if obligation.predicate.is_global() {
// 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) {
@@ -756,15 +756,14 @@
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(move |arg| {
- let mut walker = arg.walk(tcx);
+ .flat_map(|arg| {
+ let mut walker = arg.walk();
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 a8f2698..2927e64 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -291,7 +291,7 @@
//
// In any case, in practice, typeck constructs all the
// parameter environments once for every fn as it goes,
- // and errors will get reported then; so after typeck we
+ // and errors will get reported then; so outside of type inference we
// can be sure that no errors should occur.
debug!(
@@ -465,7 +465,7 @@
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.definitely_needs_subst(tcx));
+ predicates.retain(|predicate| !predicate.needs_subst());
let result = impossible_predicates(tcx, predicates);
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 4e84849..7818053 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -89,7 +89,7 @@
.filter(|item| item.kind == ty::AssocKind::Fn)
.filter_map(|item| {
object_safety_violation_for_method(tcx, trait_def_id, &item)
- .map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span))
+ .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
})
.filter(|violation| {
if let ObjectSafetyViolation::Method(
@@ -125,7 +125,10 @@
tcx.associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Const)
- .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
+ .map(|item| {
+ let ident = item.ident(tcx);
+ ObjectSafetyViolation::AssocConst(ident.name, ident.span)
+ }),
);
violations.extend(
@@ -133,7 +136,10 @@
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
- .map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)),
+ .map(|item| {
+ let ident = item.ident(tcx);
+ ObjectSafetyViolation::GAT(ident.name, ident.span)
+ }),
);
debug!(
@@ -274,7 +280,7 @@
(predicate, sp): (ty::Predicate<'tcx>, Span),
) -> Option<Span> {
let self_ty = tcx.types.self_param;
- let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into());
+ let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
@@ -367,15 +373,15 @@
(MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node
.fn_decl()
.and_then(|decl| decl.inputs.get(arg + 1))
- .map_or(method.ident.span, |arg| arg.span),
+ .map_or(method.ident(tcx).span, |arg| arg.span),
(MethodViolationCode::UndispatchableReceiver, Some(node)) => node
.fn_decl()
.and_then(|decl| decl.inputs.get(0))
- .map_or(method.ident.span, |arg| arg.span),
+ .map_or(method.ident(tcx).span, |arg| arg.span),
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
- node.fn_decl().map_or(method.ident.span, |decl| decl.output.span())
+ node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
}
- _ => method.ident.span,
+ _ => method.ident(tcx).span,
};
(v, span)
})
@@ -404,10 +410,10 @@
);
// Get the span pointing at where the `self` receiver should be.
let sm = tcx.sess.source_map();
- let self_span = method.ident.span.to(tcx
+ let self_span = method.ident(tcx).span.to(tcx
.hir()
.span_if_local(method.def_id)
- .unwrap_or_else(|| sm.next_point(method.ident.span))
+ .unwrap_or_else(|| sm.next_point(method.ident(tcx).span))
.shrink_to_hi());
let self_span = sm.span_through_char(self_span, '(').shrink_to_hi();
return Some(MethodViolationCode::StaticMethod(
@@ -571,7 +577,7 @@
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
super_trait_ref.map_bound(|super_trait_ref| {
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
- ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
+ term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
item_def_id: item.def_id,
substs: super_trait_ref.substs,
})
@@ -768,9 +774,6 @@
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() {
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 4840995..b05dbbe 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -19,6 +19,7 @@
pub label: Option<OnUnimplementedFormatString>,
pub note: Option<OnUnimplementedFormatString>,
pub enclosing_scope: Option<OnUnimplementedFormatString>,
+ pub append_const_msg: Option<Option<Symbol>>,
}
#[derive(Default)]
@@ -27,6 +28,11 @@
pub label: Option<String>,
pub note: Option<String>,
pub enclosing_scope: Option<String>,
+ /// Append a message for `~const Trait` errors. `None` means not requested and
+ /// should fallback to a generic message, `Some(None)` suggests using the default
+ /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+ /// default one..
+ pub append_const_msg: Option<Option<Symbol>>,
}
fn parse_error(
@@ -56,6 +62,10 @@
let mut errored = false;
let mut item_iter = items.iter();
+ let parse_value = |value_str| {
+ OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+ };
+
let condition = if is_root {
None
} else {
@@ -80,7 +90,14 @@
None,
)
})?;
- attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true);
+ attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
+ if let Some(symbol) = item.value_str() {
+ if parse_value(symbol).is_err() {
+ errored = true;
+ }
+ }
+ true
+ });
Some(cond.clone())
};
@@ -89,10 +106,7 @@
let mut note = None;
let mut enclosing_scope = None;
let mut subcommands = vec![];
-
- let parse_value = |value_str| {
- OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
- };
+ let mut append_const_msg = None;
for item in item_iter {
if item.has_name(sym::message) && message.is_none() {
@@ -131,6 +145,14 @@
}
continue;
}
+ } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+ if let Some(msg) = item.value_str() {
+ append_const_msg = Some(Some(msg));
+ continue;
+ } else if item.is_word() {
+ append_const_msg = Some(None);
+ continue;
+ }
}
// nothing found
@@ -153,6 +175,7 @@
label,
note,
enclosing_scope,
+ append_const_msg,
})
}
}
@@ -183,6 +206,7 @@
)?),
note: None,
enclosing_scope: None,
+ append_const_msg: None,
}))
} else {
return Err(ErrorReported);
@@ -201,8 +225,12 @@
let mut label = None;
let mut note = None;
let mut enclosing_scope = None;
+ let mut append_const_msg = None;
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
+ let options_map: FxHashMap<Symbol, String> =
+ options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
+
for command in self.subcommands.iter().chain(Some(self)).rev() {
if let Some(ref condition) = command.condition {
if !attr::eval_condition(
@@ -211,7 +239,11 @@
Some(tcx.features()),
&mut |c| {
c.ident().map_or(false, |ident| {
- options.contains(&(ident.name, c.value_str().map(|s| s.to_string())))
+ let value = c.value_str().map(|s| {
+ OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
+ });
+
+ options.contains(&(ident.name, value))
})
},
) {
@@ -235,15 +267,16 @@
if let Some(ref enclosing_scope_) = command.enclosing_scope {
enclosing_scope = Some(enclosing_scope_.clone());
}
+
+ append_const_msg = command.append_const_msg.clone();
}
- let options: FxHashMap<Symbol, String> =
- options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
OnUnimplementedNote {
- label: label.map(|l| l.format(tcx, trait_ref, &options)),
- message: message.map(|m| m.format(tcx, trait_ref, &options)),
- note: note.map(|n| n.format(tcx, trait_ref, &options)),
- enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
+ label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
+ message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
+ note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
+ enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
+ append_const_msg,
}
}
}
@@ -276,17 +309,23 @@
Piece::String(_) => (), // Normal string, no need to check it
Piece::NextArgument(a) => match a.position {
// `{Self}` is allowed
- Position::ArgumentNamed(s) if s == kw::SelfUpper => (),
+ Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
// `{ThisTraitsName}` is allowed
- Position::ArgumentNamed(s) if s == name => (),
+ Position::ArgumentNamed(s, _) if s == name => (),
// `{from_method}` is allowed
- Position::ArgumentNamed(s) if s == sym::from_method => (),
+ Position::ArgumentNamed(s, _) if s == sym::from_method => (),
// `{from_desugaring}` is allowed
- Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
+ Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (),
// `{ItemContext}` is allowed
- Position::ArgumentNamed(s) if s == sym::ItemContext => (),
+ Position::ArgumentNamed(s, _) if s == sym::ItemContext => (),
+ // `{integral}` and `{integer}` and `{float}` are allowed
+ Position::ArgumentNamed(s, _)
+ if s == sym::integral || s == sym::integer_ || s == sym::float =>
+ {
+ ()
+ }
// So is `{A}` if A is a type parameter
- Position::ArgumentNamed(s) => {
+ Position::ArgumentNamed(s, _) => {
match generics.params.iter().find(|param| param.name == s) {
Some(_) => (),
None => {
@@ -353,7 +392,7 @@
.map(|p| match p {
Piece::String(s) => s,
Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s) => match generic_map.get(&s) {
+ Position::ArgumentNamed(s, _) => match generic_map.get(&s) {
Some(val) => val,
None if s == name => &trait_str,
None => {
@@ -364,6 +403,12 @@
&empty_string
} else if s == sym::ItemContext {
&item_context
+ } else if s == sym::integral {
+ "{integral}"
+ } else if s == sym::integer_ {
+ "{integer}"
+ } else if s == sym::float {
+ "{float}"
} else {
bug!(
"broken on_unimplemented {:?} for {:?}: \
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 23f615a..dba24fb 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -19,15 +19,17 @@
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::select::ProjectionMatchesProjection;
use rustc_data_structures::sso::SsoHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
use std::collections::BTreeMap;
@@ -44,7 +46,7 @@
/// When attempting to resolve `<T as TraitRef>::Name` ...
#[derive(Debug)]
-pub enum ProjectionTyError<'tcx> {
+pub enum ProjectionError<'tcx> {
/// ...we found multiple sources of information and couldn't resolve the ambiguity.
TooManyCandidates,
@@ -53,7 +55,7 @@
}
#[derive(PartialEq, Eq, Debug)]
-enum ProjectionTyCandidate<'tcx> {
+enum ProjectionCandidate<'tcx> {
/// From a where-clause in the env or object type
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
@@ -67,28 +69,28 @@
Select(Selection<'tcx>),
}
-enum ProjectionTyCandidateSet<'tcx> {
+enum ProjectionCandidateSet<'tcx> {
None,
- Single(ProjectionTyCandidate<'tcx>),
+ Single(ProjectionCandidate<'tcx>),
Ambiguous,
Error(SelectionError<'tcx>),
}
-impl<'tcx> ProjectionTyCandidateSet<'tcx> {
+impl<'tcx> ProjectionCandidateSet<'tcx> {
fn mark_ambiguous(&mut self) {
- *self = ProjectionTyCandidateSet::Ambiguous;
+ *self = ProjectionCandidateSet::Ambiguous;
}
fn mark_error(&mut self, err: SelectionError<'tcx>) {
- *self = ProjectionTyCandidateSet::Error(err);
+ *self = ProjectionCandidateSet::Error(err);
}
// Returns true if the push was successful, or false if the candidate
// was discarded -- this could be because of ambiguity, or because
// a higher-priority candidate is already there.
- fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool {
- use self::ProjectionTyCandidate::*;
- use self::ProjectionTyCandidateSet::*;
+ fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
+ use self::ProjectionCandidate::*;
+ use self::ProjectionCandidateSet::*;
// This wacky variable is just used to try and
// make code readable and avoid confusing paths.
@@ -196,7 +198,9 @@
debug!(?obligation, "project_and_unify_type");
let mut obligations = vec![];
- let normalized_ty = match opt_normalize_projection_type(
+
+ let infcx = selcx.infcx();
+ let normalized = match opt_normalize_projection_type(
selcx,
obligation.param_env,
obligation.predicate.projection_ty,
@@ -208,13 +212,10 @@
Ok(None) => return Ok(Ok(None)),
Err(InProgress) => return Ok(Err(InProgress)),
};
-
- debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
-
- let infcx = selcx.infcx();
+ debug!(?normalized, ?obligations, "project_and_unify_type result");
match infcx
.at(&obligation.cause, obligation.param_env)
- .eq(normalized_ty, obligation.predicate.ty)
+ .eq(normalized, obligation.predicate.term)
{
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
@@ -392,7 +393,7 @@
// 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.
+ // Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),
@@ -442,7 +443,7 @@
obligations.len = ?self.obligations.len(),
"AssocTypeNormalizer: normalized type"
);
- normalized_ty
+ normalized_ty.ty().unwrap()
}
ty::Projection(data) => {
@@ -472,6 +473,7 @@
)
.ok()
.flatten()
+ .map(|term| term.ty().unwrap())
.map(|normalized_ty| {
PlaceholderReplacer::replace_placeholders(
infcx,
@@ -498,7 +500,7 @@
}
}
- fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
if self.selcx.tcx().lazy_normalization() {
constant
} else {
@@ -621,24 +623,24 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- match *ct {
- ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ match ct.val() {
+ ty::ConstKind::Bound(debruijn, _)
if debruijn.as_usize() + 1
> self.current_index.as_usize() + self.universe_indices.len() =>
{
bug!("Bound vars outside of `self.universe_indices`");
}
- ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
- if debruijn >= self.current_index =>
- {
+ ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderConst {
universe,
- name: ty::BoundConst { var: bound_const, ty },
+ name: ty::BoundConst { var: bound_const, ty: ct.ty() },
};
self.mapped_consts.insert(p, bound_const);
- self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
+ self.infcx
+ .tcx
+ .mk_const(ty::ConstS { val: ty::ConstKind::Placeholder(p), ty: ct.ty() })
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
_ => ct,
@@ -696,7 +698,7 @@
}
fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
- let r1 = match r0 {
+ let r1 = match *r0 {
ty::ReVar(_) => self
.infcx
.inner
@@ -757,8 +759,8 @@
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Placeholder(p) = ct.val() {
let replace_var = self.mapped_consts.get(&p);
match replace_var {
Some(replace_var) => {
@@ -770,8 +772,10 @@
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- self.tcx()
- .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
+ self.tcx().mk_const(ty::ConstS {
+ val: ty::ConstKind::Bound(db, *replace_var),
+ ty: ct.ty(),
+ })
}
None => ct,
}
@@ -794,7 +798,7 @@
cause: ObligationCause<'tcx>,
depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
-) -> Ty<'tcx> {
+) -> Term<'tcx> {
opt_normalize_projection_type(
selcx,
param_env,
@@ -810,7 +814,10 @@
// and a deferred predicate to resolve this when more type
// information is available.
- selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
+ selcx
+ .infcx()
+ .infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
+ .into()
})
}
@@ -832,7 +839,7 @@
cause: ObligationCause<'tcx>,
depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
-) -> Result<Option<Ty<'tcx>>, InProgress> {
+) -> Result<Option<Term<'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
@@ -908,15 +915,15 @@
debug!("opt_normalize_projection_type: found error");
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
obligations.extend(result.obligations);
- return Ok(Some(result.value));
+ return Ok(Some(result.value.into()));
}
}
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
- match project_type(selcx, &obligation) {
- Ok(ProjectedTy::Progress(Progress {
- ty: projected_ty,
+ match project(selcx, &obligation) {
+ Ok(Projected::Progress(Progress {
+ term: projected_term,
obligations: mut projected_obligations,
})) => {
// if projection succeeded, then what we get out of this
@@ -924,10 +931,9 @@
// 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 projected_term = selcx.infcx().resolve_vars_if_possible(projected_term);
- let mut result = if projected_ty.has_projections() {
+ let mut result = if projected_term.has_projections() {
let mut normalizer = AssocTypeNormalizer::new(
selcx,
param_env,
@@ -935,13 +941,11 @@
depth + 1,
&mut projected_obligations,
);
- let normalized_ty = normalizer.fold(projected_ty);
-
- debug!(?normalized_ty, ?depth);
+ let normalized_ty = normalizer.fold(projected_term);
Normalized { value: normalized_ty, obligations: projected_obligations }
} else {
- Normalized { value: projected_ty, obligations: projected_obligations }
+ Normalized { value: projected_term, obligations: projected_obligations }
};
let mut deduped: SsoHashSet<_> = Default::default();
@@ -953,28 +957,27 @@
});
if use_cache {
- infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
+ infcx.inner.borrow_mut().projection_cache().insert_term(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");
+ Ok(Projected::NoProgress(projected_ty)) => {
let result = Normalized { value: projected_ty, obligations: vec![] };
if use_cache {
- infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
+ infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
}
// No need to extend `obligations`.
Ok(Some(result.value))
}
- Err(ProjectionTyError::TooManyCandidates) => {
+ Err(ProjectionError::TooManyCandidates) => {
debug!("opt_normalize_projection_type: too many candidates");
if use_cache {
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
}
Ok(None)
}
- Err(ProjectionTyError::TraitSelectionError(_)) => {
+ Err(ProjectionError::TraitSelectionError(_)) => {
debug!("opt_normalize_projection_type: ERROR");
// if we got an error processing the `T as Trait` part,
// just return `ty::err` but add the obligation `T :
@@ -986,7 +989,7 @@
}
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
obligations.extend(result.obligations);
- Ok(Some(result.value))
+ Ok(Some(result.value.into()))
}
}
}
@@ -1033,30 +1036,22 @@
Normalized { value: new_value, obligations: vec![trait_obligation] }
}
-enum ProjectedTy<'tcx> {
+enum Projected<'tcx> {
Progress(Progress<'tcx>),
- NoProgress(Ty<'tcx>),
+ NoProgress(ty::Term<'tcx>),
}
struct Progress<'tcx> {
- ty: Ty<'tcx>,
+ term: ty::Term<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
}
impl<'tcx> Progress<'tcx> {
fn error(tcx: TyCtxt<'tcx>) -> Self {
- Progress { ty: tcx.ty_error(), obligations: vec![] }
+ Progress { term: tcx.ty_error().into(), obligations: vec![] }
}
fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
- debug!(
- self.obligations.len = ?self.obligations.len(),
- obligations.len = obligations.len(),
- "with_addl_obligations"
- );
-
- debug!(?self.obligations, ?obligations, "with_addl_obligations");
-
self.obligations.append(&mut obligations);
self
}
@@ -1067,22 +1062,21 @@
/// IMPORTANT:
/// - `obligation` must be fully normalized
#[tracing::instrument(level = "info", skip(selcx))]
-fn project_type<'cx, 'tcx>(
+fn project<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
-) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> {
+) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) {
- debug!("project: overflow!");
// This should really be an immediate error, but some existing code
// relies on being able to recover from this.
- return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
+ return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow));
}
if obligation.predicate.references_error() {
- return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
+ return Ok(Projected::Progress(Progress::error(selcx.tcx())));
}
- let mut candidates = ProjectionTyCandidateSet::None;
+ let mut candidates = ProjectionCandidateSet::None;
// Make sure that the following procedures are kept in order. ParamEnv
// needs to be first because it has highest priority, and Select checks
@@ -1093,7 +1087,7 @@
assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
- if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
+ if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates {
// Avoid normalization cycle from selection (see
// `assemble_candidates_from_object_ty`).
// FIXME(lazy_normalization): Lazy normalization should save us from
@@ -1103,19 +1097,22 @@
};
match candidates {
- ProjectionTyCandidateSet::Single(candidate) => {
- Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate)))
+ ProjectionCandidateSet::Single(candidate) => {
+ Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
}
- ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
+ ProjectionCandidateSet::None => Ok(Projected::NoProgress(
+ // FIXME(associated_const_generics): this may need to change in the future?
+ // need to investigate whether or not this is fine.
selcx
.tcx()
- .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs),
+ .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .into(),
)),
// Error occurred while trying to processing impls.
- ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)),
+ ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)),
// Inherent ambiguity that prevents us from even enumerating the
// candidates.
- ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates),
+ ProjectionCandidateSet::Ambiguous => Err(ProjectionError::TooManyCandidates),
}
}
@@ -1125,14 +1122,13 @@
fn assemble_candidates_from_param_env<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
- debug!("assemble_candidates_from_param_env(..)");
assemble_candidates_from_predicates(
selcx,
obligation,
candidate_set,
- ProjectionTyCandidate::ParamEnv,
+ ProjectionCandidate::ParamEnv,
obligation.param_env.caller_bounds().iter(),
false,
);
@@ -1151,7 +1147,7 @@
fn assemble_candidates_from_trait_def<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_trait_def(..)");
@@ -1174,10 +1170,10 @@
selcx,
obligation,
candidate_set,
- ProjectionTyCandidate::TraitDef,
+ ProjectionCandidate::TraitDef,
bounds.iter(),
true,
- )
+ );
}
/// In the case of a trait object like
@@ -1192,7 +1188,7 @@
fn assemble_candidates_from_object_ty<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
debug!("assemble_candidates_from_object_ty(..)");
@@ -1219,64 +1215,69 @@
selcx,
obligation,
candidate_set,
- ProjectionTyCandidate::Object,
+ ProjectionCandidate::Object,
env_predicates,
false,
);
}
+#[tracing::instrument(
+ level = "debug",
+ skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
+)]
fn assemble_candidates_from_predicates<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
- ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+ ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>,
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
potentially_unnormalized_candidates: bool,
) {
- debug!(?obligation, "assemble_candidates_from_predicates");
-
let infcx = selcx.infcx();
for predicate in env_predicates {
- debug!(?predicate);
let bound_predicate = predicate.kind();
if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
let data = bound_predicate.rebind(data);
- let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
+ if data.projection_def_id() != obligation.predicate.item_def_id {
+ continue;
+ }
- let is_match = same_def_id
- && infcx.probe(|_| {
- selcx.match_projection_projections(
- obligation,
- data,
- potentially_unnormalized_candidates,
- )
- });
+ let is_match = infcx.probe(|_| {
+ selcx.match_projection_projections(
+ obligation,
+ data,
+ potentially_unnormalized_candidates,
+ )
+ });
- debug!(?data, ?is_match, ?same_def_id);
+ match is_match {
+ ProjectionMatchesProjection::Yes => {
+ candidate_set.push_candidate(ctor(data));
- if is_match {
- candidate_set.push_candidate(ctor(data));
-
- if potentially_unnormalized_candidates
- && !obligation.predicate.has_infer_types_or_consts()
- {
- // HACK: Pick the first trait def candidate for a fully
- // inferred predicate. This is to allow duplicates that
- // differ only in normalization.
- return;
+ if potentially_unnormalized_candidates
+ && !obligation.predicate.has_infer_types_or_consts()
+ {
+ // HACK: Pick the first trait def candidate for a fully
+ // inferred predicate. This is to allow duplicates that
+ // differ only in normalization.
+ return;
+ }
}
+ ProjectionMatchesProjection::Ambiguous => {
+ candidate_set.mark_ambiguous();
+ }
+ ProjectionMatchesProjection::No => {}
}
}
}
}
+#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))]
fn assemble_candidates_from_impls<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
- debug!("assemble_candidates_from_impls");
-
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
@@ -1299,10 +1300,7 @@
super::ImplSource::Closure(_)
| super::ImplSource::Generator(_)
| super::ImplSource::FnPointer(_)
- | super::ImplSource::TraitAlias(_) => {
- debug!(?impl_source);
- true
- }
+ | super::ImplSource::TraitAlias(_) => true,
super::ImplSource::UserDefined(impl_data) => {
// We have to be careful when projecting out of an
// impl because of specialization. If we are not in
@@ -1327,7 +1325,7 @@
// NOTE: This should be kept in sync with the similar code in
// `rustc_ty_utils::instance::resolve_associated_item()`.
let node_item =
- assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
+ assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
.map_err(|ErrorReported| ())?;
if node_item.is_final() {
@@ -1400,8 +1398,17 @@
// Any type with multiple potential metadata types is therefore not eligible.
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
- // FIXME: should this normalize?
- let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
+ let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
+ normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ )
+ .value
+ });
+
match tail.kind() {
ty::Bool
| ty::Char
@@ -1435,7 +1442,12 @@
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
- | ty::Error(_) => false,
+ | ty::Error(_) => {
+ if tail.has_infer_types() {
+ candidate_set.mark_ambiguous();
+ }
+ false
+ },
}
}
super::ImplSource::Param(..) => {
@@ -1486,7 +1498,7 @@
};
if eligible {
- if candidate_set.push_candidate(ProjectionTyCandidate::Select(impl_source)) {
+ if candidate_set.push_candidate(ProjectionCandidate::Select(impl_source)) {
Ok(())
} else {
Err(())
@@ -1500,30 +1512,32 @@
fn confirm_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate: ProjectionTyCandidate<'tcx>,
+ candidate: ProjectionCandidate<'tcx>,
) -> Progress<'tcx> {
debug!(?obligation, ?candidate, "confirm_candidate");
let mut progress = match candidate {
- ProjectionTyCandidate::ParamEnv(poly_projection)
- | ProjectionTyCandidate::Object(poly_projection) => {
+ ProjectionCandidate::ParamEnv(poly_projection)
+ | ProjectionCandidate::Object(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
}
- ProjectionTyCandidate::TraitDef(poly_projection) => {
+ ProjectionCandidate::TraitDef(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
}
- ProjectionTyCandidate::Select(impl_source) => {
+ ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source)
}
};
+
// When checking for cycle during evaluation, we compare predicates with
// "syntactic" equality. Since normalization generally introduces a type
// with new region variables, we need to resolve them to existing variables
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
- if progress.ty.has_infer_regions() {
- progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
+ if progress.term.has_infer_regions() {
+ progress.term =
+ progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
}
progress
}
@@ -1586,7 +1600,7 @@
gen_sig,
)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
- let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
+ let name = tcx.associated_item(obligation.predicate.item_def_id).name;
let ty = if name == sym::Return {
return_ty
} else if name == sym::Yield {
@@ -1600,7 +1614,7 @@
substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id,
},
- ty,
+ term: ty.into(),
}
});
@@ -1626,7 +1640,7 @@
let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
- ty: self_ty.discriminant_ty(tcx),
+ term: self_ty.discriminant_ty(tcx).into(),
};
// We get here from `poly_project_and_unify_type` which replaces bound vars
@@ -1640,18 +1654,30 @@
_: ImplSourcePointeeData,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
-
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
- let substs = tcx.mk_substs([self_ty.into()].iter());
+ let mut obligations = vec![];
+ let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ &mut obligations,
+ )
+ });
+
+ let substs = tcx.mk_substs([self_ty.into()].iter());
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
- ty: self_ty.ptr_metadata_ty(tcx),
+ term: metadata_ty.into(),
};
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+ .with_addl_obligations(obligations)
}
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1720,7 +1746,7 @@
substs: trait_ref.substs,
item_def_id: fn_once_output_def_id,
},
- ty: ret_type,
+ term: ret_type.into(),
});
confirm_param_env_candidate(selcx, obligation, predicate, true)
@@ -1776,7 +1802,9 @@
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
- Progress { ty: cache_entry.ty, obligations: nested_obligations }
+ // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
+ // a term instead.
+ Progress { term: cache_entry.term, obligations: nested_obligations }
}
Err(e) => {
let msg = format!(
@@ -1785,7 +1813,7 @@
);
debug!("confirm_param_env_candidate: {}", msg);
let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
- Progress { ty: err, obligations: vec![] }
+ Progress { term: err.into(), obligations: vec![] }
}
}
}
@@ -1802,9 +1830,9 @@
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let param_env = obligation.param_env;
- let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) {
+ let assoc_ty = match assoc_def(selcx, impl_def_id, assoc_item_id) {
Ok(assoc_ty) => assoc_ty,
- Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested },
+ Err(ErrorReported) => return Progress { term: tcx.ty_error().into(), obligations: nested },
};
if !assoc_ty.item.defaultness.has_value() {
@@ -1814,9 +1842,9 @@
// just return Error.
debug!(
"confirm_impl_candidate: no associated type {:?} for {:?}",
- assoc_ty.item.ident, obligation.predicate
+ assoc_ty.item.name, obligation.predicate
);
- return Progress { ty: tcx.ty_error(), obligations: nested };
+ return Progress { term: tcx.ty_error().into(), obligations: nested };
}
// If we're trying to normalize `<Vec<u32> as X>::A<S>` using
//`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
@@ -1828,15 +1856,25 @@
let substs =
translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
let ty = tcx.type_of(assoc_ty.item.def_id);
+ let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
+ let term: ty::Term<'tcx> = if is_const {
+ let identity_substs =
+ crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
+ let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
+ let val = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
+ tcx.mk_const(ty::ConstS { ty, val }).into()
+ } else {
+ ty.into()
+ };
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
let err = tcx.ty_error_with_message(
obligation.cause.span,
"impl item and trait item have different parameter counts",
);
- Progress { ty: err, obligations: nested }
+ Progress { term: err.into(), obligations: nested }
} else {
assoc_ty_own_obligations(selcx, obligation, &mut nested);
- Progress { ty: ty.subst(tcx, substs), obligations: nested }
+ Progress { term: term.subst(tcx, substs), obligations: nested }
}
}
@@ -1877,13 +1915,12 @@
///
/// Based on the "projection mode", this lookup may in fact only examine the
/// topmost impl. See the comments for `Reveal` for more details.
-fn assoc_ty_def(
+fn assoc_def(
selcx: &SelectionContext<'_, '_>,
impl_def_id: DefId,
- assoc_ty_def_id: DefId,
+ assoc_def_id: DefId,
) -> Result<specialization_graph::LeafDef, ErrorReported> {
let tcx = selcx.tcx();
- let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
let trait_def = tcx.trait_def(trait_def_id);
@@ -1893,21 +1930,18 @@
// for the associated item at the given impl.
// If there is no such item in that impl, this function will fail with a
// cycle error if the specialization graph is currently being built.
- let impl_node = specialization_graph::Node::Impl(impl_def_id);
- for item in impl_node.items(tcx) {
- if matches!(item.kind, ty::AssocKind::Type)
- && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
- {
- return Ok(specialization_graph::LeafDef {
- item: *item,
- defining_node: impl_node,
- finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
- });
- }
+ if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) {
+ let item = tcx.associated_item(impl_item_id);
+ let impl_node = specialization_graph::Node::Impl(impl_def_id);
+ return Ok(specialization_graph::LeafDef {
+ item: *item,
+ defining_node: impl_node,
+ finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+ });
}
let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
- if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
+ if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
Ok(assoc_item)
} else {
// This is saying that neither the trait nor
@@ -1916,7 +1950,11 @@
// could only arise through a compiler bug --
// if the user wrote a bad item name, it
// should have failed in astconv.
- bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id))
+ bug!(
+ "No associated type `{}` for {}",
+ tcx.item_name(assoc_def_id),
+ tcx.def_path_str(impl_def_id)
+ )
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index f05582f..55903a3 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -104,7 +104,7 @@
| ty::Error(_) => true,
// [T; N] and [T] have same properties as T.
- ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
+ ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *any* of those are trivial.
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 26bacf7..6a2bd9ce 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -77,11 +77,8 @@
// 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,
- };
+ let mut max_visitor =
+ MaxEscapingBoundVarVisitor { 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));
@@ -104,18 +101,13 @@
}
/// Visitor to find the maximum escaping bound var
-struct MaxEscapingBoundVarVisitor<'tcx> {
- tcx: TyCtxt<'tcx>,
+struct MaxEscapingBoundVarVisitor {
// 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)
- }
-
+impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &ty::Binder<'tcx, T>,
@@ -148,8 +140,8 @@
ControlFlow::CONTINUE
}
- fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- match ct.val {
+ fn visit_const(&mut self, ct: 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());
@@ -196,7 +188,7 @@
}
if let Some(ty) = self.cache.get(&ty) {
- return Ok(ty);
+ return Ok(*ty);
}
// See note in `rustc_trait_selection::traits::project` about why we
@@ -208,7 +200,7 @@
// 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.
+ // Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.try_super_fold_with(self),
@@ -332,8 +324,8 @@
fn try_fold_const(
&mut self,
- constant: &'tcx ty::Const<'tcx>,
- ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ constant: ty::Const<'tcx>,
+ ) -> Result<ty::Const<'tcx>, Self::Error> {
let constant = constant.try_super_fold_with(self)?;
Ok(constant.eval(self.infcx.tcx, self.param_env))
}
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 12ca3fa..d662f61 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,7 +4,9 @@
use crate::infer::{InferCtxt, InferOk};
use crate::traits::query::Fallible;
use crate::traits::ObligationCause;
-use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::infer::canonical::{Canonical, Certainty};
+use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::PredicateObligations;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use std::fmt;
@@ -17,7 +19,6 @@
pub mod normalize;
pub mod outlives;
pub mod prove_predicate;
-use self::prove_predicate::ProvePredicate;
pub mod subtype;
pub use rustc_middle::traits::query::type_op::*;
@@ -80,9 +81,14 @@
query_key: ParamEnvAnd<'tcx, Self>,
infcx: &InferCtxt<'_, 'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
- ) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
+ ) -> Fallible<(
+ Self::QueryResponse,
+ Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
+ PredicateObligations<'tcx>,
+ Certainty,
+ )> {
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
- return Ok((result, None));
+ return Ok((result, None, vec![], Certainty::Proven));
}
// FIXME(#33684) -- We need to use
@@ -104,20 +110,7 @@
output_query_region_constraints,
)?;
- // Typically, instantiating NLL query results does not
- // create obligations. However, in some cases there
- // are unresolved type variables, and unify them *can*
- // 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(
- obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
- infcx,
- output_query_region_constraints,
- )?;
- }
-
- Ok((value, Some(canonical_self)))
+ Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
}
}
@@ -129,9 +122,39 @@
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let mut region_constraints = QueryRegionConstraints::default();
- let (output, canonicalized_query) =
+ let (output, canonicalized_query, mut obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
+ // Typically, instantiating NLL query results does not
+ // create obligations. However, in some cases there
+ // are unresolved type variables, and unify them *can*
+ // create obligations. In that case, we have to go
+ // fulfill them. We do this via a (recursive) query.
+ while !obligations.is_empty() {
+ trace!("{:#?}", obligations);
+ let mut progress = false;
+ for obligation in std::mem::take(&mut obligations) {
+ let obligation = infcx.resolve_vars_if_possible(obligation);
+ match ProvePredicate::fully_perform_into(
+ obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
+ infcx,
+ &mut region_constraints,
+ ) {
+ Ok(((), _, new, certainty)) => {
+ obligations.extend(new);
+ progress = true;
+ if let Certainty::Ambiguous = certainty {
+ obligations.push(obligation);
+ }
+ }
+ Err(_) => obligations.push(obligation),
+ }
+ }
+ if !progress {
+ return Err(NoSolution);
+ }
+ }
+
// Promote the final query-region-constraints into a
// (optional) ref-counted vector:
let region_constraints =
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index e0098cc..aea4484 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -62,7 +62,7 @@
if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
- if let Some(vid) = predicate.ty.ty_vid() {
+ if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true;
}
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 017f47d..db86041 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -173,6 +173,9 @@
let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
+ let sized_predicate = self.tcx().lang_items().sized_trait()
+ == Some(stack.obligation.predicate.skip_binder().def_id());
+
// If there are STILL multiple candidates, we can further
// reduce the list by dropping duplicates -- including
// resolving specializations.
@@ -181,6 +184,7 @@
while i < candidates.len() {
let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
self.candidate_should_be_dropped_in_favor_of(
+ sized_predicate,
&candidates[i],
&candidates[j],
needs_infer,
@@ -301,15 +305,9 @@
} else if lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else if lang_items.drop_trait() == Some(def_id)
- && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
+ && obligation.predicate.is_const_if_const()
{
- if obligation.param_env.constness() == hir::Constness::Const {
- self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
- } else {
- debug!("passing ~const Drop bound; in non-const context");
- // `~const Drop` when we are not in a const context has no effect.
- candidates.vec.push(ConstDropCandidate)
- }
+ self.assemble_const_drop_candidates(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -338,13 +336,12 @@
Ok(candidates)
}
+ #[tracing::instrument(level = "debug", skip(self, candidates))]
fn assemble_candidates_from_projected_tys(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
- debug!(?obligation, "assemble_candidates_from_projected_tys");
-
// Before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
@@ -369,12 +366,13 @@
/// supplied to find out whether it is listed among them.
///
/// Never affects the inference environment.
+ #[tracing::instrument(level = "debug", skip(self, stack, candidates))]
fn assemble_candidates_from_caller_bounds<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) -> Result<(), SelectionError<'tcx>> {
- debug!(?stack.obligation, "assemble_candidates_from_caller_bounds");
+ debug!(?stack.obligation);
let all_bounds = stack
.obligation
@@ -876,6 +874,7 @@
};
}
+ #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_trait_alias(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -883,7 +882,7 @@
) {
// Okay to skip binder here because the tests we do below do not involve bound regions.
let self_ty = obligation.self_ty().skip_binder();
- debug!(?self_ty, "assemble_candidates_for_trait_alias");
+ debug!(?self_ty);
let def_id = obligation.predicate.def_id();
@@ -894,6 +893,7 @@
/// Assembles the trait which are built-in to the language itself:
/// `Copy`, `Clone` and `Sized`.
+ #[tracing::instrument(level = "debug", skip(self, candidates))]
fn assemble_builtin_bound_candidates(
&mut self,
conditions: BuiltinImplConditions<'tcx>,
@@ -901,152 +901,88 @@
) {
match conditions {
BuiltinImplConditions::Where(nested) => {
- debug!(?nested, "builtin_bound");
candidates
.vec
.push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() });
}
BuiltinImplConditions::None => {}
BuiltinImplConditions::Ambiguous => {
- debug!("assemble_builtin_bound_candidates: ambiguous builtin");
candidates.ambiguous = true;
}
}
}
- fn assemble_const_drop_candidates<'a>(
+ fn assemble_const_drop_candidates(
&mut self,
obligation: &TraitObligation<'tcx>,
- obligation_stack: &TraitObligationStack<'a, 'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
- let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
-
- while let Some((ty, depth)) = stack.pop() {
- let mut noreturn = false;
-
- self.check_recursion_depth(depth, obligation)?;
- let mut new_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- let mut copy_obligation =
- obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None),
- substs: self.tcx().mk_substs_trait(ty, &[]),
- },
- constness: ty::BoundConstness::NotConst,
- polarity: ty::ImplPolarity::Positive,
- }));
- copy_obligation.recursion_depth = depth + 1;
- self.assemble_candidates_from_impls(©_obligation, &mut new_candidates);
- let copy_conditions = self.copy_clone_conditions(©_obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut new_candidates);
- let copy_stack = self.push_stack(obligation_stack.list(), ©_obligation);
- self.assemble_candidates_from_caller_bounds(©_stack, &mut new_candidates)?;
-
- let const_drop_obligation =
- obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: self.tcx().require_lang_item(hir::LangItem::Drop, None),
- substs: self.tcx().mk_substs_trait(ty, &[]),
- },
- constness: ty::BoundConstness::ConstIfConst,
- polarity: ty::ImplPolarity::Positive,
- }));
-
- let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation);
- self.assemble_candidates_from_caller_bounds(&const_drop_stack, &mut new_candidates)?;
-
- if !new_candidates.vec.is_empty() {
- noreturn = true;
- }
- debug!(?new_candidates.vec, "assemble_const_drop_candidates");
-
- match ty.kind() {
- ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Infer(ty::IntVar(_))
- | ty::Infer(ty::FloatVar(_))
- | ty::FnPtr(_)
- | ty::Never
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::RawPtr(_)
- | ty::Bool
- | ty::Char
- | ty::Str
- | ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`.
-
- ty::Adt(def, subst) => {
- let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- self.assemble_candidates_from_impls(
- &obligation.with(obligation.predicate.map_bound(|mut pred| {
- pred.trait_ref.substs = self.tcx().mk_substs_trait(ty, &[]);
- pred
- })),
- &mut set,
- );
- stack.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1)));
-
- debug!(?set.vec, "assemble_const_drop_candidates - ty::Adt");
- if set.vec.into_iter().any(|candidate| {
- if let SelectionCandidate::ImplCandidate(did) = candidate {
- matches!(self.tcx().impl_constness(did), hir::Constness::NotConst)
- } else {
- false
- }
- }) {
- if !noreturn {
- // has non-const Drop
- return Ok(());
- }
- debug!("not returning");
- }
- }
-
- ty::Array(ty, _) => stack.push((ty, depth + 1)),
-
- ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))),
-
- ty::Closure(_, substs) => {
- let substs = substs.as_closure();
- let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty());
- stack.push((ty, depth + 1));
- }
-
- ty::Generator(_, substs, _) => {
- let substs = substs.as_generator();
- let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty());
-
- stack.push((ty, depth + 1));
- stack.push((substs.witness(), depth + 1));
- }
-
- ty::GeneratorWitness(tys) => stack.extend(
- self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)),
- ),
-
- ty::Slice(ty) => stack.push((ty, depth + 1)),
-
- ty::Opaque(..)
- | ty::Dynamic(..)
- | ty::Error(_)
- | ty::Bound(..)
- | ty::Infer(_)
- | ty::Placeholder(_)
- | ty::Projection(..)
- | ty::Param(..) => {
- if !noreturn {
- return Ok(());
- }
- debug!("not returning");
- }
- }
- debug!(?stack, "assemble_const_drop_candidates - in loop");
+ ) {
+ // If the predicate is `~const Drop` in a non-const environment, we don't actually need
+ // to check anything. We'll short-circuit checking any obligations in confirmation, too.
+ if obligation.param_env.constness() == hir::Constness::NotConst {
+ candidates.vec.push(ConstDropCandidate(None));
+ return;
}
- // all types have passed.
- candidates.vec.push(ConstDropCandidate);
- Ok(())
+ let self_ty = self.infcx().shallow_resolve(obligation.self_ty());
+ match self_ty.skip_binder().kind() {
+ ty::Opaque(..)
+ | ty::Dynamic(..)
+ | ty::Error(_)
+ | ty::Bound(..)
+ | ty::Param(_)
+ | ty::Placeholder(_)
+ | ty::Projection(_) => {
+ // We don't know if these are `~const Drop`, at least
+ // not structurally... so don't push a candidate.
+ }
+
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Str
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Foreign(_)
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::Tuple(_)
+ | ty::GeneratorWitness(_) => {
+ // These are built-in, and cannot have a custom `impl const Drop`.
+ candidates.vec.push(ConstDropCandidate(None));
+ }
+
+ ty::Adt(..) => {
+ // Find a custom `impl Drop` impl, if it exists
+ let relevant_impl = self.tcx().find_map_relevant_impl(
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().trait_ref.self_ty(),
+ Some,
+ );
+
+ if let Some(impl_def_id) = relevant_impl {
+ // Check that `impl Drop` is actually const, if there is a custom impl
+ if self.tcx().impl_constness(impl_def_id) == hir::Constness::Const {
+ candidates.vec.push(ConstDropCandidate(Some(impl_def_id)));
+ }
+ } else {
+ // Otherwise check the ADT like a built-in type (structurally)
+ candidates.vec.push(ConstDropCandidate(None));
+ }
+ }
+
+ ty::Infer(_) => {
+ candidates.ambiguous = true;
+ }
+ }
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index b7fc578..84bc7cd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -72,15 +72,12 @@
// CheckPredicate(&A: Super)
// CheckPredicate(A: ~const Super) // <- still const env, failure
// ```
- if obligation.param_env.constness() == Constness::Const
- && obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst
- {
+ if obligation.param_env.is_const() && !obligation.predicate.is_const_if_const() {
new_obligation = TraitObligation {
cause: obligation.cause.clone(),
param_env: obligation.param_env.without_const(),
..*obligation
};
-
obligation = &new_obligation;
}
@@ -159,7 +156,10 @@
Ok(ImplSource::TraitUpcasting(data))
}
- ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)),
+ ConstDropCandidate(def_id) => {
+ let data = self.confirm_const_drop_candidate(obligation, def_id)?;
+ Ok(ImplSource::ConstDrop(data))
+ }
}
}
@@ -206,7 +206,9 @@
})?);
if let ty::Projection(..) = placeholder_self_ty.kind() {
- for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates {
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
+ debug!(?predicates, "projection predicates");
+ for predicate in predicates {
let normalized = normalize_with_depth_to(
self,
obligation.param_env,
@@ -655,7 +657,7 @@
_ => bug!("closure candidate for non-closure {:?}", obligation),
};
- let obligation_predicate = obligation.predicate.to_poly_trait_ref();
+ let obligation_predicate = obligation.predicate;
let Normalized { value: obligation_predicate, mut obligations } =
ensure_sufficient_stack(|| {
normalize_with_depth(
@@ -685,7 +687,7 @@
obligations.extend(self.confirm_poly_trait_refs(
obligation.cause.clone(),
obligation.param_env,
- obligation_predicate,
+ obligation_predicate.to_poly_trait_ref(),
trait_ref,
)?);
@@ -981,7 +983,7 @@
// Lifetimes aren't allowed to change during unsizing.
GenericArgKind::Lifetime(_) => None,
- GenericArgKind::Const(ct) => match ct.val {
+ GenericArgKind::Const(ct) => match ct.val() {
ty::ConstKind::Param(p) => Some(p.index),
_ => None,
},
@@ -997,7 +999,7 @@
let tail_field_ty = tcx.type_of(tail_field.did);
let mut unsizing_params = GrowableBitSet::new_empty();
- for arg in tail_field_ty.walk(tcx) {
+ for arg in tail_field_ty.walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i);
}
@@ -1006,7 +1008,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(tcx) {
+ for arg in tcx.type_of(field.did).walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.remove(i);
}
@@ -1085,4 +1087,128 @@
Ok(ImplSourceBuiltinData { nested })
}
+
+ fn confirm_const_drop_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ impl_def_id: Option<DefId>,
+ ) -> Result<ImplSourceConstDropData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ // `~const Drop` in a non-const environment is always trivially true, since our type is `Drop`
+ if obligation.param_env.constness() == Constness::NotConst {
+ return Ok(ImplSourceConstDropData { nested: vec![] });
+ }
+
+ let tcx = self.tcx();
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+
+ let mut nested = vec![];
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+ // If we have a custom `impl const Drop`, then
+ // first check it like a regular impl candidate
+ if let Some(impl_def_id) = impl_def_id {
+ nested.extend(self.confirm_impl_candidate(obligation, impl_def_id).nested);
+ }
+
+ // We want to confirm the ADT's fields if we have an ADT
+ let mut stack = match *self_ty.skip_binder().kind() {
+ ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(),
+ _ => vec![self_ty.skip_binder()],
+ };
+
+ while let Some(nested_ty) = stack.pop() {
+ match *nested_ty.kind() {
+ // We know these types are trivially drop
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Str
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Foreign(_) => {}
+
+ // These types are built-in, so we can fast-track by registering
+ // nested predicates for their constituient type(s)
+ ty::Array(ty, _) | ty::Slice(ty) => {
+ stack.push(ty);
+ }
+ ty::Tuple(tys) => {
+ stack.extend(tys.iter().map(|ty| ty.expect_ty()));
+ }
+ ty::Closure(_, substs) => {
+ stack.push(substs.as_closure().tupled_upvars_ty());
+ }
+ ty::Generator(_, substs, _) => {
+ let generator = substs.as_generator();
+ stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
+ }
+ ty::GeneratorWitness(tys) => {
+ stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
+ }
+
+ // If we have a projection type, make sure to normalize it so we replace it
+ // with a fresh infer variable
+ ty::Projection(..) => {
+ self.infcx.commit_unconditionally(|_| {
+ let predicate = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ self_ty
+ .rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(LangItem::Drop, None),
+ substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ .to_predicate(tcx),
+ &mut nested,
+ );
+
+ nested.push(Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ ));
+ });
+ }
+
+ // If we have any other type (e.g. an ADT), just register a nested obligation
+ // since it's either not `const Drop` (and we raise an error during selection),
+ // or it's an ADT (and we need to check for a custom impl during selection)
+ _ => {
+ let predicate = self_ty
+ .rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(LangItem::Drop, None),
+ substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ .to_predicate(tcx);
+
+ nested.push(Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ ));
+ }
+ }
+ }
+
+ Ok(ImplSourceConstDropData { nested })
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index fa88c8e..3b69700 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -36,7 +36,7 @@
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@@ -201,6 +201,7 @@
}
/// When does the builtin impl for `T: Trait` apply?
+#[derive(Debug)]
enum BuiltinImplConditions<'tcx> {
/// The impl is conditional on `T1, T2, ...: Trait`.
Where(ty::Binder<'tcx, Vec<Ty<'tcx>>>),
@@ -344,7 +345,7 @@
}
Err(e) => Err(e),
Ok(candidate) => {
- debug!(?candidate);
+ debug!(?candidate, "confirmed");
Ok(Some(candidate))
}
}
@@ -526,7 +527,7 @@
// contain the "'static" lifetime (any other lifetime
// would either be late-bound or local), so it is guaranteed
// to outlive any other lifetime
- if pred.0.is_global(self.infcx.tcx) && !pred.0.has_late_bound_regions() {
+ if pred.0.is_global() && !pred.0.has_late_bound_regions() {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToOkModuloRegions)
@@ -642,7 +643,7 @@
//
// Let's just see where this breaks :shrug:
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
- (c1.val, c2.val)
+ (c1.val(), c2.val())
{
if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
return Ok(EvaluatedToOk);
@@ -650,15 +651,15 @@
}
}
- let evaluate = |c: &'tcx ty::Const<'tcx>| {
- if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
+ let evaluate = |c: ty::Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
self.infcx
.const_eval_resolve(
obligation.param_env,
unevaluated,
Some(obligation.cause.span),
)
- .map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
+ .map(|val| ty::Const::from_value(self.tcx(), val, c.ty()))
} else {
Ok(c)
}
@@ -711,12 +712,8 @@
mut obligation: TraitObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
if !self.intercrate
- && obligation.is_global(self.tcx())
- && obligation
- .param_env
- .caller_bounds()
- .iter()
- .all(|bound| bound.definitely_needs_subst(self.tcx()))
+ && obligation.is_global()
+ && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
{
// 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
@@ -768,14 +765,38 @@
debug!(?result, "CACHE MISS");
self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
- stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
- self.insert_evaluation_cache(
- param_env,
- fresh_trait_pred,
- dep_node,
- provisional_result.max(result),
- );
- });
+ stack.cache().on_completion(
+ stack.dfn,
+ |fresh_trait_pred, provisional_result, provisional_dep_node| {
+ // Create a new `DepNode` that has dependencies on:
+ // * The `DepNode` for the original evaluation that resulted in a provisional cache
+ // entry being crated
+ // * The `DepNode` for the *current* evaluation, which resulted in us completing
+ // provisional caches entries and inserting them into the evaluation cache
+ //
+ // This ensures that when a query reads this entry from the evaluation cache,
+ // it will end up (transitively) dependening on all of the incr-comp dependencies
+ // created during the evaluation of this trait. For example, evaluating a trait
+ // will usually require us to invoke `type_of(field_def_id)` to determine the
+ // constituent types, and we want any queries reading from this evaluation
+ // cache entry to end up with a transitive `type_of(field_def_id`)` dependency.
+ //
+ // By using `in_task`, we're also creating an edge from the *current* query
+ // to the newly-created `combined_dep_node`. This is probably redundant,
+ // but it's better to add too many dep graph edges than to add too few
+ // dep graph edges.
+ let ((), combined_dep_node) = self.in_task(|this| {
+ this.tcx().dep_graph.read_index(provisional_dep_node);
+ this.tcx().dep_graph.read_index(dep_node);
+ });
+ self.insert_evaluation_cache(
+ param_env,
+ fresh_trait_pred,
+ combined_dep_node,
+ provisional_result.max(result),
+ );
+ },
+ );
} else {
debug!(?result, "PROVISIONAL");
debug!(
@@ -784,7 +805,13 @@
fresh_trait_pred, stack.depth, reached_depth,
);
- stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
+ stack.cache().insert_provisional(
+ stack.dfn,
+ reached_depth,
+ fresh_trait_pred,
+ result,
+ dep_node,
+ );
}
Ok(result)
@@ -1146,9 +1173,7 @@
ImplCandidate(def_id)
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
// const param
- ParamCandidate(trait_pred)
- if trait_pred.skip_binder().constness
- == ty::BoundConstness::ConstIfConst => {}
+ ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
// auto trait impl
AutoImplCandidate(..) => {}
// generator, this will raise error in other places
@@ -1156,7 +1181,7 @@
GeneratorCandidate => {}
// FnDef where the function is const
FnPointerCandidate { is_const: true } => {}
- ConstDropCandidate => {}
+ ConstDropCandidate(_) => {}
_ => {
// reject all other types of candidates
continue;
@@ -1469,12 +1494,18 @@
})
}
+ /// Return `Yes` if the obligation's predicate type applies to the env_predicate, and
+ /// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT,
+ /// and applying this env_predicate constrains any of the obligation's GAT substitutions.
+ ///
+ /// This behavior is a somewhat of a hack to prevent overconstraining inference variables
+ /// in cases like #91762.
pub(super) fn match_projection_projections(
&mut self,
obligation: &ProjectionTyObligation<'tcx>,
env_predicate: PolyProjectionPredicate<'tcx>,
potentially_unnormalized_candidates: bool,
- ) -> bool {
+ ) -> ProjectionMatchesProjection {
let mut nested_obligations = Vec::new();
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
obligation.cause.span,
@@ -1496,7 +1527,8 @@
infer_predicate.projection_ty
};
- self.infcx
+ let is_match = self
+ .infcx
.at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
@@ -1505,7 +1537,26 @@
nested_obligations.into_iter().chain(obligations),
)
.map_or(false, |res| res.may_apply())
- })
+ });
+
+ if is_match {
+ let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
+ // FIXME(generic-associated-types): Addresses aggressive inference in #92917.
+ // If this type is a GAT, and of the GAT substs resolve to something new,
+ // that means that we must have newly inferred something about the GAT.
+ // We should give up in that case.
+ if !generics.params.is_empty()
+ && obligation.predicate.substs[generics.parent_count..]
+ .iter()
+ .any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
+ {
+ ProjectionMatchesProjection::Ambiguous
+ } else {
+ ProjectionMatchesProjection::Yes
+ }
+ } else {
+ ProjectionMatchesProjection::No
+ }
}
///////////////////////////////////////////////////////////////////////////
@@ -1523,6 +1574,7 @@
/// See the comment for "SelectionCandidate" for more details.
fn candidate_should_be_dropped_in_favor_of(
&mut self,
+ sized_predicate: bool,
victim: &EvaluatedCandidate<'tcx>,
other: &EvaluatedCandidate<'tcx>,
needs_infer: bool,
@@ -1535,11 +1587,11 @@
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
- cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
+ cand.is_global() && !cand.has_late_bound_regions()
};
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
- // and `DiscriminantKindCandidate` to anything else.
+ // `DiscriminantKindCandidate`, and `ConstDropCandidate` to anything else.
//
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
@@ -1556,7 +1608,7 @@
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
- | ConstDropCandidate,
+ | ConstDropCandidate(_),
_,
) => true,
(
@@ -1564,7 +1616,7 @@
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
- | ConstDropCandidate,
+ | ConstDropCandidate(_),
) => false,
(ParamCandidate(other), ParamCandidate(victim)) => {
@@ -1594,6 +1646,16 @@
// Drop otherwise equivalent non-const fn pointer candidates
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
+ // If obligation is a sized predicate or the where-clause bound is
+ // global, prefer the projection or object candidate. See issue
+ // #50825 and #89352.
+ (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+ sized_predicate || is_global(cand)
+ }
+ (ParamCandidate(ref cand), ObjectCandidate(_) | ProjectionCandidate(_)) => {
+ !(sized_predicate || is_global(cand))
+ }
+
// Global bounds from the where clause should be ignored
// here (see issue #50825). Otherwise, we have a where
// clause so don't go around looking for impls.
@@ -1609,15 +1671,8 @@
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..)
- | ObjectCandidate(_)
- | ProjectionCandidate(_),
+ | TraitAliasCandidate(..),
) => !is_global(cand),
- (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
- // Prefer these to a global where-clause bound
- // (see issue #50825).
- is_global(cand)
- }
(
ImplCandidate(_)
| ClosureCandidate
@@ -1953,7 +2008,7 @@
ty::Generator(_, ref substs, _) => {
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
let witness = substs.as_generator().witness();
- t.rebind(vec![ty].into_iter().chain(iter::once(witness)).collect())
+ t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
}
ty::GeneratorWitness(types) => {
@@ -2004,7 +2059,7 @@
.skip_binder() // binder moved -\
.iter()
.flat_map(|ty| {
- let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(ty); // <----/
+ let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
self.infcx.commit_unconditionally(|_| {
let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
@@ -2143,14 +2198,9 @@
self.tcx(),
obligation_ty,
SimplifyParams::Yes,
- StripReferences::No,
);
- let simplified_impl_ty = fast_reject::simplify_type(
- self.tcx(),
- impl_ty,
- SimplifyParams::No,
- StripReferences::No,
- );
+ let simplified_impl_ty =
+ fast_reject::simplify_type(self.tcx(), impl_ty, SimplifyParams::No);
simplified_obligation_ty.is_some()
&& simplified_impl_ty.is_some()
@@ -2382,7 +2432,7 @@
// chain. Ideally, we should have a way to configure this either
// by using -Z verbose or just a CLI argument.
let derived_cause = DerivedObligationCause {
- parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
+ parent_trait_pred: obligation.predicate,
parent_code: obligation.cause.clone_code(),
};
let derived_code = variant(derived_cause);
@@ -2505,6 +2555,11 @@
from_dfn: usize,
reached_depth: usize,
result: EvaluationResult,
+ /// The `DepNodeIndex` created for the `evaluate_stack` call for this provisional
+ /// evaluation. When we create an entry in the evaluation cache using this provisional
+ /// cache entry (see `on_completion`), we use this `dep_node` to ensure that future reads from
+ /// the cache will have all of the necessary incr comp dependencies tracked.
+ dep_node: DepNodeIndex,
}
impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> {
@@ -2547,6 +2602,7 @@
reached_depth: usize,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
result: EvaluationResult,
+ dep_node: DepNodeIndex,
) {
debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
@@ -2572,7 +2628,10 @@
}
}
- map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
+ map.insert(
+ fresh_trait_pred,
+ ProvisionalEvaluation { from_dfn, reached_depth, result, dep_node },
+ );
}
/// Invoked when the node with dfn `dfn` does not get a successful
@@ -2623,7 +2682,7 @@
fn on_completion(
&self,
dfn: usize,
- mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
+ mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult, DepNodeIndex),
) {
debug!(?dfn, "on_completion");
@@ -2632,7 +2691,7 @@
{
debug!(?fresh_trait_pred, ?eval, "on_completion");
- op(fresh_trait_pred, eval.result);
+ op(fresh_trait_pred, eval.result, eval.dep_node);
}
}
}
@@ -2676,3 +2735,9 @@
write!(f, "TraitObligationStack({:?})", self.obligation)
}
}
+
+pub enum ProjectionMatchesProjection {
+ Yes,
+ Ambiguous,
+ No,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index ab732f5..38a6220 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -117,9 +117,8 @@
/// Specialization is determined by the sets of types to which the impls apply;
/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
/// to.
+#[instrument(skip(tcx), level = "debug")]
pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool {
- debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
-
// The feature gate should prevent introducing new specializations, but not
// taking advantage of upstream ones.
let features = tcx.features();
@@ -258,6 +257,7 @@
trait_id: DefId,
) -> specialization_graph::Graph {
let mut sg = specialization_graph::Graph::new();
+ let overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id);
let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
@@ -271,7 +271,7 @@
for impl_def_id in trait_impls {
if let Some(impl_def_id) = impl_def_id.as_local() {
// This is where impl overlap checking happens:
- let insert_result = sg.insert(tcx, impl_def_id.to_def_id());
+ let insert_result = sg.insert(tcx, impl_def_id.to_def_id(), overlap_mode);
// Report error if there was one.
let (overlap, used_to_be_allowed) = match insert_result {
Err(overlap) => (Some(overlap), None),
@@ -485,7 +485,7 @@
let mut types_without_default_bounds = FxHashSet::default();
let sized_trait = tcx.lang_items().sized_trait();
- if !substs.is_noop() {
+ if !substs.is_empty() {
types_without_default_bounds.extend(substs.types());
w.push('<');
w.push_str(
@@ -507,12 +507,21 @@
let mut pretty_predicates =
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
- for (p, _) in predicates {
+ for (mut p, _) in predicates {
if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
if Some(poly_trait_ref.def_id()) == sized_trait {
- types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
+ types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder());
continue;
}
+
+ if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness {
+ let new_trait_pred = poly_trait_ref.map_bound(|mut trait_pred| {
+ trait_pred.constness = ty::BoundConstness::NotConst;
+ trait_pred
+ });
+
+ p = tcx.mk_predicate(new_trait_pred.map_bound(ty::PredicateKind::Trait))
+ }
}
pretty_predicates.push(p.to_string());
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 3ac273f..497ac20 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -2,7 +2,7 @@
use crate::traits;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
@@ -41,6 +41,7 @@
tcx: TyCtxt<'tcx>,
impl_def_id: DefId,
simplified_self: Option<SimplifiedType>,
+ overlap_mode: OverlapMode,
) -> Result<Inserted, OverlapError>;
}
@@ -48,12 +49,7 @@
/// Insert an impl into this set of children without comparing to any existing impls.
fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
- if let Some(st) = fast_reject::simplify_type(
- tcx,
- trait_ref.self_ty(),
- SimplifyParams::No,
- StripReferences::No,
- ) {
+ if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
} else {
@@ -68,12 +64,7 @@
fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let vec: &mut Vec<DefId>;
- if let Some(st) = fast_reject::simplify_type(
- tcx,
- trait_ref.self_ty(),
- SimplifyParams::No,
- StripReferences::No,
- ) {
+ if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
vec = self.non_blanket_impls.get_mut(&st).unwrap();
} else {
@@ -92,6 +83,7 @@
tcx: TyCtxt<'_>,
impl_def_id: DefId,
simplified_self: Option<SimplifiedType>,
+ overlap_mode: OverlapMode,
) -> Result<Inserted, OverlapError> {
let mut last_lint = None;
let mut replace_children = Vec::new();
@@ -142,6 +134,7 @@
possible_sibling,
impl_def_id,
traits::SkipLeakCheck::default(),
+ overlap_mode,
|_| true,
|| false,
);
@@ -166,6 +159,7 @@
possible_sibling,
impl_def_id,
traits::SkipLeakCheck::Yes,
+ overlap_mode,
|overlap| {
if let Some(overlap_kind) =
tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
@@ -273,6 +267,7 @@
&mut self,
tcx: TyCtxt<'_>,
impl_def_id: DefId,
+ overlap_mode: OverlapMode,
) -> Result<Option<FutureCompatOverlapError>, OverlapError>;
/// Insert cached metadata mapping from a child impl back to its parent.
@@ -287,6 +282,7 @@
&mut self,
tcx: TyCtxt<'_>,
impl_def_id: DefId,
+ overlap_mode: OverlapMode,
) -> Result<Option<FutureCompatOverlapError>, OverlapError> {
assert!(impl_def_id.is_local());
@@ -316,19 +312,18 @@
let mut parent = trait_def_id;
let mut last_lint = None;
- let simplified = fast_reject::simplify_type(
- tcx,
- trait_ref.self_ty(),
- SimplifyParams::No,
- StripReferences::No,
- );
+ let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No);
// Descend the specialization tree, where `parent` is the current parent node.
loop {
use self::Inserted::*;
- let insert_result =
- self.children.entry(parent).or_default().insert(tcx, impl_def_id, simplified)?;
+ let insert_result = self.children.entry(parent).or_default().insert(
+ tcx,
+ impl_def_id,
+ simplified,
+ overlap_mode,
+ )?;
match insert_result {
BecameNewSibling(opt_lint) => {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 55feb3c..2ed7a8f 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -48,7 +48,6 @@
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
- _id: hir::HirId,
span: Span,
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
@@ -131,9 +130,6 @@
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 4bd73ef..2dd3b77 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -41,7 +41,7 @@
.into()
}
GenericArgKind::Const(ct) => {
- match ct.val {
+ match ct.val() {
ty::ConstKind::Infer(infer) => {
let resolved = infcx.shallow_resolve(infer);
if resolved == infer {
@@ -49,7 +49,9 @@
return None;
}
- infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty })
+ infcx
+ .tcx
+ .mk_const(ty::ConstS { val: ty::ConstKind::Infer(resolved), ty: ct.ty() })
}
_ => ct,
}
@@ -116,7 +118,10 @@
}
ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty);
- wf.compute(t.ty.into());
+ wf.compute(match t.term {
+ ty::Term::Ty(ty) => ty.into(),
+ ty::Term::Const(c) => c.into(),
+ })
}
ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg);
@@ -132,11 +137,10 @@
wf.compute(b.into());
}
ty::PredicateKind::ConstEvaluatable(uv) => {
- let substs = uv.substs(wf.tcx());
- let obligations = wf.nominal_obligations(uv.def.did, substs);
+ let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
wf.out.extend(obligations);
- for arg in substs.iter() {
+ for arg in uv.substs.iter() {
wf.compute(arg);
}
}
@@ -196,15 +200,14 @@
trait_ref: &ty::TraitRef<'tcx>,
item: Option<&hir::Item<'tcx>>,
cause: &mut traits::ObligationCause<'tcx>,
- pred: &ty::Predicate<'tcx>,
- mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>,
+ pred: ty::Predicate<'tcx>,
) {
debug!(
"extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
trait_ref, item, cause, pred
);
- let items = match item {
- Some(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.items,
+ let (items, impl_def_id) = match item {
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
_ => return,
};
let fix_span =
@@ -221,12 +224,17 @@
// projection coming from another associated type. See
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`.
- if let ty::Projection(projection_ty) = proj.ty.kind() {
- let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id);
- if let Some(impl_item_span) =
- items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
+ if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
+ if let Some(&impl_item_id) =
+ tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
{
- cause.span = impl_item_span;
+ if let Some(impl_item_span) = items
+ .iter()
+ .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .map(fix_span)
+ {
+ cause.span = impl_item_span;
+ }
}
}
}
@@ -235,13 +243,16 @@
// can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() {
- if let Some(impl_item_span) = trait_assoc_items
- .find(|i| i.def_id == item_def_id)
- .and_then(|trait_assoc_item| {
- items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span)
- })
+ if let Some(&impl_item_id) =
+ tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
{
- cause.span = impl_item_span;
+ if let Some(impl_item_span) = items
+ .iter()
+ .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .map(fix_span)
+ {
+ cause.span = impl_item_span;
+ }
}
}
}
@@ -297,10 +308,9 @@
let extend = |obligation: traits::PredicateObligation<'tcx>| {
let mut cause = cause.clone();
- if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() {
+ if let Some(parent_trait_pred) = obligation.predicate.to_opt_poly_trait_pred() {
let derived_cause = traits::DerivedObligationCause {
- // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
- parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
+ parent_trait_pred,
parent_code: obligation.cause.clone_code(),
};
*cause.make_mut_code() =
@@ -311,8 +321,7 @@
trait_ref,
item,
&mut cause,
- &obligation.predicate,
- tcx.associated_items(trait_ref.def_id).in_definition_order(),
+ obligation.predicate,
);
traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
};
@@ -423,7 +432,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(self.tcx());
+ let mut walker = arg.walk();
let param_env = self.param_env;
let depth = self.recursion_depth;
while let Some(arg) = walker.next() {
@@ -435,18 +444,14 @@
GenericArgKind::Lifetime(_) => continue,
GenericArgKind::Const(constant) => {
- match constant.val {
+ match constant.val() {
ty::ConstKind::Unevaluated(uv) => {
- assert!(uv.promoted.is_none());
- let substs = uv.substs(self.tcx());
-
- let obligations = self.nominal_obligations(uv.def.did, substs);
+ let obligations = self.nominal_obligations(uv.def.did, uv.substs);
self.out.extend(obligations);
- let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
- ty::Unevaluated::new(uv.def, substs),
- ))
- .to_predicate(self.tcx());
+ let predicate =
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
+ .to_predicate(self.tcx());
let cause = self.cause(traits::MiscObligation);
self.out.push(traits::Obligation::with_depth(
cause,
@@ -461,9 +466,9 @@
if resolved != infer {
let cause = self.cause(traits::MiscObligation);
- let resolved_constant = self.infcx.tcx.mk_const(ty::Const {
+ let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Infer(resolved),
- ..*constant
+ ty: constant.ty(),
});
self.out.push(traits::Obligation::with_depth(
cause,
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index f22751d..25f228c 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -12,9 +12,9 @@
rustc_index = { path = "../rustc_index" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.75.0"
-chalk-engine = "0.75.0"
-chalk-solve = "0.75.0"
+chalk-ir = "0.76.0"
+chalk-engine = "0.76.0"
+chalk-solve = "0.76.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index c386806..51b66e1 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -20,11 +20,10 @@
use std::fmt;
use std::sync::Arc;
-use crate::chalk::lowering::{self, LowerInto};
+use crate::chalk::lowering::LowerInto;
pub struct RustIrDatabase<'tcx> {
pub(crate) interner: RustInterner<'tcx>,
- pub(crate) reempty_placeholder: ty::Region<'tcx>,
}
impl fmt::Debug for RustIrDatabase<'_> {
@@ -40,12 +39,9 @@
bound_vars: SubstsRef<'tcx>,
) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
- let mut regions_substitutor =
- lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
predicates
.iter()
.map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
- .map(|wc| wc.fold_with(&mut regions_substitutor))
.filter_map(|wc| LowerInto::<
Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
>::lower_into(wc, self.interner)).collect()
@@ -287,9 +283,6 @@
let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
- let mut regions_substitutor =
- lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
- let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
let where_clauses = self.where_clauses_for(def_id, bound_vars);
@@ -335,9 +328,6 @@
let self_ty = trait_ref.self_ty();
let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
- let mut regions_substitutor =
- lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
- let self_ty = self_ty.fold_with(&mut regions_substitutor);
let lowered_ty = self_ty.lower_into(self.interner);
parameters[0].assert_ty_ref(self.interner).could_match(
@@ -436,23 +426,13 @@
) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
let def_id = associated_ty_id.0;
let assoc_item = self.interner.tcx.associated_item(def_id);
- let (impl_id, trait_id) = match assoc_item.container {
- AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
- AssocItemContainer::ImplContainer(def_id) => {
- (def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
- }
- };
+ let impl_id = assoc_item.container.id();
match assoc_item.kind {
AssocKind::Type => {}
_ => unimplemented!("Not possible??"),
}
- let trait_item = self
- .interner
- .tcx
- .associated_items(trait_id)
- .find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
- .unwrap();
+ let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version");
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
let binders = binders_for(self.interner, bound_vars);
let ty = self
@@ -464,7 +444,7 @@
Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
impl_id: chalk_ir::ImplId(impl_id),
- associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
+ associated_ty_id: chalk_ir::AssocTypeId(trait_item_id),
value: chalk_ir::Binders::new(
binders,
chalk_solve::rust_ir::AssociatedTyValueBound { ty },
@@ -566,11 +546,11 @@
Fn => lang_items.fn_trait(),
FnMut => lang_items.fn_mut_trait(),
FnOnce => lang_items.fn_once_trait(),
+ Generator => lang_items.gen_trait(),
Unsize => lang_items.unsize_trait(),
Unpin => lang_items.unpin_trait(),
CoerceUnsized => lang_items.coerce_unsized_trait(),
DiscriminantKind => lang_items.discriminant_kind_trait(),
- Generator => lang_items.generator_return(),
};
def_id.map(chalk_ir::TraitId)
}
@@ -694,28 +674,18 @@
let variances = self.interner.tcx.variances_of(def_id.0);
chalk_ir::Variances::from_iter(
self.interner,
- variances.iter().map(|v| match v {
- ty::Variance::Invariant => chalk_ir::Variance::Invariant,
- ty::Variance::Covariant => chalk_ir::Variance::Covariant,
- ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
- ty::Variance::Bivariant => unimplemented!(),
- }),
+ variances.iter().map(|v| v.lower_into(self.interner)),
)
}
fn adt_variance(
&self,
- def_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+ adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
) -> chalk_ir::Variances<RustInterner<'tcx>> {
- let variances = self.interner.tcx.variances_of(def_id.0.did);
+ let variances = self.interner.tcx.variances_of(adt_id.0.did);
chalk_ir::Variances::from_iter(
self.interner,
- variances.iter().map(|v| match v {
- ty::Variance::Invariant => chalk_ir::Variance::Invariant,
- ty::Variance::Covariant => chalk_ir::Variance::Covariant,
- ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
- ty::Variance::Bivariant => unimplemented!(),
- }),
+ variances.iter().map(|v| v.lower_into(self.interner)),
)
}
}
@@ -741,11 +711,11 @@
var: ty::BoundVar::from_usize(substs.len()),
kind: ty::BrAnon(substs.len() as u32),
};
- tcx.mk_region(ty::RegionKind::ReLateBound(ty::INNERMOST, br)).into()
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
ty::GenericParamDefKind::Const { .. } => tcx
- .mk_const(ty::Const {
+ .mk_const(ty::ConstS {
val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
ty: tcx.type_of(param.def_id),
})
@@ -765,7 +735,7 @@
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
}
ty::subst::GenericArgKind::Const(c) => {
- chalk_ir::VariableKind::Const(c.ty.lower_into(interner))
+ chalk_ir::VariableKind::Const(c.ty().lower_into(interner))
}
}),
)
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index cc07bfc..9d810d0 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -35,7 +35,7 @@
use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, Binder, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::def_id::DefId;
use chalk_ir::{FnSig, ForeignDefId};
@@ -188,12 +188,18 @@
chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)),
),
+ ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
+ chalk_ir::GoalData::SubtypeGoal(chalk_ir::SubtypeGoal {
+ a: a.lower_into(interner),
+ b: b.lower_into(interner),
+ })
+ }
+
// FIXME(chalk): other predicates
//
// We can defer this, but ultimately we'll want to express
// some of these in terms of chalk operations.
ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
@@ -226,13 +232,26 @@
for rustc_middle::ty::ProjectionPredicate<'tcx>
{
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
+ // FIXME(associated_const_equality): teach chalk about terms for alias eq.
chalk_ir::AliasEq {
- ty: self.ty.lower_into(interner),
+ ty: self.term.ty().unwrap().lower_into(interner),
alias: self.projection_ty.lower_into(interner),
}
}
}
+/*
+// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
+impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
+ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
+ match self {
+ ty::Term::Ty(ty) => ty.lower_into(interner).into(),
+ ty::Term::Const(c) => c.lower_into(interner).into(),
+ }
+ }
+}
+*/
+
impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
@@ -370,7 +389,7 @@
TyKind::Array(ty, c) => {
let ty = ty.lower_into(interner);
let c = c.lower_into(interner);
- ty::Array(ty, interner.tcx.mk_const(c))
+ ty::Array(ty, c)
}
TyKind::FnDef(id, substitution) => ty::FnDef(id.0, substitution.lower_into(interner)),
TyKind::Closure(closure, substitution) => {
@@ -430,30 +449,30 @@
impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInterner<'tcx>> {
- use rustc_middle::ty::RegionKind::*;
-
- match self {
- ReEarlyBound(_) => {
+ match *self {
+ ty::ReEarlyBound(_) => {
panic!("Should have already been substituted.");
}
- ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
+ ty::ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
chalk_ir::DebruijnIndex::new(db.as_u32()),
br.var.as_usize(),
))
.intern(interner),
- ReFree(_) => unimplemented!(),
- ReStatic => chalk_ir::LifetimeData::Static.intern(interner),
- ReVar(_) => unimplemented!(),
- RePlaceholder(placeholder_region) => {
+ ty::ReFree(_) => unimplemented!(),
+ ty::ReStatic => chalk_ir::LifetimeData::Static.intern(interner),
+ ty::ReVar(_) => unimplemented!(),
+ ty::RePlaceholder(placeholder_region) => {
chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex {
ui: chalk_ir::UniverseIndex { counter: placeholder_region.universe.index() },
idx: 0,
})
.intern(interner)
}
- ReEmpty(_) => unimplemented!(),
- // FIXME(chalk): need to handle ReErased
- ReErased => unimplemented!(),
+ ty::ReEmpty(ui) => {
+ chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() })
+ .intern(interner)
+ }
+ ty::ReErased => chalk_ir::LifetimeData::Erased.intern(interner),
}
}
}
@@ -461,7 +480,7 @@
impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'tcx>> {
fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> {
let kind = match self.data(interner) {
- chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound(
+ chalk_ir::LifetimeData::BoundVar(var) => ty::ReLateBound(
ty::DebruijnIndex::from_u32(var.debruijn.depth()),
ty::BoundRegion {
var: ty::BoundVar::from_usize(var.index),
@@ -469,18 +488,16 @@
},
),
chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(),
- chalk_ir::LifetimeData::Placeholder(p) => {
- ty::RegionKind::RePlaceholder(ty::Placeholder {
- universe: ty::UniverseIndex::from_usize(p.ui.counter),
- name: ty::BoundRegionKind::BrAnon(p.idx as u32),
- })
- }
- chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic,
- chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(),
+ chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
+ universe: ty::UniverseIndex::from_usize(p.ui.counter),
+ name: ty::BoundRegionKind::BrAnon(p.idx as u32),
+ }),
+ chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
chalk_ir::LifetimeData::Empty(ui) => {
- ty::RegionKind::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
+ ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
}
- chalk_ir::LifetimeData::Erased => ty::RegionKind::ReErased,
+ chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased,
+ chalk_ir::LifetimeData::Phantom(void, _) => match *void {},
};
interner.tcx.mk_region(kind)
}
@@ -488,8 +505,8 @@
impl<'tcx> LowerInto<'tcx, chalk_ir::Const<RustInterner<'tcx>>> for ty::Const<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Const<RustInterner<'tcx>> {
- let ty = self.ty.lower_into(interner);
- let value = match self.val {
+ let ty = self.ty().lower_into(interner);
+ let value = match self.val() {
ty::ConstKind::Value(val) => {
chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val })
}
@@ -515,7 +532,7 @@
chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(),
chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned),
};
- ty::Const { ty, val }
+ interner.tcx.mk_const(ty::ConstS { ty, val })
}
}
@@ -551,7 +568,7 @@
}
chalk_ir::GenericArgData::Const(c) => {
let c: ty::Const<'tcx> = c.lower_into(interner);
- interner.tcx.mk_const(c).into()
+ c.into()
}
}
}
@@ -651,7 +668,8 @@
.mk_substs_trait(self_ty, predicate.substs)
.lower_into(interner),
}),
- ty: predicate.ty.lower_into(interner),
+ // FIXME(associated_const_equality): teach chalk about terms for alias eq.
+ ty: predicate.term.ty().unwrap().lower_into(interner),
}),
),
ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
@@ -774,6 +792,16 @@
}
}
}
+impl<'tcx> LowerInto<'tcx, chalk_ir::Variance> for ty::Variance {
+ fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Variance {
+ match self {
+ ty::Variance::Covariant => chalk_ir::Variance::Covariant,
+ ty::Variance::Invariant => chalk_ir::Variance::Invariant,
+ ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
+ ty::Variance::Bivariant => unimplemented!(),
+ }
+ }
+}
impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
for ty::ProjectionPredicate<'tcx>
@@ -787,7 +815,7 @@
trait_bound: trait_ref.lower_into(interner),
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
- value: self.ty.lower_into(interner),
+ value: self.term.ty().unwrap().lower_into(interner),
}
}
}
@@ -806,7 +834,7 @@
tcx: TyCtxt<'tcx>,
ty: Binder<'tcx, T>,
) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
- let mut bound_vars_collector = BoundVarsCollector::new(tcx);
+ let mut bound_vars_collector = BoundVarsCollector::new();
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
@@ -836,16 +864,14 @@
}
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(tcx: TyCtxt<'tcx>) -> Self {
+ crate fn new() -> Self {
BoundVarsCollector {
- tcx,
binder_index: ty::INNERMOST,
parameters: BTreeMap::new(),
named_parameters: vec![],
@@ -854,10 +880,6 @@
}
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>,
@@ -889,8 +911,8 @@
}
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match r {
- ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
+ match *r {
+ ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
ty::BoundRegionKind::BrNamed(def_id, _name) => {
if !self.named_parameters.iter().any(|d| *d == def_id) {
self.named_parameters.push(def_id);
@@ -951,12 +973,12 @@
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
- match r {
- ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
+ match *r {
+ ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => {
let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
- return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br));
+ return self.tcx.mk_region(ty::ReLateBound(index, new_br));
}
None => panic!("Missing `BrNamed`."),
},
@@ -1008,10 +1030,6 @@
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
- // FIXME(chalk): currently we convert params to placeholders starting at
- // index `0`. To support placeholders, we'll actually need to do a
- // first pass to collect placeholders. Then we can insert params after.
- ty::Placeholder(_) => unimplemented!(),
ty::Param(param) => match self.list.iter().position(|r| r == ¶m) {
Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
@@ -1027,29 +1045,29 @@
}))
}
},
-
_ => t.super_fold_with(self),
}
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
- match r {
- // FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
- // This covers any region variables in a goal, right?
+ match *r {
+ // FIXME(chalk) - jackh726 - this currently isn't hit in any tests,
+ // since canonicalization will already change these to canonical
+ // variables (ty::ReLateBound).
ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) {
Some(idx) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(*idx),
kind: ty::BrAnon(*idx),
};
- self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+ self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
}
None => {
let idx = self.named_regions.len() as u32;
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
self.named_regions.insert(_re.def_id, idx);
- self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+ self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
}
},
@@ -1058,6 +1076,39 @@
}
}
+crate struct ReverseParamsSubstitutor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+}
+
+impl<'tcx> ReverseParamsSubstitutor<'tcx> {
+ crate fn new(
+ tcx: TyCtxt<'tcx>,
+ params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+ ) -> Self {
+ Self { tcx, params }
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReverseParamsSubstitutor<'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ match *t.kind() {
+ ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, name }) => {
+ match self.params.get(&name.as_usize()) {
+ Some(param) => self.tcx.mk_ty(ty::Param(*param)),
+ None => t,
+ }
+ }
+
+ _ => t.super_fold_with(self),
+ }
+ }
+}
+
/// Used to collect `Placeholder`s.
crate struct PlaceholdersCollector {
universe_index: ty::UniverseIndex,
@@ -1076,11 +1127,6 @@
}
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 => {
@@ -1094,7 +1140,7 @@
}
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match r {
+ match *r {
ty::RePlaceholder(p) if p.universe == self.universe_index => {
if let ty::BoundRegionKind::BrAnon(anon) = p.name {
self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
@@ -1107,32 +1153,3 @@
r.super_visit_with(self)
}
}
-
-/// Used to substitute specific `Regions`s with placeholders.
-crate struct RegionsSubstitutor<'tcx> {
- tcx: TyCtxt<'tcx>,
- reempty_placeholder: ty::Region<'tcx>,
-}
-
-impl<'tcx> RegionsSubstitutor<'tcx> {
- crate fn new(tcx: TyCtxt<'tcx>, reempty_placeholder: ty::Region<'tcx>) -> Self {
- RegionsSubstitutor { tcx, reempty_placeholder }
- }
-}
-
-impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> {
- fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
- match r {
- ty::ReEmpty(ui) => {
- assert_eq!(ui.as_usize(), 0);
- self.reempty_placeholder
- }
-
- _ => r.super_fold_with(self),
- }
- }
-}
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index a4d844e..3c2a266 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -22,9 +22,8 @@
use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
-use crate::chalk::lowering::{
- LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor,
-};
+use crate::chalk::lowering::LowerInto;
+use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor};
use chalk_solve::Solution;
@@ -42,19 +41,10 @@
let mut placeholders_collector = PlaceholdersCollector::new();
obligation.visit_with(&mut placeholders_collector);
- let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
- universe: ty::UniverseIndex::ROOT,
- name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
- }));
-
let mut params_substitutor =
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
let obligation = obligation.fold_with(&mut params_substitutor);
- // FIXME(chalk): we really should be substituting these back in the solution
- let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
-
- let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
- let obligation = obligation.fold_with(&mut regions_substitutor);
+ let params: FxHashMap<usize, ParamTy> = params_substitutor.params;
let max_universe = obligation.max_universe.index();
@@ -85,7 +75,7 @@
chalk_ir::VariableKind::Lifetime,
chalk_ir::UniverseIndex { counter: ui.index() },
),
- CanonicalVarKind::Const(_ui) => unimplemented!(),
+ CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
}),
),
@@ -96,7 +86,8 @@
use chalk_solve::Solver;
let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
- let db = ChalkRustIrDatabase { interner, reempty_placeholder };
+ let db = ChalkRustIrDatabase { interner };
+ debug!(?lowered_goal);
let solution = solver.solve(&db, &lowered_goal);
debug!(?obligation, ?solution, "evaluate goal");
@@ -110,8 +101,9 @@
use rustc_middle::infer::canonical::CanonicalVarInfo;
let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
+ let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
subst.as_slice(interner).iter().for_each(|p| {
- var_values.push(p.lower_into(interner));
+ var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
});
let variables: Vec<_> = binders
.iter(interner)
@@ -127,9 +119,9 @@
chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
ty::UniverseIndex::from_usize(var.skip_kind().counter),
),
- chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
- ty::UniverseIndex::from_usize(var.skip_kind().counter),
- ),
+ // FIXME(compiler-errors): We don't currently have a way of turning
+ // a Chalk ty back into a rustc ty, right?
+ chalk_ir::VariableKind::Const(_) => todo!(),
};
CanonicalVarInfo { kind }
})
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 672e149..455fc46 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -192,7 +192,7 @@
ty::Array(ety, _) | ty::Slice(ety) => {
// single-element containers, behave like their element
rustc_data_structures::stack::ensure_sufficient_stack(|| {
- dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)
+ dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints)
})?;
}
@@ -278,9 +278,9 @@
tcx.at(span).adt_dtorck_constraint(def.did)?;
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
// there, but that needs some way to handle cycles.
- constraints.dtorck_types.extend(dtorck_types.subst(tcx, substs));
- constraints.outlives.extend(outlives.subst(tcx, substs));
- constraints.overflows.extend(overflows.subst(tcx, substs));
+ constraints.dtorck_types.extend(dtorck_types.iter().map(|t| t.subst(tcx, substs)));
+ constraints.outlives.extend(outlives.iter().map(|t| t.subst(tcx, substs)));
+ constraints.overflows.extend(overflows.iter().map(|t| t.subst(tcx, substs)));
}
// Objects must be alive in order for their destructor
@@ -308,7 +308,7 @@
crate fn adt_dtorck_constraint(
tcx: TyCtxt<'_>,
def_id: DefId,
-) -> Result<DtorckConstraint<'_>, NoSolution> {
+) -> Result<&DtorckConstraint<'_>, NoSolution> {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
debug!("dtorck_constraint: {:?}", def);
@@ -324,7 +324,7 @@
overflows: vec![],
};
debug!("dtorck_constraint: {:?} => {:?}", def, result);
- return Ok(result);
+ return Ok(tcx.arena.alloc(result));
}
let mut result = DtorckConstraint::empty();
@@ -337,7 +337,7 @@
debug!("dtorck_constraint: {:?} => {:?}", def, result);
- Ok(result)
+ Ok(tcx.arena.alloc(result))
}
fn dedup_dtorck_constraint(c: &mut DtorckConstraint<'_>) {
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 46c2f7e..a4aa965 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -39,7 +39,7 @@
// always only region relations, and we are about to
// erase those anyway:
debug_assert_eq!(
- normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)),
+ normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)),
None,
);
@@ -57,7 +57,7 @@
})
}
-fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool {
+fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
match p.kind().skip_binder() {
ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
ty::PredicateKind::Trait(..)
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index a8e3768..1de50ba 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -36,7 +36,10 @@
&mut obligations,
);
fulfill_cx.register_predicate_obligations(infcx, obligations);
- Ok(NormalizationResult { normalized_ty: answer })
+ // FIXME(associated_const_equality): All users of normalize_projection_ty expected
+ // a type, but there is the possibility it could've been a const now. Maybe change
+ // it to a Term later?
+ Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() })
},
)
}
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
new file mode 100644
index 0000000..4142c99
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -0,0 +1,136 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::ty::{self, TyCtxt};
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers {
+ associated_item,
+ associated_item_def_ids,
+ associated_items,
+ impl_item_implementor_ids,
+ trait_of_item,
+ ..*providers
+ };
+}
+
+fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
+ let item = tcx.hir().expect_item(def_id.expect_local());
+ match item.kind {
+ hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
+ trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+ ),
+ hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
+ impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+ ),
+ hir::ItemKind::TraitAlias(..) => &[],
+ _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
+ }
+}
+
+fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
+ let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+ ty::AssocItems::new(items)
+}
+
+fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
+ tcx.associated_items(impl_id)
+ .in_definition_order()
+ .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
+ .collect()
+}
+
+/// If the given `DefId` describes an item belonging to a trait,
+/// returns the `DefId` of the trait that the trait item belongs to;
+/// otherwise, returns `None`.
+fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+ tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
+ ty::TraitContainer(def_id) => Some(def_id),
+ ty::ImplContainer(_) => None,
+ })
+}
+
+fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let parent_def_id = tcx.hir().get_parent_item(id);
+ let parent_item = tcx.hir().expect_item(parent_def_id);
+ match parent_item.kind {
+ hir::ItemKind::Impl(ref impl_) => {
+ if let Some(impl_item_ref) =
+ impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ {
+ let assoc_item =
+ associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+ debug_assert_eq!(assoc_item.def_id, def_id);
+ return assoc_item;
+ }
+ }
+
+ hir::ItemKind::Trait(.., ref trait_item_refs) => {
+ if let Some(trait_item_ref) =
+ trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ {
+ let assoc_item =
+ associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+ debug_assert_eq!(assoc_item.def_id, def_id);
+ return assoc_item;
+ }
+ }
+
+ _ => {}
+ }
+
+ span_bug!(
+ parent_item.span,
+ "unexpected parent of trait or impl item or item not found: {:?}",
+ parent_item.kind
+ )
+}
+
+fn associated_item_from_trait_item_ref(
+ tcx: TyCtxt<'_>,
+ parent_def_id: LocalDefId,
+ trait_item_ref: &hir::TraitItemRef,
+) -> ty::AssocItem {
+ let def_id = trait_item_ref.id.def_id;
+ let (kind, has_self) = match trait_item_ref.kind {
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ };
+
+ ty::AssocItem {
+ name: trait_item_ref.ident.name,
+ kind,
+ vis: tcx.visibility(def_id),
+ defaultness: trait_item_ref.defaultness,
+ def_id: def_id.to_def_id(),
+ trait_item_def_id: Some(def_id.to_def_id()),
+ container: ty::TraitContainer(parent_def_id.to_def_id()),
+ fn_has_self_parameter: has_self,
+ }
+}
+
+fn associated_item_from_impl_item_ref(
+ tcx: TyCtxt<'_>,
+ parent_def_id: LocalDefId,
+ impl_item_ref: &hir::ImplItemRef,
+) -> ty::AssocItem {
+ let def_id = impl_item_ref.id.def_id;
+ let (kind, has_self) = match impl_item_ref.kind {
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ };
+
+ ty::AssocItem {
+ name: impl_item_ref.ident.name,
+ kind,
+ vis: tcx.visibility(def_id),
+ defaultness: impl_item_ref.defaultness,
+ def_id: def_id.to_def_id(),
+ trait_item_def_id: impl_item_ref.trait_item_def_id,
+ container: ty::ImplContainer(parent_def_id.to_def_id()),
+ fn_has_self_parameter: has_self,
+ }
+}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 13ffb2a..91c4398 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -54,10 +54,6 @@
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>,
@@ -94,8 +90,8 @@
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match r {
- ty::ReLateBound(index, br) if *index == self.binder_index => {
+ match *r {
+ ty::ReLateBound(index, br) if index == self.binder_index => {
match self.vars.entry(br.var.as_u32()) {
Entry::Vacant(entry) => {
entry.insert(ty::BoundVariableKind::Region(br.kind));
@@ -152,8 +148,7 @@
let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
- let item = tcx.associated_item(def.did);
- resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
+ resolve_associated_item(tcx, def.did, param_env, trait_def_id, substs)
} else {
let ty = tcx.type_of(def.def_id_for_type_of());
let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
@@ -204,19 +199,12 @@
fn resolve_associated_item<'tcx>(
tcx: TyCtxt<'tcx>,
- trait_item: &ty::AssocItem,
+ trait_item_id: DefId,
param_env: ty::ParamEnv<'tcx>,
trait_id: DefId,
rcvr_substs: SubstsRef<'tcx>,
) -> Result<Option<Instance<'tcx>>, ErrorReported> {
- let def_id = trait_item.def_id;
- debug!(
- "resolve_associated_item(trait_item={:?}, \
- param_env={:?}, \
- trait_id={:?}, \
- rcvr_substs={:?})",
- def_id, param_env, trait_id, rcvr_substs
- );
+ debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_substs, "resolve_associated_item");
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
@@ -232,7 +220,7 @@
traits::ImplSource::UserDefined(impl_data) => {
debug!(
"resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
- param_env, trait_item, rcvr_substs, impl_data
+ param_env, trait_item_id, rcvr_substs, impl_data
);
assert!(!rcvr_substs.needs_infer());
assert!(!trait_ref.needs_infer());
@@ -241,9 +229,9 @@
let trait_def = tcx.trait_def(trait_def_id);
let leaf_def = trait_def
.ancestors(tcx, impl_data.impl_def_id)?
- .leaf_def(tcx, trait_item.ident, trait_item.kind)
+ .leaf_def(tcx, trait_item_id)
.unwrap_or_else(|| {
- bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
+ bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
});
let substs = tcx.infer_ctxt().enter(|infcx| {
@@ -297,22 +285,22 @@
// performs (i.e. that the definition's type in the `impl` matches
// the declaration in the `trait`), so that we can cheaply check
// here if it failed, instead of approximating it.
- if trait_item.kind == ty::AssocKind::Const
- && trait_item.def_id != leaf_def.item.def_id
+ if leaf_def.item.kind == ty::AssocKind::Const
+ && trait_item_id != leaf_def.item.def_id
&& leaf_def.item.def_id.is_local()
{
let normalized_type_of = |def_id, substs| {
tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
};
- let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
+ let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
if original_ty != resolved_ty {
let msg = format!(
"Instance::resolve: inconsistent associated `const` type: \
was `{}: {}` but resolved to `{}: {}`",
- tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs),
+ tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
original_ty,
tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
resolved_ty,
@@ -343,19 +331,22 @@
}
traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
- def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
+ def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
substs: rcvr_substs,
}),
_ => None,
},
traits::ImplSource::Object(ref data) => {
- let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
- Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
+ let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
+ Some(Instance {
+ def: ty::InstanceDef::Virtual(trait_item_id, index),
+ substs: rcvr_substs,
+ })
}
traits::ImplSource::Builtin(..) => {
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
// FIXME(eddyb) use lang items for methods instead of names.
- let name = tcx.item_name(def_id);
+ let name = tcx.item_name(trait_item_id);
if name == sym::clone {
let self_ty = trait_ref.self_ty();
@@ -367,7 +358,7 @@
};
Some(Instance {
- def: ty::InstanceDef::CloneShim(def_id, self_ty),
+ def: ty::InstanceDef::CloneShim(trait_item_id, self_ty),
substs: rcvr_substs,
})
} else {
@@ -375,7 +366,7 @@
// Use the default `fn clone_from` from `trait Clone`.
let substs = tcx.erase_regions(rcvr_substs);
- Some(ty::Instance::new(def_id, substs))
+ Some(ty::Instance::new(trait_item_id, substs))
}
} else {
None
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 60f8e19..55e1999 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -16,6 +16,7 @@
use rustc_middle::ty::query::Providers;
+mod assoc;
mod common_traits;
pub mod instance;
mod needs_drop;
@@ -23,6 +24,7 @@
mod ty;
pub fn provide(providers: &mut Providers) {
+ assoc::provide(providers);
common_traits::provide(providers);
needs_drop::provide(providers);
ty::provide(providers);
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index d3eb9fd..b08f8f6 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -92,19 +92,14 @@
seen,
shadow_seen,
representable_cache,
- ty,
+ *ty,
force_result,
),
ty::Adt(def, substs) => {
// Find non representable fields with their spans
fold_repr(def.all_fields().map(|field| {
let ty = field.ty(tcx, substs);
- let span = match field
- .did
- .as_local()
- .map(|id| tcx.hir().local_def_id_to_hir_id(id))
- .and_then(|id| tcx.hir().find(id))
- {
+ let span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
Some(hir::Node::Field(field)) => field.ty.span,
_ => sp,
};
@@ -260,7 +255,7 @@
force_result: &mut bool,
) -> Representability {
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
- if let Some(representability) = representable_cache.get(ty) {
+ if let Some(representability) = representable_cache.get(&ty) {
debug!(
"is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
ty, sp, representability
@@ -327,7 +322,7 @@
// struct Foo { Option<Option<Foo>> }
for &seen_adt in iter {
- if ty::TyS::same_type(ty, seen_adt) {
+ if ty == seen_adt {
debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty);
return Representability::ContainsRecursive;
}
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 6c2657b..e44f80d 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,6 +1,6 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
use rustc_span::{sym, Span};
@@ -71,90 +71,6 @@
result
}
-fn associated_item_from_trait_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
- let def_id = trait_item_ref.id.def_id;
- let (kind, has_self) = match trait_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
- };
-
- ty::AssocItem {
- ident: trait_item_ref.ident,
- kind,
- vis: tcx.visibility(def_id),
- defaultness: trait_item_ref.defaultness,
- def_id: def_id.to_def_id(),
- container: ty::TraitContainer(parent_def_id.to_def_id()),
- fn_has_self_parameter: has_self,
- }
-}
-
-fn associated_item_from_impl_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
- let def_id = impl_item_ref.id.def_id;
- let (kind, has_self) = match impl_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
- };
-
- ty::AssocItem {
- ident: impl_item_ref.ident,
- kind,
- vis: tcx.visibility(def_id),
- defaultness: impl_item_ref.defaultness,
- def_id: def_id.to_def_id(),
- container: ty::ImplContainer(parent_def_id.to_def_id()),
- fn_has_self_parameter: has_self,
- }
-}
-
-fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let parent_id = tcx.hir().get_parent_item(id);
- let parent_def_id = tcx.hir().local_def_id(parent_id);
- let parent_item = tcx.hir().expect_item(parent_def_id);
- match parent_item.kind {
- hir::ItemKind::Impl(ref impl_) => {
- if let Some(impl_item_ref) =
- impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
- {
- let assoc_item =
- associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
- debug_assert_eq!(assoc_item.def_id, def_id);
- return assoc_item;
- }
- }
-
- hir::ItemKind::Trait(.., ref trait_item_refs) => {
- if let Some(trait_item_ref) =
- trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
- {
- let assoc_item =
- associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
- debug_assert_eq!(assoc_item.def_id, def_id);
- return assoc_item;
- }
- }
-
- _ => {}
- }
-
- span_bug!(
- parent_item.span,
- "unexpected parent of trait or impl item or item not found: {:?}",
- parent_item.kind
- )
-}
-
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
@@ -197,25 +113,6 @@
ty::AdtSizedConstraint(result)
}
-fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
- let item = tcx.hir().expect_item(def_id.expect_local());
- match item.kind {
- hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
- trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
- ),
- hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
- impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
- ),
- hir::ItemKind::TraitAlias(..) => &[],
- _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
- }
-}
-
-fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
- let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
- ty::AssocItems::new(items)
-}
-
fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
tcx.hir()
.get_if_local(def_id)
@@ -231,16 +128,6 @@
.map(|ident| ident.span)
}
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
- tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
- ty::TraitContainer(def_id) => Some(def_id),
- ty::ImplContainer(_) => None,
- })
-}
-
/// See `ParamEnv` struct definition for details.
#[instrument(level = "debug", skip(tcx))]
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
@@ -262,7 +149,7 @@
// 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
+ // are any errors at that point, so outside of type inference you can be
// sure that this will succeed without errors anyway.
if tcx.sess.opts.debugging_opts.chalk {
@@ -270,16 +157,6 @@
predicates.extend(environment);
}
- // It's important that we include the default substs in unevaluated
- // constants, since `Unevaluated` instances in predicates whose substs are None
- // can lead to "duplicate" caller bounds candidates during trait selection,
- // duplicate in the sense that both have their default substs, but the
- // candidate that resulted from a superpredicate still uses `None` in its
- // `substs_` field of `Unevaluated` to indicate that it has its default substs,
- // whereas the other candidate has `substs_: Some(default_substs)`, see
- // issue #89334
- predicates = tcx.expose_default_const_substs(predicates);
-
let local_did = def_id.as_local();
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
@@ -392,8 +269,7 @@
if !def_id.is_local() {
return ty::List::empty();
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let node = tcx.hir().get(hir_id);
+ let node = tcx.hir().get_by_def_id(def_id.expect_local());
enum NodeKind {
TraitImpl,
@@ -447,7 +323,7 @@
// constituents are well-formed.
NodeKind::InherentImpl => {
let self_ty = tcx.type_of(def_id);
- inputs.extend(self_ty.walk(tcx));
+ inputs.extend(self_ty.walk());
}
// In an fn, we assume that the arguments and all their constituents are
@@ -456,7 +332,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(tcx)));
+ inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
}
NodeKind::Other => (),
@@ -534,7 +410,7 @@
let self_ty = trait_ref.self_ty();
let self_ty_matches = match self_ty.kind() {
- ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
+ ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(),
_ => false,
};
@@ -549,9 +425,7 @@
/// Check if a function is async.
fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
- let node = tcx.hir().get(hir_id);
+ let node = tcx.hir().get_by_def_id(def_id.expect_local());
let fn_kind = node.fn_kind().unwrap_or_else(|| {
bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
@@ -600,7 +474,7 @@
Some(0) | None => false,
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
- Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(ty)),
+ Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(*ty)),
}
}
ty::Ref(..) => {
@@ -620,14 +494,10 @@
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
asyncness,
- associated_item,
- associated_item_def_ids,
- associated_items,
adt_sized_constraint,
def_ident_span,
param_env,
param_env_reveal_all_normalized,
- trait_of_item,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index f11c93e..e26f003 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -19,116 +19,94 @@
// Does this have parameters? Used to determine whether substitution is
// required.
/// Does this have `Param`?
- const HAS_KNOWN_TY_PARAM = 1 << 0;
+ const HAS_TY_PARAM = 1 << 0;
/// Does this have `ReEarlyBound`?
- const HAS_KNOWN_RE_PARAM = 1 << 1;
+ const HAS_RE_PARAM = 1 << 1;
/// Does this have `ConstKind::Param`?
- const HAS_KNOWN_CT_PARAM = 1 << 2;
+ const HAS_CT_PARAM = 1 << 2;
- const KNOWN_NEEDS_SUBST = TypeFlags::HAS_KNOWN_TY_PARAM.bits
- | TypeFlags::HAS_KNOWN_RE_PARAM.bits
- | TypeFlags::HAS_KNOWN_CT_PARAM.bits;
+ const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
+ | TypeFlags::HAS_RE_PARAM.bits
+ | TypeFlags::HAS_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_KNOWN_FREE_LOCAL_REGIONS = 1 << 9;
+ const HAS_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_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;
+ 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;
/// 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_KNOWN_FREE_REGIONS = 1 << 14;
-
- const HAS_POTENTIAL_FREE_REGIONS = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits
- | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
+ const HAS_FREE_REGIONS = 1 << 14;
/// 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?
- ///
- /// 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;
+ 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;
-
- /// 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;
-
+ const HAS_CT_FRESH = 1 << 19;
}
}
@@ -422,9 +400,11 @@
/// they carry no values.
impl UnifyKey for TyVid {
type Value = ();
+ #[inline]
fn index(&self) -> u32 {
self.as_u32()
}
+ #[inline]
fn from_index(i: u32) -> TyVid {
TyVid::from_u32(i)
}
@@ -441,6 +421,7 @@
fn index(&self) -> u32 {
self.index
}
+ #[inline]
fn from_index(i: u32) -> IntVid {
IntVid { index: i }
}
@@ -453,9 +434,11 @@
impl UnifyKey for FloatVid {
type Value = Option<FloatVarValue>;
+ #[inline]
fn index(&self) -> u32 {
self.index
}
+ #[inline]
fn from_index(i: u32) -> FloatVid {
FloatVid { index: i }
}
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index 7e570e1..57930a2 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -15,6 +15,7 @@
rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_target = { path = "../rustc_target" }
@@ -27,3 +28,4 @@
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
rustc_lint = { path = "../rustc_lint" }
+rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index ea54b85..7e9abe3 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -93,62 +93,100 @@
span: Span,
trait_def_id: DefId,
trait_segment: &'_ hir::PathSegment<'_>,
+ is_impl: bool,
) {
- let trait_def = self.tcx().trait_def(trait_def_id);
+ if self.tcx().features().unboxed_closures {
+ return;
+ }
- if !self.tcx().features().unboxed_closures
- && trait_segment.args().parenthesized != trait_def.paren_sugar
- {
- let sess = &self.tcx().sess.parse_sess;
+ let trait_def = self.tcx().trait_def(trait_def_id);
+ if !trait_def.paren_sugar {
+ if trait_segment.args().parenthesized {
+ // For now, require that parenthetical notation be used only with `Fn()` etc.
+ let mut err = feature_err(
+ &self.tcx().sess.parse_sess,
+ sym::unboxed_closures,
+ span,
+ "parenthetical notation is only stable when used with `Fn`-family traits",
+ );
+ err.emit();
+ }
+
+ return;
+ }
+
+ let sess = self.tcx().sess;
+
+ if !trait_segment.args().parenthesized {
// For now, require that parenthetical notation be used only with `Fn()` etc.
- let (msg, sugg) = if trait_def.paren_sugar {
- (
- "the precise format of `Fn`-family traits' type parameters is subject to \
- change",
- Some(format!(
- "{}{} -> {}",
- trait_segment.ident,
- trait_segment
- .args
- .as_ref()
- .and_then(|args| args.args.get(0))
- .and_then(|arg| match arg {
- hir::GenericArg::Type(ty) => match ty.kind {
- hir::TyKind::Tup(t) => t
- .iter()
- .map(|e| sess.source_map().span_to_snippet(e.span))
- .collect::<Result<Vec<_>, _>>()
- .map(|a| a.join(", ")),
- _ => sess.source_map().span_to_snippet(ty.span),
- }
- .map(|s| format!("({})", s))
- .ok(),
- _ => None,
- })
- .unwrap_or_else(|| "()".to_string()),
- trait_segment
- .args()
- .bindings
- .iter()
- .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
- (true, hir::TypeBindingKind::Equality { ty }) => {
- sess.source_map().span_to_snippet(ty.span).ok()
- }
- _ => None,
- })
- .unwrap_or_else(|| "()".to_string()),
- )),
- )
- } else {
- ("parenthetical notation is only stable when used with `Fn`-family traits", None)
- };
- let mut err = feature_err(sess, sym::unboxed_closures, span, msg);
- if let Some(sugg) = sugg {
- let msg = "use parenthetical notation instead";
- err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
+ let mut err = feature_err(
+ &sess.parse_sess,
+ sym::unboxed_closures,
+ span,
+ "the precise format of `Fn`-family traits' type parameters is subject to change",
+ );
+ // Do not suggest the other syntax if we are in trait impl:
+ // the desugaring would contain an associated type constrait.
+ if !is_impl {
+ let args = trait_segment
+ .args
+ .as_ref()
+ .and_then(|args| args.args.get(0))
+ .and_then(|arg| match arg {
+ hir::GenericArg::Type(ty) => match ty.kind {
+ hir::TyKind::Tup(t) => t
+ .iter()
+ .map(|e| sess.source_map().span_to_snippet(e.span))
+ .collect::<Result<Vec<_>, _>>()
+ .map(|a| a.join(", ")),
+ _ => sess.source_map().span_to_snippet(ty.span),
+ }
+ .map(|s| format!("({})", s))
+ .ok(),
+ _ => None,
+ })
+ .unwrap_or_else(|| "()".to_string());
+ let ret = trait_segment
+ .args()
+ .bindings
+ .iter()
+ .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
+ (true, hir::TypeBindingKind::Equality { term }) => {
+ let span = match term {
+ hir::Term::Ty(ty) => ty.span,
+ hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
+ };
+ sess.source_map().span_to_snippet(span).ok()
+ }
+ _ => None,
+ })
+ .unwrap_or_else(|| "()".to_string());
+ err.span_suggestion(
+ span,
+ "use parenthetical notation instead",
+ format!("{}{} -> {}", trait_segment.ident, args, ret),
+ Applicability::MaybeIncorrect,
+ );
}
err.emit();
}
+
+ if is_impl {
+ let trait_name = self.tcx().def_path_str(trait_def_id);
+ struct_span_err!(
+ self.tcx().sess,
+ span,
+ E0183,
+ "manual implementations of `{}` are experimental",
+ trait_name,
+ )
+ .span_label(
+ span,
+ format!("manual implementations of `{}` are experimental", trait_name),
+ )
+ .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
+ .emit();
+ }
}
pub(crate) fn complain_about_assoc_type_not_found<I>(
@@ -173,10 +211,9 @@
);
let all_candidate_names: Vec<_> = all_candidates()
- .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
- .flatten()
+ .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.filter_map(
- |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None },
+ |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
)
.collect();
@@ -232,7 +269,7 @@
let trait_def_id = assoc_item.container.id();
names.push(format!(
"`{}` (from trait `{}`)",
- assoc_item.ident,
+ assoc_item.name,
tcx.def_path_str(trait_def_id),
));
}
@@ -289,11 +326,11 @@
let mut names: FxHashMap<_, usize> = FxHashMap::default();
for item in assoc_items {
types_count += 1;
- *names.entry(item.ident.name).or_insert(0) += 1;
+ *names.entry(item.name).or_insert(0) += 1;
}
let mut dupes = false;
for item in assoc_items {
- let prefix = if names[&item.ident.name] > 1 {
+ let prefix = if names[&item.name] > 1 {
let trait_def_id = item.container.id();
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
@@ -301,7 +338,7 @@
String::new()
};
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
- err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident));
+ err.span_label(sp, format!("`{}{}` defined here", prefix, item.name));
}
}
if potential_assoc_types.len() == assoc_items.len() {
@@ -312,14 +349,14 @@
// `Iterator<Item = isize>`.
for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) {
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
- suggestions.push((*potential, format!("{} = {}", item.ident, snippet)));
+ suggestions.push((*potential, format!("{} = {}", item.name, snippet)));
}
}
} else if let (Ok(snippet), false) =
(tcx.sess.source_map().span_to_snippet(*span), dupes)
{
let types: Vec<_> =
- assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect();
+ assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
let code = if snippet.ends_with('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can
// suggest, but at least we can clue them to the correct syntax
@@ -350,17 +387,17 @@
let mut names: FxHashMap<_, usize> = FxHashMap::default();
for item in assoc_items {
types_count += 1;
- *names.entry(item.ident.name).or_insert(0) += 1;
+ *names.entry(item.name).or_insert(0) += 1;
}
let mut label = vec![];
for item in assoc_items {
- let postfix = if names[&item.ident.name] > 1 {
+ let postfix = if names[&item.name] > 1 {
let trait_def_id = item.container.id();
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
} else {
String::new()
};
- label.push(format!("`{}`{}", item.ident, postfix));
+ label.push(format!("`{}`{}", item.name, postfix));
}
if !label.is_empty() {
err.span_label(
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 9566965..05ff7f8 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -445,7 +445,7 @@
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();
+ (gen_pos != GenericArgPosition::Type || infer_args) && !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);
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 8226ffb..96f9204 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -6,7 +6,7 @@
mod generics;
use crate::bounds::Bounds;
-use crate::collect::PlaceholderHirTyCollector;
+use crate::collect::HirPlaceholderCollector;
use crate::errors::{
AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
@@ -83,7 +83,7 @@
ty: Ty<'tcx>,
param: Option<&ty::GenericParamDef>,
span: Span,
- ) -> &'tcx Const<'tcx>;
+ ) -> Const<'tcx>;
/// Projecting an associated type from a (potentially)
/// higher-ranked trait reference is more complicated, because of
@@ -123,7 +123,7 @@
#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
- Equality(Ty<'tcx>),
+ Equality(ty::Term<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]),
}
@@ -288,7 +288,7 @@
/// Given the type/lifetime/const arguments provided to some path (along with
/// an implicit `Self`, if this is a trait reference), returns the complete
/// set of substitutions. This may involve applying defaulted type parameters.
- /// Also returns back constraints on associated types.
+ /// Constraints on associated typess are created from `create_assoc_bindings_for_generic_args`.
///
/// Example:
///
@@ -302,7 +302,7 @@
/// which will have been resolved to a `def_id`
/// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
/// parameters are returned in the `SubstsRef`, the associated type bindings like
- /// `Output = u32` are returned in the `Vec<ConvertedBinding...>` result.
+ /// `Output = u32` are returned from `create_assoc_bindings_for_generic_args`.
///
/// Note that the type listing given here is *exactly* what the user provided.
///
@@ -388,7 +388,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(tcx).any(|arg| arg == self_param.into()) {
+ if default_ty.walk().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;
@@ -482,7 +482,20 @@
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
match param.kind {
- GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
+ GenericParamDefKind::Lifetime => self
+ .astconv
+ .re_infer(Some(param), self.span)
+ .unwrap_or_else(|| {
+ debug!(?param, "unelided lifetime in signature");
+
+ // This indicates an illegal lifetime in a non-assoc-trait position
+ tcx.sess.delay_span_bug(self.span, "unelided lifetime in signature");
+
+ // Supply some dummy value. We don't have an
+ // `re_error`, annoyingly, so use `'static`.
+ tcx.lifetimes.re_static
+ })
+ .into(),
GenericParamDefKind::Type { has_default, .. } => {
if !infer_args && has_default {
// No type parameter provided, but a default exists.
@@ -601,10 +614,17 @@
.iter()
.map(|binding| {
let kind = match binding.kind {
- hir::TypeBindingKind::Equality { ty } => {
- ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
- }
- hir::TypeBindingKind::Constraint { bounds } => {
+ hir::TypeBindingKind::Equality { ref term } => match term {
+ hir::Term::Ty(ref ty) => {
+ ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
+ }
+ hir::Term::Const(ref c) => {
+ let local_did = self.tcx().hir().local_def_id(c.hir_id);
+ let c = Const::from_anon_const(self.tcx(), local_did);
+ ConvertedBindingKind::Equality(c.into())
+ }
+ },
+ hir::TypeBindingKind::Constraint { ref bounds } => {
ConvertedBindingKind::Constraint(bounds)
}
};
@@ -669,6 +689,7 @@
trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
self_ty,
trait_ref.path.segments.last().unwrap(),
+ true,
)
}
@@ -765,7 +786,7 @@
let infer_args = trait_segment.infer_args;
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
- self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
+ self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
self.instantiate_poly_trait_ref_inner(
hir_id,
@@ -822,9 +843,15 @@
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
+ is_impl: bool,
) -> ty::TraitRef<'tcx> {
- let (substs, _) =
- self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
+ let (substs, _) = self.create_substs_for_ast_trait_ref(
+ span,
+ trait_def_id,
+ self_ty,
+ trait_segment,
+ is_impl,
+ );
let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
if let Some(b) = assoc_bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -839,8 +866,9 @@
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'a>,
+ is_impl: bool,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
- self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
+ self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
self.create_substs_for_ast_path(
span,
@@ -859,6 +887,12 @@
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
.is_some()
}
+ fn trait_defines_associated_const_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+ self.tcx()
+ .associated_items(trait_def_id)
+ .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Const, trait_def_id)
+ .is_some()
+ }
// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized<'hir>(
@@ -1106,34 +1140,40 @@
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
// of calling `filter_by_name_and_kind`.
- let assoc_ty = tcx
- .associated_items(candidate.def_id())
- .filter_by_name_unhygienic(assoc_ident.name)
- .find(|i| {
- i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
- })
+ let find_item_of_kind = |kind| {
+ tcx.associated_items(candidate.def_id())
+ .filter_by_name_unhygienic(assoc_ident.name)
+ .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
+ };
+ let assoc_item = find_item_of_kind(ty::AssocKind::Type)
+ .or_else(|| find_item_of_kind(ty::AssocKind::Const))
.expect("missing associated type");
- if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
+ if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
+ let kind = match assoc_item.kind {
+ ty::AssocKind::Type => "type",
+ ty::AssocKind::Const => "const",
+ _ => unreachable!(),
+ };
tcx.sess
.struct_span_err(
binding.span,
- &format!("associated type `{}` is private", binding.item_name),
+ &format!("associated {kind} `{}` is private", binding.item_name),
)
- .span_label(binding.span, "private associated type")
+ .span_label(binding.span, &format!("private associated {kind}"))
.emit();
}
- tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span, None);
+ tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
if !speculative {
dup_bindings
- .entry(assoc_ty.def_id)
+ .entry(assoc_item.def_id)
.and_modify(|prev_span| {
self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
span: binding.span,
prev_span: *prev_span,
item_name: binding.item_name,
- def_path: tcx.def_path_str(assoc_ty.container.id()),
+ def_path: tcx.def_path_str(assoc_item.container.id()),
});
})
.or_insert(binding.span);
@@ -1141,7 +1181,7 @@
// Include substitutions for generic parameters of associated types
let projection_ty = candidate.map_bound(|trait_ref| {
- let ident = Ident::new(assoc_ty.ident.name, binding.item_name.span);
+ let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
ident,
hir_id: Some(binding.hir_id),
@@ -1153,7 +1193,7 @@
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
tcx,
path_span,
- assoc_ty.def_id,
+ assoc_item.def_id,
&item_segment,
trait_ref.substs,
);
@@ -1164,14 +1204,14 @@
);
ty::ProjectionTy {
- item_def_id: assoc_ty.def_id,
+ item_def_id: assoc_item.def_id,
substs: substs_trait_ref_and_assoc_item,
}
});
if !speculative {
// Find any late-bound regions declared in `ty` that are not
- // declared in the trait-ref or assoc_ty. These are not well-formed.
+ // declared in the trait-ref or assoc_item. These are not well-formed.
//
// Example:
//
@@ -1207,18 +1247,35 @@
}
match binding.kind {
- ConvertedBindingKind::Equality(ty) => {
+ ConvertedBindingKind::Equality(term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
+ let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
+ let def_kind = tcx.def_kind(assoc_item_def_id);
+ match (def_kind, term) {
+ (hir::def::DefKind::AssocTy, ty::Term::Ty(_))
+ | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (),
+ (_, _) => {
+ let got = if let ty::Term::Ty(_) = term { "type" } else { "const" };
+ let expected = def_kind.descr(assoc_item_def_id);
+ tcx.sess
+ .struct_span_err(
+ binding.span,
+ &format!("mismatch in bind of {expected}, got {got}"),
+ )
+ .span_note(
+ tcx.def_span(assoc_item_def_id),
+ &format!("{expected} defined here does not match {got}"),
+ )
+ .emit();
+ }
+ }
bounds.projection_bounds.push((
- projection_ty.map_bound(|projection_ty| {
- debug!(
- "add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
- projection_ty, projection_ty.substs
- );
- ty::ProjectionPredicate { projection_ty, ty }
+ projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
+ projection_ty,
+ term: term,
}),
binding.span,
));
@@ -1369,8 +1426,10 @@
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
- let references_self =
- pred.skip_binder().ty.walk(tcx).any(|arg| arg == dummy_self.into());
+ let references_self = match pred.skip_binder().term {
+ ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+ ty::Term::Const(c) => c.ty().walk().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.
@@ -1594,10 +1653,13 @@
{
let mut matching_candidates = all_candidates()
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+ let mut const_candidates = all_candidates()
+ .filter(|r| self.trait_defines_associated_const_named(r.def_id(), assoc_name));
- let bound = match matching_candidates.next() {
- Some(bound) => bound,
- None => {
+ let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
+ (Some(bound), _) => (bound, matching_candidates.next()),
+ (None, Some(bound)) => (bound, const_candidates.next()),
+ (None, None) => {
self.complain_about_assoc_type_not_found(
all_candidates,
&ty_param_name(),
@@ -1607,10 +1669,9 @@
return Err(ErrorReported);
}
};
-
debug!("one_bound_for_assoc_type: bound = {:?}", bound);
- if let Some(bound2) = matching_candidates.next() {
+ if let Some(bound2) = next_cand {
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
let is_equality = is_equality();
@@ -1695,6 +1756,7 @@
return Err(ErrorReported);
}
}
+
Ok(bound)
}
@@ -1727,7 +1789,7 @@
let variant_def = adt_def
.variants
.iter()
- .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did));
+ .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did));
if let Some(variant_def) = variant_def {
if permit_variants {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
@@ -1743,7 +1805,7 @@
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&qself_ty.kind(), qself_res) {
- (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => {
+ (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => {
// `Self` in an impl of a trait -- we have a concrete self type and a
// trait reference.
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
@@ -1764,7 +1826,8 @@
}
(
&ty::Param(_),
- Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did),
+ Res::SelfTy { trait_: Some(param_did), alias_to: None }
+ | Res::Def(DefKind::TyParam, param_did),
) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
_ => {
if variant_resolution.is_some() {
@@ -1786,7 +1849,7 @@
&adt_def
.variants
.iter()
- .map(|variant| variant.ident.name)
+ .map(|variant| variant.name)
.collect::<Vec<Symbol>>(),
assoc_ident.name,
None,
@@ -1829,14 +1892,17 @@
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
// of calling `filter_by_name_and_kind`.
- let item = tcx
- .associated_items(trait_did)
- .in_definition_order()
- .find(|i| {
- i.kind.namespace() == Namespace::TypeNS
- && i.ident.normalize_to_macros_2_0() == assoc_ident
- })
- .expect("missing associated type");
+ let item = tcx.associated_items(trait_did).in_definition_order().find(|i| {
+ i.kind.namespace() == Namespace::TypeNS
+ && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+ });
+ // Assume that if it's not matched, there must be a const defined with the same name
+ // but it was used in a type position.
+ let Some(item) = item else {
+ let msg = format!("found associated const `{assoc_ident}` when type was expected");
+ tcx.sess.struct_span_err(span, &msg).emit();
+ return Err(ErrorReported);
+ };
let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
let ty = self.normalize_ty(span, ty);
@@ -1906,7 +1972,7 @@
.and_then(|def_id| {
def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
})
- .map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id());
+ .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
@@ -1932,7 +1998,8 @@
debug!("qpath_to_ty: self_type={:?}", self_ty);
- let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment);
+ let trait_ref =
+ self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
let item_substs = self.create_substs_for_associated_item(
tcx,
@@ -2204,19 +2271,38 @@
let index = generics.param_def_id_to_index[&def_id];
tcx.mk_ty_param(index, tcx.hir().name(hir_id))
}
- Res::SelfTy(Some(_), None) => {
+ Res::SelfTy { trait_: Some(_), alias_to: None } => {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments);
tcx.types.self_param
}
- Res::SelfTy(_, Some((def_id, forbid_generic))) => {
+ Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
// `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
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.definitely_needs_subst(tcx) {
+ let ty = tcx.at(span).type_of(def_id);
+ // HACK(min_const_generics): Forbid generic `Self` types
+ // here as we can't easily do that during nameres.
+ //
+ // We do this before normalization as we otherwise allow
+ // ```rust
+ // trait AlwaysApplicable { type Assoc; }
+ // impl<T: ?Sized> AlwaysApplicable for T { type Assoc = usize; }
+ //
+ // trait BindsParam<T> {
+ // type ArrayTy;
+ // }
+ // impl<T> BindsParam<T> for <T as AlwaysApplicable>::Assoc {
+ // type ArrayTy = [u8; Self::MAX];
+ // }
+ // ```
+ // Note that the normalization happens in the param env of
+ // the anon const, which is empty. This is why the
+ // `AlwaysApplicable` impl needs a `T: ?Sized` bound for
+ // this to compile if we were to normalize here.
+ if forbid_generic && ty.needs_subst() {
let mut err = tcx.sess.struct_span_err(
path.span,
"generic `Self` types are currently not permitted in anonymous constants",
@@ -2231,7 +2317,7 @@
err.emit();
tcx.ty_error()
} else {
- normalized_ty
+ self.normalize_ty(span, ty)
}
}
Res::Def(DefKind::AssocTy, def_id) => {
@@ -2469,7 +2555,7 @@
debug!(?bound_vars);
// We proactively collect all the inferred type params to emit a single error per fn def.
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
for ty in decl.inputs {
visitor.visit_ty(ty);
}
@@ -2588,7 +2674,7 @@
// If any of the derived region bounds are 'static, that is always
// the best choice.
- if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
+ if derived_region_bounds.iter().any(|r| r.is_static()) {
return Some(tcx.lifetimes.re_static);
}
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 8bc3a48..6a28bb1 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -48,14 +48,19 @@
/// where-clauses). Because some of our bounds listings (e.g.,
/// regions) don't include the self-type, you must supply the
/// self-type here (the `param_ty` parameter).
- pub fn predicates(
- &self,
+ pub fn predicates<'out, 's>(
+ &'s self,
tcx: TyCtxt<'tcx>,
param_ty: Ty<'tcx>,
- ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+ // the output must live shorter than the duration of the borrow of self and 'tcx.
+ ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
+ where
+ 'tcx: 'out,
+ 's: 'out,
+ {
// If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| {
- tcx.lang_items().sized_trait().map(|sized| {
+ tcx.lang_items().sized_trait().map(move |sized| {
let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: sized,
substs: tcx.mk_substs_trait(param_ty, &[]),
@@ -64,25 +69,22 @@
})
});
- sized_predicate
- .into_iter()
- .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
- (
- region_bound
- .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
- .to_predicate(tcx),
- span,
- )
- }))
- .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+ let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
+ let pred = region_bound
+ .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
+ .to_predicate(tcx);
+ (pred, span)
+ });
+ let trait_bounds =
+ self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
(predicate, span)
- }))
- .chain(
- self.projection_bounds
- .iter()
- .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
- )
- .collect()
+ });
+ let projection_bounds = self
+ .projection_bounds
+ .iter()
+ .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+
+ sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
}
}
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 405e4e8..3701b25 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -4,7 +4,7 @@
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
+use rustc_middle::ty::{self, ToPredicate, Ty};
use rustc_span::{MultiSpan, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
@@ -505,7 +505,7 @@
pub(crate) fn opt_suggest_box_span(
&self,
span: Span,
- outer_ty: &'tcx TyS<'tcx>,
+ outer_ty: Ty<'tcx>,
orig_expected: Expectation<'tcx>,
) -> Option<Span> {
match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index eea8f40..f64a90e 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -269,7 +269,7 @@
},
};
autoref = Some(Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+ kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
target: method.sig.inputs()[0],
});
}
@@ -307,6 +307,36 @@
}
}
+ /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the
+ /// likely intention is to create an array containing tuples.
+ fn maybe_suggest_bad_array_definition(
+ &self,
+ err: &mut DiagnosticBuilder<'a>,
+ call_expr: &'tcx hir::Expr<'tcx>,
+ callee_expr: &'tcx hir::Expr<'tcx>,
+ ) -> bool {
+ let hir_id = self.tcx.hir().get_parent_node(call_expr.hir_id);
+ let parent_node = self.tcx.hir().get(hir_id);
+ if let (
+ hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
+ hir::ExprKind::Tup(exp),
+ hir::ExprKind::Call(_, args),
+ ) = (parent_node, &callee_expr.kind, &call_expr.kind)
+ {
+ if args.len() == exp.len() {
+ let start = callee_expr.span.shrink_to_hi();
+ err.span_suggestion(
+ start,
+ "consider separating array elements with a comma",
+ ",".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+ false
+ }
+
fn confirm_builtin_call(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
@@ -422,7 +452,9 @@
_ => Res::Err,
};
- err.span_label(call_expr.span, "call expression requires function");
+ if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
+ err.span_label(call_expr.span, "call expression requires function");
+ }
if let Some(span) = self.tcx.hir().res_span(def) {
let callee_ty = callee_ty.to_string();
@@ -596,7 +628,7 @@
for (method_arg_ty, self_arg_ty) in
iter::zip(method_sig.inputs().iter().skip(1), self.fn_sig.inputs())
{
- fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty);
+ fcx.demand_eqtype(self.call_expr.span, *self_arg_ty, *method_arg_ty);
}
fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index a397ee7..56b6c09 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -328,16 +328,28 @@
err.emit();
}
CastError::CastToChar => {
- type_error_struct!(
+ let mut err = type_error_struct!(
fcx.tcx.sess,
self.span,
self.expr_ty,
E0604,
"only `u8` can be cast as `char`, not `{}`",
self.expr_ty
- )
- .span_label(self.span, "invalid cast")
- .emit();
+ );
+ err.span_label(self.span, "invalid cast");
+ if self.expr_ty.is_numeric() {
+ err.span_help(
+ self.span,
+ if self.expr_ty == fcx.tcx.types.i8 {
+ "try casting from `u8` instead"
+ } else if self.expr_ty == fcx.tcx.types.u32 {
+ "try `char::from_u32` instead"
+ } else {
+ "try `char::from_u32` instead (via a `u32`)"
+ },
+ );
+ }
+ err.emit();
}
CastError::NonScalar => {
let mut err = type_error_struct!(
@@ -357,7 +369,7 @@
.try_coerce(
self.expr,
fcx.tcx.mk_ref(
- &ty::RegionKind::ReErased,
+ fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: expr_ty, mutbl },
),
self.cast_ty,
@@ -407,7 +419,7 @@
.try_coerce(
self.expr,
fcx.tcx.mk_ref(
- &ty::RegionKind::ReErased,
+ fcx.tcx.lifetimes.re_erased,
TypeAndMut { ty: self.expr_ty, mutbl },
),
self.cast_ty,
@@ -873,7 +885,7 @@
});
// this will report a type mismatch if needed
- fcx.demand_eqtype(self.span, ety, m_cast.ty);
+ fcx.demand_eqtype(self.span, *ety, m_cast.ty);
return Ok(CastKind::ArrayPtrCast);
}
}
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index fd7b3a5..1650a62 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -12,11 +12,12 @@
use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::layout::MAX_SIMD_LANES;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
@@ -268,7 +269,7 @@
ty::Adt(ref adt, _) => {
adt.did == panic_info_did
&& mutbl == hir::Mutability::Not
- && *region != RegionKind::ReStatic
+ && !region.is_static()
}
_ => false,
},
@@ -381,12 +382,17 @@
tcx.sess,
field_span,
E0740,
- "unions may not contain fields that need dropping"
+ "unions cannot contain fields that may need dropping"
+ )
+ .note(
+ "a type is guaranteed not to need dropping \
+ when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type",
)
.multipart_suggestion_verbose(
- "wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped",
+ "when the type does not implement `Copy`, \
+ wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped",
vec![
- (ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")),
+ (ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()),
(ty_span.shrink_to_hi(), ">".into()),
],
Applicability::MaybeIncorrect,
@@ -462,17 +468,14 @@
debug!(?item, ?span);
struct FoundParentLifetime;
- struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics);
+ struct FindParentLifetimeVisitor<'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.1.parent_count as u32 {
+ if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
+ if index < self.0.parent_count as u32 {
return ControlFlow::Break(FoundParentLifetime);
} else {
return ControlFlow::CONTINUE;
@@ -482,8 +485,8 @@
r.super_visit_with(self)
}
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::ConstKind::Unevaluated(..) = c.val {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ConstKind::Unevaluated(..) = c.val() {
// FIXME(#72219) We currently don't detect lifetimes within substs
// which would violate this check. Even though the particular substitution is not used
// within the const, this should still be fixed.
@@ -502,32 +505,34 @@
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.tcx, self.generics))
+ t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
.map_break(|FoundParentLifetime| t)
}
}
}
impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
- type Map = rustc_middle::hir::map::Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
- [PathSegment { res: Some(Res::SelfTy(_, impl_ref)), .. }] => {
+ [
+ PathSegment {
+ res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }),
+ ..
+ },
+ ] => {
let impl_ty_name =
impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
self.selftys.push((path.span, impl_ty_name));
@@ -626,6 +631,7 @@
///
/// Without this check the above code is incorrectly accepted: we would ICE if
/// some tried, for example, to clone an `Option<X<&mut ()>>`.
+#[instrument(level = "debug", skip(tcx))]
fn check_opaque_meets_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
@@ -633,17 +639,14 @@
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
- match origin {
- // Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
- // Can have different predicates to their defining use
- hir::OpaqueTyOrigin::TyAlias => {}
- }
-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let param_env = tcx.param_env(def_id);
+ let defining_use_anchor = match *origin {
+ hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
+ hir::OpaqueTyOrigin::TyAlias => def_id,
+ };
+ let param_env = tcx.param_env(defining_use_anchor);
- tcx.infer_ctxt().enter(move |infcx| {
+ tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
let inh = Inherited::new(infcx, def_id);
let infcx = &inh.infcx;
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
@@ -656,16 +659,15 @@
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)
- .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, substs))
- {
+ let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
+ trace!(?hidden_type);
+ match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
Err(ty_err) => tcx.sess.delay_span_bug(
- opaque_defn.definition_span,
+ span,
&format!(
- "could not unify `{}` with revealed type:\n{}",
- opaque_defn.concrete_ty, ty_err,
+ "could not check bounds on revealed type `{}`:\n{}",
+ hidden_type, ty_err,
),
),
}
@@ -678,10 +680,17 @@
infcx.report_fulfillment_errors(&errors, None, false);
}
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let fcx = FnCtxt::new(&inh, param_env, hir_id);
- fcx.regionck_item(hir_id, span, FxHashSet::default());
+ match origin {
+ // Checked when type checking the function containing them.
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
+ // Can have different predicates to their defining use
+ hir::OpaqueTyOrigin::TyAlias => {
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let fcx = FnCtxt::new(&inh, param_env, hir_id);
+ fcx.regionck_item(hir_id, span, FxHashSet::default());
+ }
+ }
});
}
@@ -841,14 +850,8 @@
trait_def: &ty::TraitDef,
trait_item: &ty::AssocItem,
impl_id: DefId,
- impl_item: &hir::ImplItem<'_>,
+ impl_item: &hir::ImplItemRef,
) {
- let kind = match impl_item.kind {
- hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
- hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
- hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
- };
-
let ancestors = match trait_def.ancestors(tcx, impl_id) {
Ok(ancestors) => ancestors,
Err(_) => return,
@@ -857,7 +860,7 @@
if parent.is_from_trait() {
None
} else {
- Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+ Some((parent, parent.item(tcx, trait_item.def_id)))
}
});
@@ -894,7 +897,7 @@
}
}
-pub(super) fn check_impl_items_against_trait<'tcx>(
+fn check_impl_items_against_trait<'tcx>(
tcx: TyCtxt<'tcx>,
full_impl_span: Span,
impl_id: LocalDefId,
@@ -926,174 +929,111 @@
}
}
- // Locate trait definition and items
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
- let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
- let associated_items = tcx.associated_items(impl_trait_ref.def_id);
- // Check existing impl methods to see if they are both present in trait
- // and compatible with trait signature
- for impl_item in impl_items {
- let ty_impl_item = tcx.associated_item(impl_item.def_id);
-
- let mut items =
- associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
-
- let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
- let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
- (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
- (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
- (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
- _ => false,
- };
-
- // If we don't have a compatible item, we'll use the first one whose name matches
- // to report an error.
- let mut compatible_kind = is_compatible(&ty_trait_item);
- let mut trait_item = ty_trait_item;
-
- if !compatible_kind {
- if let Some(ty_trait_item) = items.find(is_compatible) {
- compatible_kind = true;
- trait_item = ty_trait_item;
- }
- }
-
- (compatible_kind, trait_item)
+ for impl_item in impl_item_refs {
+ let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+ let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
+ tcx.associated_item(trait_item_id)
} else {
+ // Checked in `associated_item`.
+ tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
continue;
};
-
- if compatible_kind {
- match impl_item.kind {
- hir::ImplItemKind::Const(..) => {
- // Find associated const definition.
- compare_const_impl(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- );
- }
- hir::ImplItemKind::Fn(..) => {
- let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- compare_impl_method(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- opt_trait_span,
- );
- }
- hir::ImplItemKind::TyAlias(impl_ty) => {
- let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- compare_ty_impl(
- tcx,
- &ty_impl_item,
- impl_ty.span,
- &ty_trait_item,
- impl_trait_ref,
- opt_trait_span,
- );
- }
+ let impl_item_full = tcx.hir().impl_item(impl_item.id);
+ match impl_item_full.kind {
+ hir::ImplItemKind::Const(..) => {
+ // Find associated const definition.
+ compare_const_impl(
+ tcx,
+ &ty_impl_item,
+ impl_item.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ );
}
-
- check_specialization_validity(
- tcx,
- trait_def,
- &ty_trait_item,
- impl_id.to_def_id(),
- impl_item,
- );
- } else {
- report_mismatch_error(
- tcx,
- ty_trait_item.def_id,
- impl_trait_ref,
- impl_item,
- &ty_impl_item,
- );
+ hir::ImplItemKind::Fn(..) => {
+ let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+ compare_impl_method(
+ tcx,
+ &ty_impl_item,
+ impl_item.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ opt_trait_span,
+ );
+ }
+ hir::ImplItemKind::TyAlias(impl_ty) => {
+ let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+ compare_ty_impl(
+ tcx,
+ &ty_impl_item,
+ impl_ty.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ opt_trait_span,
+ );
+ }
}
+
+ check_specialization_validity(
+ tcx,
+ trait_def,
+ &ty_trait_item,
+ impl_id.to_def_id(),
+ impl_item,
+ );
}
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
- let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
// Check for missing items from trait
let mut missing_items = Vec::new();
- for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
+
+ let mut must_implement_one_of: Option<&[Ident]> =
+ trait_def.must_implement_one_of.as_deref();
+
+ for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
let is_implemented = ancestors
- .leaf_def(tcx, trait_item.ident, trait_item.kind)
- .map(|node_item| !node_item.defining_node.is_from_trait())
- .unwrap_or(false);
+ .leaf_def(tcx, trait_item_id)
+ .map_or(false, |node_item| node_item.item.defaultness.has_value());
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
- if !trait_item.defaultness.has_value() {
- missing_items.push(*trait_item);
+ missing_items.push(tcx.associated_item(trait_item_id));
+ }
+
+ if let Some(required_items) = &must_implement_one_of {
+ // true if this item is specifically implemented in this impl
+ let is_implemented_here = ancestors
+ .leaf_def(tcx, trait_item_id)
+ .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+
+ if is_implemented_here {
+ let trait_item = tcx.associated_item(trait_item_id);
+ if required_items.contains(&trait_item.ident(tcx)) {
+ must_implement_one_of = None;
+ }
}
}
}
if !missing_items.is_empty() {
+ let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
}
+
+ if let Some(missing_items) = must_implement_one_of {
+ let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
+ let attr_span = tcx
+ .get_attrs(impl_trait_ref.def_id)
+ .iter()
+ .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+ .map(|attr| attr.span);
+
+ missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
+ }
}
}
-#[inline(never)]
-#[cold]
-fn report_mismatch_error<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_item_def_id: DefId,
- impl_trait_ref: ty::TraitRef<'tcx>,
- impl_item: &hir::ImplItem<'_>,
- ty_impl_item: &ty::AssocItem,
-) {
- let mut err = match impl_item.kind {
- hir::ImplItemKind::Const(..) => {
- // Find associated const definition.
- struct_span_err!(
- tcx.sess,
- impl_item.span,
- E0323,
- "item `{}` is an associated const, which doesn't match its trait `{}`",
- ty_impl_item.ident,
- impl_trait_ref.print_only_trait_path()
- )
- }
-
- hir::ImplItemKind::Fn(..) => {
- struct_span_err!(
- tcx.sess,
- impl_item.span,
- E0324,
- "item `{}` is an associated method, which doesn't match its trait `{}`",
- ty_impl_item.ident,
- impl_trait_ref.print_only_trait_path()
- )
- }
-
- hir::ImplItemKind::TyAlias(_) => {
- struct_span_err!(
- tcx.sess,
- impl_item.span,
- E0325,
- "item `{}` is an associated type, which doesn't match its trait `{}`",
- ty_impl_item.ident,
- impl_trait_ref.print_only_trait_path()
- )
- }
- };
-
- err.span_label(impl_item.span, "does not match trait");
- if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
- err.span_label(trait_span, "item in trait");
- }
- err.emit();
-}
-
/// Checks whether a type can be represented in memory. In particular, it
/// identifies types that contain themselves without indirection through a
/// pointer, which would mean their size is unbounded.
@@ -1271,7 +1211,7 @@
if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
if !stack.contains(&def.did) {
if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
- defs.push((def.did, field.ident.span));
+ defs.push((def.did, field.ident(tcx).span));
return Some(defs);
}
}
@@ -1408,7 +1348,7 @@
let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
let i_span = match variant_i.disr_expr {
Some(ref expr) => tcx.hir().span(expr.hir_id),
- None => tcx.hir().span(variant_i_hir_id),
+ None => tcx.def_span(variant_did),
};
let span = match v.disr_expr {
Some(ref expr) => tcx.hir().span(expr.hir_id),
@@ -1475,7 +1415,7 @@
return;
}
- for leaf in ty.walk(tcx) {
+ for leaf in ty.walk() {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if let ty::Param(param) = leaf_ty.kind() {
debug!("found use of ty param {:?}", param);
@@ -1534,8 +1474,8 @@
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
let mut label = false;
- if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
- let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
+ if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+ let typeck_results = tcx.typeck(def_id);
if visitor
.returns
.iter()
@@ -1573,10 +1513,6 @@
{
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, _) => {
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index c87ab0d..3c62683 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -279,7 +279,8 @@
return None;
};
- let ret_param_ty = projection.skip_binder().ty;
+ // Since this is a return parameter type it is safe to unwrap.
+ let ret_param_ty = projection.skip_binder().term.ty().unwrap();
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
@@ -449,7 +450,7 @@
.skip_binder()
.inputs()
.iter()
- .map(|ty| ArgKind::from_expected_ty(ty, None))
+ .map(|ty| ArgKind::from_expected_ty(*ty, None))
.collect();
let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) {
Some((sp, args)) => (Some(sp), args),
@@ -706,9 +707,10 @@
// Extract the type from the projection. Note that there can
// be no bound variables in this type because the "self type"
// does not have any regions in it.
- let output_ty = self.resolve_vars_if_possible(predicate.ty);
+ let output_ty = self.resolve_vars_if_possible(predicate.term);
debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
- Some(output_ty)
+ // This is a projection on a Fn trait so will always be a type.
+ Some(output_ty.ty().unwrap())
}
/// Converts the types that the user supplied, in case that doing
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 6192c77..be7ac00 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -142,7 +142,7 @@
where
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
{
- self.unify(&a, &b)
+ self.unify(a, b)
.and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
}
@@ -472,7 +472,7 @@
}
};
adjustments.push(Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
+ kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)),
target: ty,
});
@@ -1575,7 +1575,7 @@
expected,
found,
can_suggest,
- fcx.tcx.hir().get_parent_item(id),
+ fcx.tcx.hir().local_def_id_to_hir_id(fcx.tcx.hir().get_parent_item(id)),
);
}
if !pointing_at_return_type {
@@ -1584,13 +1584,19 @@
}
let parent_id = fcx.tcx.hir().get_parent_item(id);
- let parent_item = fcx.tcx.hir().get(parent_id);
+ let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
if let (Some((expr, _)), Some((fn_decl, _, _))) =
(expression, fcx.get_node_fn_decl(parent_item))
{
fcx.suggest_missing_break_or_return_expr(
- &mut err, expr, fn_decl, expected, found, id, parent_id,
+ &mut err,
+ expr,
+ fn_decl,
+ expected,
+ found,
+ id,
+ fcx.tcx.hir().local_def_id_to_hir_id(parent_id),
);
}
@@ -1667,10 +1673,10 @@
],
Applicability::MachineApplicable,
);
- let sugg = vec![sp, cause.span]
+ let sugg = [sp, cause.span]
.into_iter()
.flat_map(|sp| {
- vec![
+ [
(sp.shrink_to_lo(), "Box::new(".to_string()),
(sp.shrink_to_hi(), ")".to_string()),
]
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index c942baf..38449c2 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -300,7 +300,7 @@
cause.span(tcx),
E0053,
"method `{}` has an incompatible type for trait",
- trait_m.ident
+ trait_m.name
);
match &terr {
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
@@ -377,9 +377,9 @@
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Types(ExpectedFound {
- expected: trait_fty,
- found: impl_fty,
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_fty.into(),
+ found: impl_fty.into(),
})),
&terr,
false,
@@ -435,16 +435,24 @@
if trait_params != impl_params {
let item_kind = assoc_item_kind_str(impl_m);
let def_span = tcx.sess.source_map().guess_head_span(span);
- let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span);
+ let span = impl_m
+ .def_id
+ .as_local()
+ .and_then(|did| tcx.hir().get_generics(did))
+ .map_or(def_span, |g| g.span);
let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
let def_sp = tcx.sess.source_map().guess_head_span(sp);
- tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)
+ trait_m
+ .def_id
+ .as_local()
+ .and_then(|did| tcx.hir().get_generics(did))
+ .map_or(def_sp, |g| g.span)
});
tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
span,
item_kind,
- ident: impl_m.ident,
+ ident: impl_m.ident(tcx),
generics_span,
});
return Err(ErrorReported);
@@ -532,14 +540,14 @@
impl_m_span,
E0185,
"method `{}` has a `{}` declaration in the impl, but not in the trait",
- trait_m.ident,
+ trait_m.name,
self_descr
);
err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
err.span_label(span, format!("trait method declared without `{}`", self_descr));
} else {
- err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
+ err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx));
}
err.emit();
return Err(ErrorReported);
@@ -552,14 +560,14 @@
impl_m_span,
E0186,
"method `{}` has a `{}` declaration in the trait, but not in the impl",
- trait_m.ident,
+ trait_m.name,
self_descr
);
err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{}` used in trait", self_descr));
} else {
- err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
+ err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx));
}
err.emit();
return Err(ErrorReported);
@@ -632,7 +640,7 @@
"{} `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
item_kind,
- trait_.ident,
+ trait_.name,
impl_count,
pluralize!(impl_count),
trait_count,
@@ -739,7 +747,7 @@
impl_span,
E0050,
"method `{}` has {} but the declaration in trait `{}` has {}",
- trait_m.ident,
+ trait_m.name,
potentially_plural_count(impl_number_args, "parameter"),
tcx.def_path_str(trait_m.def_id),
trait_number_args
@@ -753,7 +761,7 @@
),
);
} else {
- err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
+ err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx));
}
err.span_label(
impl_span,
@@ -803,7 +811,7 @@
impl_span,
E0643,
"method `{}` has incompatible signature for trait",
- trait_m.ident
+ trait_m.name
);
err.span_label(trait_span, "declaration in trait here");
match (impl_synthetic, trait_synthetic) {
@@ -873,13 +881,6 @@
}
}
}
- type Map = intravisit::ErasedMap<'v>;
- fn nested_visit_map(
- &mut self,
- ) -> intravisit::NestedVisitorMap<Self::Map>
- {
- intravisit::NestedVisitorMap::None
- }
}
let mut visitor = Visitor(None, impl_def_id);
for ty in input_tys {
@@ -964,7 +965,7 @@
*impl_span,
E0053,
"method `{}` has an incompatible const parameter type for trait",
- trait_m.ident
+ trait_m.name
);
err.span_note(
trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
@@ -1052,7 +1053,7 @@
cause.span,
E0326,
"implemented const `{}` has an incompatible type for trait",
- trait_c.ident
+ trait_c.name
);
let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
@@ -1067,9 +1068,9 @@
&mut diag,
&cause,
trait_c_span.map(|span| (span, "type in trait".to_owned())),
- Some(infer::ValuePairs::Types(ExpectedFound {
- expected: trait_ty,
- found: impl_ty,
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_ty.into(),
+ found: impl_ty.into(),
})),
&terr,
false,
@@ -1305,7 +1306,7 @@
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
- tcx.mk_const(ty::Const {
+ tcx.mk_const(ty::ConstS {
ty: tcx.type_of(param.def_id),
val: ty::ConstKind::Bound(
ty::INNERMOST,
@@ -1352,7 +1353,7 @@
item_def_id: trait_ty.def_id,
substs: rebased_substs,
},
- ty: impl_ty_value,
+ term: impl_ty_value.into(),
},
bound_vars,
)
@@ -1377,7 +1378,14 @@
let mut selcx = traits::SelectionContext::new(&infcx);
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
- let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+ let normalize_cause = ObligationCause::new(
+ impl_ty_span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CheckAssociatedTypeBounds {
+ impl_item_def_id: impl_ty.def_id,
+ trait_item_def_id: trait_ty.def_id,
+ },
+ );
let mk_cause = |span: Span| {
let code = if span.is_dummy() {
traits::MiscObligation
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index b7e276b..4f180d8 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::error::{ExpectedFound, TypeError};
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::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span};
use super::method::probe;
@@ -24,16 +24,15 @@
pub fn emit_coerce_suggestions(
&self,
err: &mut DiagnosticBuilder<'_>,
- expr: &hir::Expr<'_>,
+ expr: &hir::Expr<'tcx>,
expr_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
error: TypeError<'tcx>,
) {
self.annotate_expected_due_to_let_ty(err, expr, error);
- self.suggest_box_deref(err, expr, expected, expr_ty);
- self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
+ self.suggest_compatible_variants(err, expr, expected, expr_ty);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
return;
}
@@ -110,7 +109,7 @@
pub fn demand_coerce(
&self,
- expr: &hir::Expr<'_>,
+ expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -130,7 +129,7 @@
/// will be permitted if the diverges flag is currently "always".
pub fn demand_coerce_diag(
&self,
- expr: &hir::Expr<'_>,
+ expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -259,23 +258,6 @@
}
}
- fn suggest_box_deref(
- &self,
- err: &mut DiagnosticBuilder<'_>,
- expr: &hir::Expr<'_>,
- expected: Ty<'tcx>,
- expr_ty: Ty<'tcx>,
- ) {
- if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
- err.span_suggestion_verbose(
- expr.span.shrink_to_lo(),
- "try dereferencing the `Box`",
- "*".to_string(),
- Applicability::MachineApplicable,
- );
- }
- }
-
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(
@@ -356,31 +338,40 @@
})
.collect();
- if let [variant] = &compatible_variants[..] {
- // Just a single matching variant.
- err.multipart_suggestion(
- &format!("try wrapping the expression in `{}`", variant),
- vec![
- (expr.span.shrink_to_lo(), format!("{}(", variant)),
- (expr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- } else if compatible_variants.len() > 1 {
- // More than one matching variant.
- err.multipart_suggestions(
- &format!(
- "try wrapping the expression in a variant of `{}`",
- self.tcx.def_path_str(expected_adt.did)
- ),
- compatible_variants.into_iter().map(|variant| {
+ let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!("{}: ", ident),
+ None => String::new(),
+ };
+
+ match &compatible_variants[..] {
+ [] => { /* No variants to format */ }
+ [variant] => {
+ // Just a single matching variant.
+ err.multipart_suggestion_verbose(
+ &format!("try wrapping the expression in `{}`", variant),
vec![
- (expr.span.shrink_to_lo(), format!("{}(", variant)),
+ (expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
(expr.span.shrink_to_hi(), ")".to_string()),
- ]
- }),
- Applicability::MaybeIncorrect,
- );
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ // More than one matching variant.
+ err.multipart_suggestions(
+ &format!(
+ "try wrapping the expression in a variant of `{}`",
+ self.tcx.def_path_str(expected_adt.did)
+ ),
+ compatible_variants.into_iter().map(|variant| {
+ vec![
+ (expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
+ (expr.span.shrink_to_hi(), ")".to_string()),
+ ]
+ }),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
}
@@ -473,18 +464,18 @@
let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id);
let hir = self.tcx.hir().find(expr_parent);
let closure_params_len = closure_fn_decl.inputs.len();
- let (method_path, method_span, method_expr) = match (hir, closure_params_len) {
+ let (method_path, method_expr) = match (hir, closure_params_len) {
(
Some(Node::Expr(hir::Expr {
- kind: hir::ExprKind::MethodCall(path, span, expr, _),
+ kind: hir::ExprKind::MethodCall(segment, expr, _),
..
})),
1,
- ) => (path, span, expr),
+ ) => (segment, expr),
_ => return None,
};
- let self_ty = self.typeck_results.borrow().node_type(method_expr[0].hir_id);
+ let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
let self_ty = format!("{:?}", self_ty);
let name = method_path.ident.name;
let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
@@ -492,42 +483,54 @@
|| self_ty.starts_with("std::option::Option")
|| self_ty.starts_with("std::result::Result"))
&& (name == sym::map || name == sym::and_then);
- match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) {
+ match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
(true, Ok(src)) => {
let suggestion = format!("as_ref().{}", src);
- Some((*method_span, "consider using `as_ref` instead", suggestion))
+ Some((method_path.ident.span, "consider using `as_ref` instead", suggestion))
}
_ => None,
}
}
- crate fn is_hir_id_from_struct_pattern_shorthand_field(
+ crate fn maybe_get_struct_pattern_shorthand_field(
&self,
- hir_id: hir::HirId,
- sp: Span,
- ) -> bool {
- let sm = self.sess().source_map();
- let parent_id = self.tcx.hir().get_parent_node(hir_id);
- if let Some(parent) = self.tcx.hir().find(parent_id) {
- // Account for fields
- if let Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) = parent
- {
- if let Ok(src) = sm.span_to_snippet(sp) {
- for field in *fields {
- if field.ident.as_str() == src && field.is_shorthand {
- return true;
- }
+ expr: &hir::Expr<'_>,
+ ) -> Option<Symbol> {
+ let hir = self.tcx.hir();
+ let local = match expr {
+ hir::Expr {
+ kind:
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path {
+ res: hir::def::Res::Local(_),
+ segments: [hir::PathSegment { ident, .. }],
+ ..
+ },
+ )),
+ ..
+ } => Some(ident),
+ _ => None,
+ }?;
+
+ match hir.find(hir.get_parent_node(expr.hir_id))? {
+ Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => {
+ for field in *fields {
+ if field.ident.name == local.name && field.is_shorthand {
+ return Some(local.name);
}
}
}
+ _ => {}
}
- false
+
+ None
}
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
- crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
- match self.tcx.hir().find(hir_id)? {
- Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
+ crate fn maybe_get_block_expr(&self, expr: &hir::Expr<'tcx>) -> Option<&'tcx hir::Expr<'tcx>> {
+ match expr {
+ hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
_ => None,
}
}
@@ -565,7 +568,7 @@
/// `&mut`!".
pub fn check_ref(
&self,
- expr: &hir::Expr<'_>,
+ expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
) -> Option<(Span, &'static str, String, Applicability, bool /* verbose */)> {
@@ -583,9 +586,6 @@
s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
};
- let is_struct_pat_shorthand_field =
- self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
-
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
let expr = expr.peel_drop_temps();
@@ -643,8 +643,9 @@
};
if self.can_coerce(ref_ty, expected) {
let mut sugg_sp = sp;
- if let hir::ExprKind::MethodCall(ref segment, sp, ref args, _) = expr.kind {
- let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(sp));
+ if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind {
+ let clone_trait =
+ self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
if let ([arg], Some(true), sym::clone) = (
&args[..],
self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
@@ -679,11 +680,12 @@
false,
));
}
- let field_name = if is_struct_pat_shorthand_field {
- format!("{}: ", sugg_expr)
- } else {
- String::new()
+
+ let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!("{}: ", ident),
+ None => String::new(),
};
+
if let Some(hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Assign(left_expr, ..),
..
@@ -713,14 +715,14 @@
hir::Mutability::Mut => (
sp,
"consider mutably borrowing here",
- format!("{}&mut {}", field_name, sugg_expr),
+ format!("{}&mut {}", prefix, sugg_expr),
Applicability::MachineApplicable,
false,
),
hir::Mutability::Not => (
sp,
"consider borrowing here",
- format!("{}&{}", field_name, sugg_expr),
+ format!("{}&{}", prefix, sugg_expr),
Applicability::MachineApplicable,
false,
),
@@ -732,7 +734,7 @@
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
_,
&ty::Ref(_, checked, _),
- ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
+ ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => {
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
@@ -857,36 +859,40 @@
Applicability::MachineApplicable,
false,
));
- } else if self.infcx.type_is_copy_modulo_regions(
- self.param_env,
- expected,
- sp,
- ) {
- // For this suggestion to make sense, the type would need to be `Copy`.
- if let Ok(code) = sm.span_to_snippet(expr.span) {
- let message = if checked_ty.is_region_ptr() {
- "consider dereferencing the borrow"
- } else {
- "consider dereferencing the type"
- };
- 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) {
- (expr.span.shrink_to_lo(), "*".to_string())
- } else {
- (expr.span.shrink_to_lo(), "*".to_string())
- };
- return Some((
- span,
- message,
- suggestion,
- Applicability::MachineApplicable,
- true,
- ));
- }
+ }
+
+ // For this suggestion to make sense, the type would need to be `Copy`,
+ // or we have to be moving out of a `Box<T>`
+ if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
+ || checked_ty.is_box()
+ {
+ let message = if checked_ty.is_box() {
+ "consider unboxing the value"
+ } else if checked_ty.is_region_ptr() {
+ "consider dereferencing the borrow"
+ } else {
+ "consider dereferencing the type"
+ };
+ let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!("{}: ", ident),
+ None => String::new(),
+ };
+ let (span, suggestion) = 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) {
+ // prefix should be empty here..
+ (expr.span.shrink_to_lo(), "*".to_string())
+ } else {
+ (expr.span.shrink_to_lo(), format!("{}*", prefix))
+ };
+ return Some((
+ span,
+ message,
+ suggestion,
+ Applicability::MachineApplicable,
+ true,
+ ));
}
}
}
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 3cc66aa..22d2022 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -184,8 +184,6 @@
// absent. So we report an error that the Drop impl injected a
// predicate that is not present on the struct definition.
- let self_type_hir_id = tcx.hir().local_def_id_to_hir_id(self_type_did);
-
// We can assume the predicates attached to struct/enum definition
// hold.
let generic_assumptions = tcx.predicates_of(self_type_did);
@@ -231,7 +229,13 @@
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
(ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
- relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
+ // Since struct predicates cannot have ~const, project the impl predicate
+ // onto one that ignores the constness. This is equivalent to saying that
+ // we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
+ // in the impl.
+ let non_const_a =
+ ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
+ relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
}
(ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
@@ -252,7 +256,7 @@
};
if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) {
- let item_span = tcx.hir().span(self_type_hir_id);
+ let item_span = tcx.def_span(self_type_did);
let self_descr = tcx.def_kind(self_type_did).descr(self_type_did.to_def_id());
struct_span_err!(
tcx.sess,
@@ -358,9 +362,9 @@
fn consts(
&mut self,
- a: &'tcx ty::Const<'tcx>,
- b: &'tcx ty::Const<'tcx>,
- ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b);
ty::relate::super_relate_consts(self, a, b)
}
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 621938c..0586351 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -31,10 +31,11 @@
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ExprKind, QPath};
+use rustc_hir::{ExprKind, HirId, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
+use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
@@ -230,8 +231,8 @@
// we skip issuing a warning because it is autogenerated code.
ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {}
ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"),
- ExprKind::MethodCall(_, ref span, _, _) => {
- self.warn_if_unreachable(expr.hir_id, *span, "call")
+ ExprKind::MethodCall(segment, ..) => {
+ self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call")
}
_ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"),
}
@@ -282,12 +283,6 @@
}
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
- ExprKind::LlvmInlineAsm(asm) => {
- for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
- self.check_expr(expr);
- }
- tcx.mk_unit()
- }
ExprKind::Break(destination, ref expr_opt) => {
self.check_expr_break(destination, expr_opt.as_deref(), expr)
}
@@ -312,8 +307,8 @@
}
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
- ExprKind::MethodCall(segment, span, args, _) => {
- self.check_method_call(expr, segment, span, args, expected)
+ ExprKind::MethodCall(segment, args, _) => {
+ self.check_method_call(expr, segment, args, expected)
}
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
ExprKind::Type(e, t) => {
@@ -426,9 +421,9 @@
// Places may legitimately have unsized types.
// For example, dereferences of a fat pointer and
// the last field of a struct can be unsized.
- ExpectHasType(ty)
+ ExpectHasType(*ty)
} else {
- Expectation::rvalue_hint(self, ty)
+ Expectation::rvalue_hint(self, *ty)
}
}
_ => NoExpectation,
@@ -742,7 +737,7 @@
kind: hir::ImplItemKind::Fn(..),
span: encl_fn_span,
..
- })) = self.tcx.hir().find(encl_item_id)
+ })) = self.tcx.hir().find_by_def_id(encl_item_id)
{
// We are inside a function body, so reporting "return statement
// outside of function body" needs an explanation.
@@ -751,7 +746,7 @@
// If this didn't hold, we would not have to report an error in
// the first place.
- assert_ne!(encl_item_id, encl_body_owner_id);
+ assert_ne!(hir::HirId::make_owner(encl_item_id), encl_body_owner_id);
let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
let encl_body = self.tcx.hir().body(encl_body_id);
@@ -870,14 +865,22 @@
),
..
}) => {
- // We have a situation like `while Some(0) = value.get(0) {`, where `while let`
- // was more likely intended.
- err.span_suggestion_verbose(
- expr.span.shrink_to_lo(),
- "you might have meant to use pattern destructuring",
- "let ".to_string(),
- Applicability::MachineApplicable,
- );
+ // Check if our lhs is a child of the condition of a while loop
+ let expr_is_ancestor = std::iter::successors(Some(lhs.hir_id), |id| {
+ self.tcx.hir().find_parent_node(*id)
+ })
+ .take_while(|id| *id != parent)
+ .any(|id| id == expr.hir_id);
+ // if it is, then we have a situation like `while Some(0) = value.get(0) {`,
+ // where `while let` was more likely intended.
+ if expr_is_ancestor {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "you might have meant to use pattern destructuring",
+ "let ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
break;
}
hir::Node::Item(_)
@@ -1103,7 +1106,6 @@
&self,
expr: &'tcx hir::Expr<'tcx>,
segment: &hir::PathSegment<'_>,
- span: Span,
args: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
@@ -1111,6 +1113,7 @@
let rcvr_t = self.check_expr(&rcvr);
// no need to check for bot/err -- callee does that
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
+ let span = segment.ident.span;
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
Ok(method) => {
@@ -1226,7 +1229,7 @@
let body = self.tcx.hir().body(anon_const.body);
// Create a new function context.
- let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+ let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
@@ -1315,10 +1318,7 @@
base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
) -> Ty<'tcx> {
// Find the relevant variant
- let (variant, adt_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, expr.hir_id)
- {
- variant_ty
- } else {
+ let Some((variant, adt_ty)) = self.check_struct_path(qpath, expr.hir_id) else {
self.check_struct_fields_on_error(fields, base_expr);
return self.tcx.ty_error();
};
@@ -1376,7 +1376,7 @@
.fields
.iter()
.enumerate()
- .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field)))
+ .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field)))
.collect::<FxHashMap<_, _>>();
let mut seen_fields = FxHashMap::default();
@@ -1457,7 +1457,9 @@
expr_span,
self.field_ty(base_expr.span, f, base_subs),
);
- let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+ let ident = self
+ .tcx
+ .adjust_ident(f.ident(self.tcx), variant.def_id);
if let Some(_) = remaining_fields.remove(&ident) {
let target_ty =
self.field_ty(base_expr.span, f, substs);
@@ -1475,10 +1477,7 @@
&cause,
target_ty,
fru_ty,
- FieldMisMatch(
- variant.ident.name,
- ident.name,
- ),
+ FieldMisMatch(variant.name, ident.name),
)
.emit(),
}
@@ -1508,7 +1507,7 @@
}
} else {
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
- let base_ty = self.typeck_results.borrow().node_type(base_expr.hir_id);
+ let base_ty = self.typeck_results.borrow().expr_ty(*base_expr);
let same_adt = match (adt_ty.kind(), base_ty.kind()) {
(ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
_ => false,
@@ -1585,10 +1584,10 @@
) {
let len = remaining_fields.len();
- let mut displayable_field_names =
- remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();
-
- displayable_field_names.sort();
+ let mut displayable_field_names: Vec<&str> =
+ remaining_fields.keys().map(|ident| ident.as_str()).collect();
+ // sorting &str primitives here, sort_unstable is ok
+ displayable_field_names.sort_unstable();
let mut truncated_fields_error = String::new();
let remaining_fields_names = match &displayable_field_names[..] {
@@ -1665,7 +1664,7 @@
"{} `{}::{}` has no field named `{}`",
kind_name,
actual,
- variant.ident,
+ variant.name,
field.ident
),
_ => struct_span_err!(
@@ -1680,15 +1679,17 @@
},
ty,
);
+
+ let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap();
match variant.ctor_kind {
CtorKind::Fn => match ty.kind() {
ty::Adt(adt, ..) if adt.is_enum() => {
err.span_label(
- variant.ident.span,
+ variant_ident_span,
format!(
"`{adt}::{variant}` defined here",
adt = ty,
- variant = variant.ident,
+ variant = variant.name,
),
);
err.span_label(field.ident.span, "field does not exist");
@@ -1697,18 +1698,18 @@
&format!(
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
- variant = variant.ident,
+ variant = variant.name,
),
format!(
"{adt}::{variant}(/* fields */)",
adt = ty,
- variant = variant.ident,
+ variant = variant.name,
),
Applicability::HasPlaceholders,
);
}
_ => {
- err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
+ err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty));
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
@@ -1725,9 +1726,12 @@
_ => {
// prevent all specified fields from being suggested
let skip_fields = skip_fields.iter().map(|x| x.ident.name);
- if let Some(field_name) =
- Self::suggest_field_name(variant, field.ident.name, skip_fields.collect())
- {
+ if let Some(field_name) = self.suggest_field_name(
+ variant,
+ field.ident.name,
+ skip_fields.collect(),
+ expr_span,
+ ) {
err.span_suggestion(
field.ident.span,
"a field with a similar name exists",
@@ -1740,7 +1744,7 @@
if adt.is_enum() {
err.span_label(
field.ident.span,
- format!("`{}::{}` does not have this field", ty, variant.ident),
+ format!("`{}::{}` does not have this field", ty, variant.name),
);
} else {
err.span_label(
@@ -1748,7 +1752,8 @@
format!("`{}` does not have this field", ty),
);
}
- let available_field_names = self.available_field_names(variant);
+ let available_field_names =
+ self.available_field_names(variant, expr_span);
if !available_field_names.is_empty() {
err.note(&format!(
"available fields are: {}",
@@ -1764,23 +1769,31 @@
err.emit();
}
- // Return an hint about the closest match in field names
+ // Return a hint about the closest match in field names
fn suggest_field_name(
+ &self,
variant: &'tcx ty::VariantDef,
field: Symbol,
skip: Vec<Symbol>,
+ // The span where stability will be checked
+ span: Span,
) -> Option<Symbol> {
let names = variant
.fields
.iter()
.filter_map(|field| {
// ignore already set fields and private fields from non-local crates
- if skip.iter().any(|&x| x == field.ident.name)
+ // and unstable fields.
+ if skip.iter().any(|&x| x == field.name)
|| (!variant.def_id.is_local() && !field.vis.is_public())
+ || matches!(
+ self.tcx.eval_stability(field.did, None, span, None),
+ stability::EvalResult::Deny { .. }
+ )
{
None
} else {
- Some(field.ident.name)
+ Some(field.name)
}
})
.collect::<Vec<Symbol>>();
@@ -1788,18 +1801,27 @@
find_best_match_for_name(&names, field, None)
}
- fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<Symbol> {
+ fn available_field_names(
+ &self,
+ variant: &'tcx ty::VariantDef,
+ access_span: Span,
+ ) -> Vec<Symbol> {
variant
.fields
.iter()
.filter(|field| {
let def_scope = self
.tcx
- .adjust_ident_and_get_scope(field.ident, variant.def_id, self.body_id)
+ .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id)
.1;
field.vis.is_accessible_from(def_scope, self.tcx)
+ && !matches!(
+ self.tcx.eval_stability(field.did, None, access_span, None),
+ stability::EvalResult::Deny { .. }
+ )
})
- .map(|field| field.ident.name)
+ .filter(|field| !self.tcx.is_doc_hidden(field.did))
+ .map(|field| field.name)
.collect()
}
@@ -1834,8 +1856,9 @@
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id);
let fields = &base_def.non_enum_variant().fields;
- if let Some(index) =
- fields.iter().position(|f| f.ident.normalize_to_macros_2_0() == ident)
+ if let Some(index) = fields
+ .iter()
+ .position(|f| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
{
let field = &fields[index];
let field_ty = self.field_ty(expr.span, field, substs);
@@ -1913,10 +1936,15 @@
_ => return,
};
let mut add_label = true;
- if let ty::Adt(def, _) = output_ty.kind() {
+ if let ty::Adt(def, _) = output_ty.skip_binder().kind() {
// no field access on enum type
if !def.is_enum() {
- if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) {
+ if def
+ .non_enum_variant()
+ .fields
+ .iter()
+ .any(|field| field.ident(self.tcx) == field_ident)
+ {
add_label = false;
err.span_label(
field_ident.span,
@@ -1947,7 +1975,7 @@
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
field, base, expr, expr_t
);
- let mut err = self.no_such_field_err(field, expr_t);
+ let mut err = self.no_such_field_err(field, expr_t, base.hir_id);
match *expr_t.peel_refs().kind() {
ty::Array(_, len) => {
@@ -1957,7 +1985,7 @@
self.suggest_first_deref_field(&mut err, expr, base, field);
}
ty::Adt(def, _) if !def.is_enum() => {
- self.suggest_fields_on_recordish(&mut err, def, field);
+ self.suggest_fields_on_recordish(&mut err, def, field, expr.span);
}
ty::Param(param_ty) => {
self.point_at_param_definition(&mut err, param_ty);
@@ -2075,7 +2103,7 @@
.unwrap()
.fields
.iter()
- .any(|f| f.ident == field)
+ .any(|f| f.ident(self.tcx) == field)
{
if let Some(dot_loc) = expr_snippet.rfind('.') {
found = true;
@@ -2120,9 +2148,10 @@
err: &mut DiagnosticBuilder<'_>,
def: &'tcx ty::AdtDef,
field: Ident,
+ access_span: Span,
) {
if let Some(suggested_field_name) =
- Self::suggest_field_name(def.non_enum_variant(), field.name, vec![])
+ self.suggest_field_name(def.non_enum_variant(), field.name, vec![], access_span)
{
err.span_suggestion(
field.span,
@@ -2133,7 +2162,7 @@
} else {
err.span_label(field.span, "unknown field");
let struct_variant_def = def.non_enum_variant();
- let field_names = self.available_field_names(struct_variant_def);
+ let field_names = self.available_field_names(struct_variant_def, access_span);
if !field_names.is_empty() {
err.note(&format!(
"available fields are: {}",
@@ -2149,7 +2178,7 @@
expr: &hir::Expr<'_>,
base: &hir::Expr<'_>,
field: Ident,
- len: &ty::Const<'tcx>,
+ len: ty::Const<'tcx>,
) {
if let (Some(len), Ok(user_index)) =
(len.try_eval_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
@@ -2184,7 +2213,8 @@
fn no_such_field_err(
&self,
field: Ident,
- expr_t: &'tcx ty::TyS<'tcx>,
+ expr_t: Ty<'tcx>,
+ id: HirId,
) -> DiagnosticBuilder<'_> {
let span = field.span;
debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
@@ -2200,11 +2230,16 @@
);
// try to add a suggestion in case the field is a nested field of a field of the Adt
- if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) {
+ if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
for candidate_field in fields.iter() {
- if let Some(field_path) =
- self.check_for_nested_field(span, field, candidate_field, substs, vec![])
- {
+ if let Some(field_path) = self.check_for_nested_field(
+ span,
+ field,
+ candidate_field,
+ substs,
+ vec![],
+ self.tcx.parent_module(id).to_def_id(),
+ ) {
let field_path_str = field_path
.iter()
.map(|id| id.name.to_ident_string())
@@ -2256,13 +2291,14 @@
candidate_field: &ty::FieldDef,
subst: SubstsRef<'tcx>,
mut field_path: Vec<Ident>,
+ id: DefId,
) -> Option<Vec<Ident>> {
debug!(
"check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
span, candidate_field, field_path
);
- if candidate_field.ident == target_field {
+ if candidate_field.ident(self.tcx) == target_field {
Some(field_path)
} else if field_path.len() > 3 {
// For compile-time reasons and to avoid infinite recursion we only check for fields
@@ -2271,14 +2307,16 @@
} else {
// recursively search fields of `candidate_field` if it's a ty::Adt
- field_path.push(candidate_field.ident.normalize_to_macros_2_0());
+ field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
let field_ty = candidate_field.ty(self.tcx, subst);
- if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) {
+ if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
for field in nested_fields.iter() {
- let ident = field.ident.normalize_to_macros_2_0();
- if ident == target_field {
- return Some(field_path);
- } else {
+ let accessible = field.vis.is_accessible_from(id, self.tcx);
+ if accessible {
+ let ident = field.ident(self.tcx).normalize_to_macros_2_0();
+ if ident == target_field {
+ return Some(field_path);
+ }
let field_path = field_path.clone();
if let Some(path) = self.check_for_nested_field(
span,
@@ -2286,6 +2324,7 @@
field,
subst,
field_path,
+ id,
) {
return Some(path);
}
@@ -2407,7 +2446,7 @@
// allows them to be inferred based on how they are used later in the
// function.
if is_input {
- let ty = self.structurally_resolved_type(expr.span, &ty);
+ let ty = self.structurally_resolved_type(expr.span, ty);
match *ty.kind() {
ty::FnDef(..) => {
let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx));
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
index e5da33d..7214cdf 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -70,7 +70,7 @@
// 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);
+ fallback_has_occurred |= self.fallback_opaque_type_vars(*ty);
}
// See if we can make any more progress.
@@ -176,7 +176,7 @@
.type_var_origin(ty)
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
- let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
+ let oty = self.inner.borrow().opaque_types_vars.get(&ty).copied();
if let Some(opaque_ty) = oty {
debug!(
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 1aca291..2bdc3af 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -182,7 +182,7 @@
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
// type of `foo` (possibly adjusted), but we don't want to
// include that. We want just the `[_, u32]` part.
- if !method.substs.is_noop() {
+ if !method.substs.is_empty() {
let method_generics = self.tcx.generics_of(method.def_id);
if !method_generics.params.is_empty() {
let user_type_annotation = self.infcx.probe(|_| {
@@ -211,7 +211,7 @@
}
pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
- if !substs.is_noop() {
+ if !substs.is_empty() {
debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
@@ -235,7 +235,7 @@
) {
debug!("fcx {}", 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 },
@@ -315,11 +315,14 @@
}
// FIXME: currently we never try to compose autoderefs
// and ReifyFnPointer/UnsafeFnPointer, but we could.
- _ => bug!(
- "while adjusting {:?}, can't compose {:?} and {:?}",
- expr,
- entry.get(),
- adj
+ _ => self.tcx.sess.delay_span_bug(
+ expr.span,
+ &format!(
+ "while adjusting {:?}, can't compose {:?} and {:?}",
+ expr,
+ entry.get(),
+ adj
+ ),
),
};
*entry.get_mut() = adj;
@@ -489,7 +492,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);
@@ -498,14 +501,14 @@
ty
}
- pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+ pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
}
}
- pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
+ pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> {
let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
let c = ty::Const::from_anon_const(self.tcx, const_def_id);
self.register_wf_obligation(
@@ -520,7 +523,7 @@
&self,
ast_c: &hir::AnonConst,
param_def_id: DefId,
- ) -> &'tcx ty::Const<'tcx> {
+ ) -> ty::Const<'tcx> {
let const_def = ty::WithOptConstParam {
did: self.tcx.hir().local_def_id(ast_c.hir_id),
const_param_did: Some(param_def_id),
@@ -541,11 +544,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>(&self, t: T) -> bool
+ fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
where
T: TypeFoldable<'tcx>,
{
- t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types()
+ t.has_free_regions() || t.has_projections() || t.has_infer_types()
}
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
@@ -605,7 +608,7 @@
field: &'tcx ty::FieldDef,
substs: SubstsRef<'tcx>,
) -> Ty<'tcx> {
- self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
+ self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
}
pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
@@ -756,7 +759,7 @@
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
- let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
+ let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
// FIXME(#27336) can't use ? here, Try::from_error doesn't default
// to identity so the resulting type is not constrained.
@@ -964,7 +967,7 @@
if found != self.tcx.types.unit {
return;
}
- if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
+ if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind {
if self
.typeck_results
.borrow()
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index e796fe5..b69682b 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -28,6 +28,11 @@
use std::iter;
use std::slice;
+struct FnArgsAsTuple<'hir> {
+ first: &'hir hir::Expr<'hir>,
+ last: &'hir hir::Expr<'hir>,
+}
+
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();
@@ -127,136 +132,21 @@
let expected_arg_count = formal_input_tys.len();
- let param_count_error = |expected_count: usize,
- arg_count: usize,
- error_code: &str,
- c_variadic: bool,
- sugg_unit: bool| {
- let (span, start_span, args, ctor_of) = match &call_expr.kind {
- hir::ExprKind::Call(
- hir::Expr {
- span,
- kind:
- hir::ExprKind::Path(hir::QPath::Resolved(
- _,
- hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
- )),
- ..
- },
- args,
- ) => (*span, *span, &args[..], Some(of)),
- hir::ExprKind::Call(hir::Expr { span, .. }, args) => {
- (*span, *span, &args[..], None)
- }
- hir::ExprKind::MethodCall(path_segment, span, args, _) => (
- *span,
- // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
- path_segment
- .args
- .and_then(|args| args.args.iter().last())
- // Account for `foo.bar::<T>()`.
- .map(|arg| {
- // Skip the closing `>`.
- tcx.sess
- .source_map()
- .next_point(tcx.sess.source_map().next_point(arg.span()))
- })
- .unwrap_or(*span),
- &args[1..], // Skip the receiver.
- None, // methods are never ctors
- ),
- k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
- };
- let arg_spans = if provided_args.is_empty() {
- // foo()
- // ^^^-- supplied 0 arguments
- // |
- // expected 2 arguments
- vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
- } else {
- // foo(1, 2, 3)
- // ^^^ - - - supplied 3 arguments
- // |
- // expected 2 arguments
- args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
- };
+ // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args
+ let mut arg_count_error: Option<(usize, usize, &str, bool, Option<FnArgsAsTuple<'_>>)> =
+ None;
- let mut err = tcx.sess.struct_span_err_with_code(
- span,
- &format!(
- "this {} takes {}{} but {} {} supplied",
- match ctor_of {
- Some(CtorOf::Struct) => "struct",
- Some(CtorOf::Variant) => "enum variant",
- None => "function",
- },
- if c_variadic { "at least " } else { "" },
- potentially_plural_count(expected_count, "argument"),
- potentially_plural_count(arg_count, "argument"),
- if arg_count == 1 { "was" } else { "were" }
- ),
- DiagnosticId::Error(error_code.to_owned()),
- );
- let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
- for (i, span) in arg_spans.into_iter().enumerate() {
- err.span_label(
- span,
- if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
- );
- }
-
- if let Some(def_id) = fn_def_id {
- if let Some(def_span) = tcx.def_ident_span(def_id) {
- let mut spans: MultiSpan = def_span.into();
-
- let params = tcx
- .hir()
- .get_if_local(def_id)
- .and_then(|node| node.body_id())
- .into_iter()
- .map(|id| tcx.hir().body(id).params)
- .flatten();
-
- for param in params {
- spans.push_span_label(param.span, String::new());
- }
-
- let def_kind = tcx.def_kind(def_id);
- err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
- }
- }
-
- if sugg_unit {
- let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
- // remove closing `)` from the span
- let sugg_span = sugg_span.shrink_to_lo();
- err.span_suggestion(
- sugg_span,
- "expected the unit value `()`; create it with empty parentheses",
- String::from("()"),
- Applicability::MachineApplicable,
- );
- } else {
- err.span_label(
- span,
- format!(
- "expected {}{}",
- if c_variadic { "at least " } else { "" },
- potentially_plural_count(expected_count, "argument")
- ),
- );
- }
- err.emit();
- };
-
+ // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
match tuple_type.kind() {
- ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
- param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
- (self.err_args(provided_args.len()), vec![])
- }
+ // We expected a tuple and got a tuple
ty::Tuple(arg_types) => {
+ // Argument length differs
+ if arg_types.len() != provided_args.len() {
+ arg_count_error =
+ Some((arg_types.len(), provided_args.len(), "E0057", false, None));
+ }
let expected_input_tys = match expected_input_tys.get(0) {
Some(&ty) => match ty.kind() {
ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
@@ -267,6 +157,8 @@
(arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
}
_ => {
+ // Otherwise, there's a mismatch, so clear out what we're expecting, and set
+ // our input typs to err_args so we don't blow up the error messages
struct_span_err!(
tcx.sess,
call_span,
@@ -284,7 +176,8 @@
if supplied_arg_count >= expected_arg_count {
(formal_input_tys.to_vec(), expected_input_tys)
} else {
- param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
+ arg_count_error =
+ Some((expected_arg_count, supplied_arg_count, "E0060", false, None));
(self.err_args(supplied_arg_count), vec![])
}
} else {
@@ -296,8 +189,25 @@
} else {
false
};
- param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
+ // are we passing elements of a tuple without the tuple parentheses?
+ let expected_input_tys = if expected_input_tys.is_empty() {
+ // In most cases we can use expected_input_tys, but some callers won't have the type
+ // information, in which case we fall back to the types from the input expressions.
+ formal_input_tys
+ } else {
+ &*expected_input_tys
+ };
+
+ let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args);
+
+ arg_count_error = Some((
+ expected_arg_count,
+ supplied_arg_count,
+ "E0061",
+ sugg_unit,
+ sugg_tuple_wrap_args,
+ ));
(self.err_args(supplied_arg_count), vec![])
};
@@ -315,13 +225,15 @@
assert_eq!(expected_input_tys.len(), formal_input_tys.len());
+ let provided_arg_count: usize = provided_args.len();
+
// Keep track of the fully coerced argument types
- let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
+ let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count];
// We introduce a helper function to demand that a given argument satisfy a given input
// This is more complicated than just checking type equality, as arguments could be coerced
// This version writes those types back so further type checking uses the narrowed types
- let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
+ let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| {
let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
let provided_arg = &provided_args[idx];
@@ -340,13 +252,13 @@
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
// Keep track of these for below
- final_arg_types.push((idx, checked_ty, coerced_ty));
+ final_arg_types[idx] = Some((checked_ty, coerced_ty));
// Cause selection errors caused by resolving a single argument to point at the
// argument and not the call. This is otherwise redundant with the `demand_coerce`
// call immediately after, but it lets us customize the span pointed to in the
// fulfillment error to be more accurate.
- let _ =
+ let coerced_ty =
self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
self.point_at_arg_instead_of_call_if_possible(
@@ -358,6 +270,8 @@
);
});
+ final_arg_types[idx] = Some((checked_ty, coerced_ty));
+
// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
@@ -416,6 +330,134 @@
}
}
+ // If there was an error in parameter count, emit that here
+ if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) =
+ arg_count_error
+ {
+ let (span, start_span, args, ctor_of) = match &call_expr.kind {
+ hir::ExprKind::Call(
+ hir::Expr {
+ span,
+ kind:
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ _,
+ hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
+ )),
+ ..
+ },
+ args,
+ ) => (*span, *span, &args[..], Some(of)),
+ hir::ExprKind::Call(hir::Expr { span, .. }, args) => {
+ (*span, *span, &args[..], None)
+ }
+ hir::ExprKind::MethodCall(path_segment, args, _) => (
+ path_segment.ident.span,
+ // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
+ path_segment
+ .args
+ .and_then(|args| args.args.iter().last())
+ // Account for `foo.bar::<T>()`.
+ .map(|arg| {
+ // Skip the closing `>`.
+ tcx.sess
+ .source_map()
+ .next_point(tcx.sess.source_map().next_point(arg.span()))
+ })
+ .unwrap_or(path_segment.ident.span),
+ &args[1..], // Skip the receiver.
+ None, // methods are never ctors
+ ),
+ k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
+ };
+ let arg_spans = if provided_args.is_empty() {
+ // foo()
+ // ^^^-- supplied 0 arguments
+ // |
+ // expected 2 arguments
+ vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
+ } else {
+ // foo(1, 2, 3)
+ // ^^^ - - - supplied 3 arguments
+ // |
+ // expected 2 arguments
+ args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
+ };
+ let call_name = match ctor_of {
+ Some(CtorOf::Struct) => "struct",
+ Some(CtorOf::Variant) => "enum variant",
+ None => "function",
+ };
+ let mut err = tcx.sess.struct_span_err_with_code(
+ span,
+ &format!(
+ "this {} takes {}{} but {} {} supplied",
+ call_name,
+ if c_variadic { "at least " } else { "" },
+ potentially_plural_count(expected_count, "argument"),
+ potentially_plural_count(arg_count, "argument"),
+ if arg_count == 1 { "was" } else { "were" }
+ ),
+ DiagnosticId::Error(err_code.to_owned()),
+ );
+ let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
+ for (i, span) in arg_spans.into_iter().enumerate() {
+ err.span_label(
+ span,
+ if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
+ );
+ }
+ if let Some(def_id) = fn_def_id {
+ if let Some(def_span) = tcx.def_ident_span(def_id) {
+ let mut spans: MultiSpan = def_span.into();
+
+ let params = tcx
+ .hir()
+ .get_if_local(def_id)
+ .and_then(|node| node.body_id())
+ .into_iter()
+ .map(|id| tcx.hir().body(id).params)
+ .flatten();
+
+ for param in params {
+ spans.push_span_label(param.span, String::new());
+ }
+
+ let def_kind = tcx.def_kind(def_id);
+ err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+ }
+ }
+ if sugg_unit {
+ let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
+ // remove closing `)` from the span
+ let sugg_span = sugg_span.shrink_to_lo();
+ err.span_suggestion(
+ sugg_span,
+ "expected the unit value `()`; create it with empty parentheses",
+ String::from("()"),
+ Applicability::MachineApplicable,
+ );
+ } else if let Some(FnArgsAsTuple { first, last }) = sugg_tuple_wrap_args {
+ err.multipart_suggestion(
+ "use parentheses to construct a tuple",
+ vec![
+ (first.span.shrink_to_lo(), '('.to_string()),
+ (last.span.shrink_to_hi(), ')'.to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_label(
+ span,
+ format!(
+ "expected {}{}",
+ if c_variadic { "at least " } else { "" },
+ potentially_plural_count(expected_count, "argument")
+ ),
+ );
+ }
+ err.emit();
+ }
+
// We also need to make sure we at least write the ty of the other
// arguments which we skipped above.
if c_variadic {
@@ -452,6 +494,35 @@
}
}
+ fn suggested_tuple_wrap(
+ &self,
+ expected_input_tys: &[Ty<'tcx>],
+ provided_args: &'tcx [hir::Expr<'tcx>],
+ ) -> Option<FnArgsAsTuple<'_>> {
+ let [expected_arg_type] = &expected_input_tys[..] else { return None };
+
+ let ty::Tuple(expected_elems) = self.resolve_vars_if_possible(*expected_arg_type).kind()
+ else { return None };
+
+ let expected_types: Vec<_> = expected_elems.iter().map(|k| k.expect_ty()).collect();
+ let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect();
+
+ let all_match = iter::zip(expected_types, supplied_types)
+ .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok());
+
+ if all_match {
+ match provided_args {
+ [] => None,
+ [_] => unreachable!(
+ "shouldn't reach here - need count mismatch between 1-tuple and 1-argument"
+ ),
+ [first, .., last] => Some(FnArgsAsTuple { first, last }),
+ }
+ } else {
+ None
+ }
+ }
+
// AST fragment checking
pub(in super::super) fn check_lit(
&self,
@@ -511,7 +582,7 @@
_ => bug!("unexpected type: {:?}", ty),
},
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
- | Res::SelfTy(..) => match ty.kind() {
+ | Res::SelfTy { .. } => match ty.kind() {
ty::Adt(adt, substs) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did, substs))
}
@@ -846,7 +917,7 @@
}
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
- let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
+ let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
match node {
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
@@ -862,7 +933,7 @@
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
- let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
+ let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id));
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
}
@@ -975,7 +1046,7 @@
fn point_at_arg_instead_of_call_if_possible(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
- final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
+ final_arg_types: &[Option<(Ty<'tcx>, Ty<'tcx>)>],
expr: &'tcx hir::Expr<'tcx>,
call_sp: Span,
args: &'tcx [hir::Expr<'tcx>],
@@ -1016,7 +1087,7 @@
ObligationCauseCode::BuiltinDerivedObligation(code) |
ObligationCauseCode::ImplDerivedObligation(code) |
ObligationCauseCode::DerivedObligation(code) => {
- code.parent_trait_ref.self_ty().skip_binder().into()
+ code.parent_trait_pred.self_ty().skip_binder().into()
}
_ if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder() => {
@@ -1030,13 +1101,17 @@
// `FulfillmentError`.
let mut referenced_in = final_arg_types
.iter()
- .map(|&(i, checked_ty, _)| (i, checked_ty))
- .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+ .enumerate()
+ .filter_map(|(i, arg)| match arg {
+ Some((checked_ty, coerce_ty)) => Some([(i, *checked_ty), (i, *coerce_ty)]),
+ _ => None,
+ })
+ .flatten()
.flat_map(|(i, ty)| {
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(self.tcx).any(|arg| arg == self_) { Some(i) } else { None }
+ if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
})
.collect::<Vec<usize>>();
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 9c70d2c..222c14d 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -188,8 +188,7 @@
) -> ty::GenericPredicates<'tcx> {
let tcx = self.tcx;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item_id = tcx.hir().ty_param_owner(hir_id);
- let item_def_id = tcx.hir().local_def_id(item_id);
+ let item_def_id = tcx.hir().ty_param_owner(hir_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
ty::GenericPredicates {
@@ -240,7 +239,7 @@
ty: Ty<'tcx>,
param: Option<&ty::GenericParamDef>,
span: Span,
- ) -> &'tcx Const<'tcx> {
+ ) -> Const<'tcx> {
if let Some(param) = param {
if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
return ct;
@@ -283,7 +282,7 @@
if ty.has_escaping_bound_vars() {
ty // FIXME: normalization and escaping regions
} else {
- self.normalize_associated_types_in(span, &ty)
+ self.normalize_associated_types_in(span, ty)
}
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 6c7d3a0..f9c4827 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -8,8 +8,12 @@
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind};
-use rustc_infer::infer;
+use rustc_hir::{
+ Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind,
+ WherePredicate,
+};
+use rustc_infer::infer::{self, TyCtxtInferExt};
+
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Binder, Ty};
use rustc_span::symbol::{kw, sym};
@@ -208,7 +212,7 @@
pub fn suggest_deref_ref_or_into(
&self,
err: &mut DiagnosticBuilder<'_>,
- expr: &hir::Expr<'_>,
+ expr: &hir::Expr<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -231,13 +235,13 @@
}
} else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
let is_struct_pat_shorthand_field =
- self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
+ self.maybe_get_struct_pattern_shorthand_field(expr).is_some();
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
if !methods.is_empty() {
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
.filter_map(|(receiver, method)| {
- let method_call = format!(".{}()", method.ident);
+ let method_call = format!(".{}()", method.name);
if receiver.ends_with(&method_call) {
None // do not suggest code that is already there (#53348)
} else {
@@ -559,6 +563,7 @@
let ty = self.tcx.erase_late_bound_regions(ty);
if self.can_coerce(expected, ty) {
err.span_label(sp, format!("expected `{}` because of return type", expected));
+ self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
return true;
}
false
@@ -566,6 +571,115 @@
}
}
+ /// check whether the return type is a generic type with a trait bound
+ /// only suggest this if the generic param is not present in the arguments
+ /// if this is true, hint them towards changing the return type to `impl Trait`
+ /// ```
+ /// fn cant_name_it<T: Fn() -> u32>() -> T {
+ /// || 3
+ /// }
+ /// ```
+ fn try_suggest_return_impl_trait(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ fn_id: hir::HirId,
+ ) {
+ // Only apply the suggestion if:
+ // - the return type is a generic parameter
+ // - the generic param is not used as a fn param
+ // - the generic param has at least one bound
+ // - the generic param doesn't appear in any other bounds where it's not the Self type
+ // Suggest:
+ // - Changing the return type to be `impl <all bounds>`
+
+ debug!("try_suggest_return_impl_trait, expected = {:?}, found = {:?}", expected, found);
+
+ let ty::Param(expected_ty_as_param) = expected.kind() else { return };
+
+ let fn_node = self.tcx.hir().find(fn_id);
+
+ let Some(hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Fn(
+ hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. },
+ hir::Generics { params, where_clause, .. },
+ _body_id,
+ ),
+ ..
+ })) = fn_node else { return };
+
+ let Some(expected_generic_param) = params.get(expected_ty_as_param.index as usize) else { return };
+
+ // get all where BoundPredicates here, because they are used in to cases below
+ let where_predicates = where_clause
+ .predicates
+ .iter()
+ .filter_map(|p| match p {
+ WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ bounds,
+ bounded_ty,
+ ..
+ }) => {
+ // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
+ let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, bounded_ty);
+ Some((ty, bounds))
+ }
+ _ => None,
+ })
+ .map(|(ty, bounds)| match ty.kind() {
+ ty::Param(param_ty) if param_ty == expected_ty_as_param => Ok(Some(bounds)),
+ // check whether there is any predicate that contains our `T`, like `Option<T>: Send`
+ _ => match ty.contains(expected) {
+ true => Err(()),
+ false => Ok(None),
+ },
+ })
+ .collect::<Result<Vec<_>, _>>();
+
+ let Ok(where_predicates) = where_predicates else { return };
+
+ // now get all predicates in the same types as the where bounds, so we can chain them
+ let predicates_from_where =
+ where_predicates.iter().flatten().map(|bounds| bounds.iter()).flatten();
+
+ // extract all bounds from the source code using their spans
+ let all_matching_bounds_strs = expected_generic_param
+ .bounds
+ .iter()
+ .chain(predicates_from_where)
+ .filter_map(|bound| match bound {
+ GenericBound::Trait(_, _) => {
+ self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
+ }
+ _ => None,
+ })
+ .collect::<Vec<String>>();
+
+ if all_matching_bounds_strs.len() == 0 {
+ return;
+ }
+
+ let all_bounds_str = all_matching_bounds_strs.join(" + ");
+
+ let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
+ let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, param);
+ matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param)
+ });
+
+ if ty_param_used_in_fn_params {
+ return;
+ }
+
+ err.span_suggestion(
+ fn_return.span(),
+ "consider using an impl return type",
+ format!("impl {}", all_bounds_str),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
pub(in super::super) fn suggest_missing_break_or_return_expr(
&self,
err: &mut DiagnosticBuilder<'_>,
@@ -608,6 +722,21 @@
let bound_vars = self.tcx.late_bound_vars(fn_id);
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
let ty = self.normalize_associated_types_in(expr.span, ty);
+ let ty = match self.tcx.asyncness(fn_id.owner) {
+ hir::IsAsync::Async => self
+ .tcx
+ .infer_ctxt()
+ .enter(|infcx| {
+ infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+ span_bug!(
+ fn_decl.output.span(),
+ "failed to get output type of async function"
+ )
+ })
+ })
+ .skip_binder(),
+ hir::IsAsync::NotAsync => ty,
+ };
if self.can_coerce(found, ty) {
err.multipart_suggestion(
"you might have meant to return this value",
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs
index 839bd56..576dc6f 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_typeck/src/check/gather_locals.rs
@@ -1,6 +1,6 @@
use crate::check::{FnCtxt, LocalTy, UserType};
use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::Ty;
@@ -92,18 +92,12 @@
debug!(
"local variable {:?} is assigned type {}",
decl.pat,
- self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
+ self.fcx.ty_to_string(self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
);
}
}
impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
// Add explicitly-declared locals.
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
self.declare(local.into());
@@ -143,7 +137,7 @@
debug!(
"pattern binding {} is assigned to {} with type {:?}",
ident,
- self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
+ self.fcx.ty_to_string(self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
var_ty
);
}
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index d54b1d6..d360f34 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -3,6 +3,7 @@
//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
//! types computed here.
+use self::drop_ranges::DropRanges;
use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::pluralize;
@@ -10,7 +11,7 @@
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_middle::middle::region::{self, YieldData};
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -19,6 +20,8 @@
use smallvec::SmallVec;
use tracing::debug;
+mod drop_ranges;
+
struct InteriorVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
@@ -34,6 +37,7 @@
guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
guard_bindings_set: HirIdSet,
linted_values: HirIdSet,
+ drop_ranges: DropRanges,
}
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -48,9 +52,11 @@
) {
use rustc_span::DUMMY_SP;
+ let ty = self.fcx.resolve_vars_if_possible(ty);
+
debug!(
- "generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
- ty, scope, expr, source_span
+ "attempting to record type ty={:?}; hir_id={:?}; scope={:?}; expr={:?}; source_span={:?}; expr_count={:?}",
+ ty, hir_id, scope, expr, source_span, self.expr_count,
);
let live_across_yield = scope
@@ -63,21 +69,30 @@
//
// See the mega-comment at `yield_in_scope` for a proof.
- debug!(
- "comparing counts yield: {} self: {}, source_span = {:?}",
- yield_data.expr_and_pat_count, self.expr_count, source_span
- );
+ yield_data
+ .iter()
+ .find(|yield_data| {
+ debug!(
+ "comparing counts yield: {} self: {}, source_span = {:?}",
+ yield_data.expr_and_pat_count, self.expr_count, source_span
+ );
- // If it is a borrowing happening in the guard,
- // it needs to be recorded regardless because they
- // do live across this yield point.
- if guard_borrowing_from_pattern
- || yield_data.expr_and_pat_count >= self.expr_count
- {
- Some(yield_data)
- } else {
- None
- }
+ if self.fcx.sess().opts.debugging_opts.drop_tracking
+ && self
+ .drop_ranges
+ .is_dropped_at(hir_id, yield_data.expr_and_pat_count)
+ {
+ debug!("value is dropped at yield point; not recording");
+ return false;
+ }
+
+ // If it is a borrowing happening in the guard,
+ // it needs to be recorded regardless because they
+ // do live across this yield point.
+ guard_borrowing_from_pattern
+ || yield_data.expr_and_pat_count >= self.expr_count
+ })
+ .cloned()
})
})
.unwrap_or_else(|| {
@@ -85,7 +100,6 @@
});
if let Some(yield_data) = live_across_yield {
- let ty = self.fcx.resolve_vars_if_possible(ty);
debug!(
"type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
expr, scope, ty, self.expr_count, yield_data.span
@@ -141,7 +155,7 @@
self.types.insert(ty::GeneratorInteriorTypeCause {
span: source_span,
- ty: &ty,
+ ty,
scope_span,
yield_span: yield_data.span,
expr: expr.map(|e| e.hir_id),
@@ -154,7 +168,6 @@
self.expr_count,
expr.map(|e| e.span)
);
- let ty = self.fcx.resolve_vars_if_possible(ty);
if let Some((unresolved_type, unresolved_type_span)) =
self.fcx.unresolved_type_vars(&ty)
{
@@ -186,10 +199,11 @@
guard_bindings: <_>::default(),
guard_bindings_set: <_>::default(),
linted_values: <_>::default(),
+ drop_ranges: drop_ranges::compute_drop_ranges(fcx, def_id, body),
};
intravisit::walk_body(&mut visitor, body);
- // Check that we visited the same amount of expressions and the RegionResolutionVisitor
+ // Check that we visited the same amount of expressions as the RegionResolutionVisitor
let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
assert_eq!(region_expr_count, visitor.expr_count);
@@ -266,12 +280,6 @@
// librustc_middle/middle/region.rs since `expr_count` is compared against the results
// there.
impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
let Arm { guard, pat, body, .. } = arm;
self.visit_pat(pat);
@@ -319,6 +327,7 @@
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
let mut guard_borrowing_from_pattern = false;
+
match &expr.kind {
ExprKind::Call(callee, args) => match &callee.kind {
ExprKind::Path(qpath) => {
@@ -407,7 +416,7 @@
let tcx = self.fcx.tcx;
let ref_ty = tcx.mk_ref(
// Use `ReErased` as `resolve_interior` is going to replace all the regions anyway.
- tcx.mk_region(ty::RegionKind::ReErased),
+ tcx.mk_region(ty::ReErased),
ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
);
self.record(
@@ -439,12 +448,6 @@
}
impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
intravisit::walk_pat(self, pat);
if let PatKind::Binding(_, id, ..) = pat.kind {
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
new file mode 100644
index 0000000..972dd62
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -0,0 +1,279 @@
+//! Drop range analysis finds the portions of the tree where a value is guaranteed to be dropped
+//! (i.e. moved, uninitialized, etc.). This is used to exclude the types of those values from the
+//! generator type. See `InteriorVisitor::record` for where the results of this analysis are used.
+//!
+//! There are three phases to this analysis:
+//! 1. Use `ExprUseVisitor` to identify the interesting values that are consumed and borrowed.
+//! 2. Use `DropRangeVisitor` to find where the interesting values are dropped or reinitialized,
+//! and also build a control flow graph.
+//! 3. Use `DropRanges::propagate_to_fixpoint` to flow the dropped/reinitialized information through
+//! the CFG and find the exact points where we know a value is definitely dropped.
+//!
+//! The end result is a data structure that maps the post-order index of each node in the HIR tree
+//! to a set of values that are known to be dropped at that location.
+
+use self::cfg_build::build_control_flow_graph;
+use self::record_consumed_borrow::find_consumed_and_borrowed;
+use crate::check::FnCtxt;
+use hir::def_id::DefId;
+use hir::{Body, HirId, HirIdMap, Node};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::hir::map::Map;
+use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
+use rustc_middle::ty;
+use std::collections::BTreeMap;
+use std::fmt::Debug;
+
+mod cfg_build;
+mod cfg_propagate;
+mod cfg_visualize;
+mod record_consumed_borrow;
+
+pub fn compute_drop_ranges<'a, 'tcx>(
+ fcx: &'a FnCtxt<'a, 'tcx>,
+ def_id: DefId,
+ body: &'tcx Body<'tcx>,
+) -> DropRanges {
+ if fcx.sess().opts.debugging_opts.drop_tracking {
+ let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
+
+ let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
+ let mut drop_ranges = build_control_flow_graph(
+ fcx.tcx.hir(),
+ fcx.tcx,
+ &fcx.typeck_results.borrow(),
+ consumed_borrowed_places,
+ body,
+ num_exprs,
+ );
+
+ drop_ranges.propagate_to_fixpoint();
+
+ DropRanges { tracked_value_map: drop_ranges.tracked_value_map, nodes: drop_ranges.nodes }
+ } else {
+ // If drop range tracking is not enabled, skip all the analysis and produce an
+ // empty set of DropRanges.
+ DropRanges { tracked_value_map: FxHashMap::default(), nodes: IndexVec::new() }
+ }
+}
+
+/// Applies `f` to consumable node in the HIR subtree pointed to by `place`.
+///
+/// This includes the place itself, and if the place is a reference to a local
+/// variable then `f` is also called on the HIR node for that variable as well.
+///
+/// For example, if `place` points to `foo()`, then `f` is called once for the
+/// result of `foo`. On the other hand, if `place` points to `x` then `f` will
+/// be called both on the `ExprKind::Path` node that represents the expression
+/// as well as the HirId of the local `x` itself.
+fn for_each_consumable<'tcx>(hir: Map<'tcx>, place: TrackedValue, mut f: impl FnMut(TrackedValue)) {
+ f(place);
+ let node = hir.find(place.hir_id());
+ if let Some(Node::Expr(expr)) = node {
+ match expr.kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ _,
+ hir::Path { res: hir::def::Res::Local(hir_id), .. },
+ )) => {
+ f(TrackedValue::Variable(*hir_id));
+ }
+ _ => (),
+ }
+ }
+}
+
+rustc_index::newtype_index! {
+ pub struct PostOrderId {
+ DEBUG_FORMAT = "id({})",
+ }
+}
+
+rustc_index::newtype_index! {
+ pub struct TrackedValueIndex {
+ DEBUG_FORMAT = "hidx({})",
+ }
+}
+
+/// Identifies a value whose drop state we need to track.
+#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
+enum TrackedValue {
+ /// Represents a named variable, such as a let binding, parameter, or upvar.
+ ///
+ /// The HirId points to the variable's definition site.
+ Variable(HirId),
+ /// A value produced as a result of an expression.
+ ///
+ /// The HirId points to the expression that returns this value.
+ Temporary(HirId),
+}
+
+impl TrackedValue {
+ fn hir_id(&self) -> HirId {
+ match self {
+ TrackedValue::Variable(hir_id) | TrackedValue::Temporary(hir_id) => *hir_id,
+ }
+ }
+
+ fn from_place_with_projections_allowed(place_with_id: &PlaceWithHirId<'_>) -> Self {
+ match place_with_id.place.base {
+ PlaceBase::Rvalue | PlaceBase::StaticItem => {
+ TrackedValue::Temporary(place_with_id.hir_id)
+ }
+ PlaceBase::Local(hir_id)
+ | PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => {
+ TrackedValue::Variable(hir_id)
+ }
+ }
+ }
+}
+
+/// Represents a reason why we might not be able to convert a HirId or Place
+/// into a tracked value.
+#[derive(Debug)]
+enum TrackedValueConversionError {
+ /// Place projects are not currently supported.
+ ///
+ /// The reasoning around these is kind of subtle, so we choose to be more
+ /// conservative around these for now. There is not reason in theory we
+ /// cannot support these, we just have not implemented it yet.
+ PlaceProjectionsNotSupported,
+}
+
+impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue {
+ type Error = TrackedValueConversionError;
+
+ fn try_from(place_with_id: &PlaceWithHirId<'_>) -> Result<Self, Self::Error> {
+ if !place_with_id.place.projections.is_empty() {
+ debug!(
+ "TrackedValue from PlaceWithHirId: {:?} has projections, which are not supported.",
+ place_with_id
+ );
+ return Err(TrackedValueConversionError::PlaceProjectionsNotSupported);
+ }
+
+ Ok(TrackedValue::from_place_with_projections_allowed(place_with_id))
+ }
+}
+
+pub struct DropRanges {
+ tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+ nodes: IndexVec<PostOrderId, NodeInfo>,
+}
+
+impl DropRanges {
+ pub fn is_dropped_at(&self, hir_id: HirId, location: usize) -> bool {
+ self.tracked_value_map
+ .get(&TrackedValue::Temporary(hir_id))
+ .or(self.tracked_value_map.get(&TrackedValue::Variable(hir_id)))
+ .cloned()
+ .map_or(false, |tracked_value_id| {
+ self.expect_node(location.into()).drop_state.contains(tracked_value_id)
+ })
+ }
+
+ /// Returns a reference to the NodeInfo for a node, panicking if it does not exist
+ fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
+ &self.nodes[id]
+ }
+}
+
+/// Tracks information needed to compute drop ranges.
+struct DropRangesBuilder {
+ /// The core of DropRangesBuilder is a set of nodes, which each represent
+ /// one expression. We primarily refer to them by their index in a
+ /// post-order traversal of the HIR tree, since this is what
+ /// generator_interior uses to talk about yield positions.
+ ///
+ /// This IndexVec keeps the relevant details for each node. See the
+ /// NodeInfo struct for more details, but this information includes things
+ /// such as the set of control-flow successors, which variables are dropped
+ /// or reinitialized, and whether each variable has been inferred to be
+ /// known-dropped or potentially reintiialized at each point.
+ nodes: IndexVec<PostOrderId, NodeInfo>,
+ /// We refer to values whose drop state we are tracking by the HirId of
+ /// where they are defined. Within a NodeInfo, however, we store the
+ /// drop-state in a bit vector indexed by a HirIdIndex
+ /// (see NodeInfo::drop_state). The hir_id_map field stores the mapping
+ /// from HirIds to the HirIdIndex that is used to represent that value in
+ /// bitvector.
+ tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+
+ /// When building the control flow graph, we don't always know the
+ /// post-order index of the target node at the point we encounter it.
+ /// For example, this happens with break and continue. In those cases,
+ /// we store a pair of the PostOrderId of the source and the HirId
+ /// of the target. Once we have gathered all of these edges, we make a
+ /// pass over the set of deferred edges (see process_deferred_edges in
+ /// cfg_build.rs), look up the PostOrderId for the target (since now the
+ /// post-order index for all nodes is known), and add missing control flow
+ /// edges.
+ deferred_edges: Vec<(PostOrderId, HirId)>,
+ /// This maps HirIds of expressions to their post-order index. It is
+ /// used in process_deferred_edges to correctly add back-edges.
+ post_order_map: HirIdMap<PostOrderId>,
+}
+
+impl Debug for DropRangesBuilder {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("DropRanges")
+ .field("hir_id_map", &self.tracked_value_map)
+ .field("post_order_maps", &self.post_order_map)
+ .field("nodes", &self.nodes.iter_enumerated().collect::<BTreeMap<_, _>>())
+ .finish()
+ }
+}
+
+/// DropRanges keeps track of what values are definitely dropped at each point in the code.
+///
+/// Values of interest are defined by the hir_id of their place. Locations in code are identified
+/// by their index in the post-order traversal. At its core, DropRanges maps
+/// (hir_id, post_order_id) -> bool, where a true value indicates that the value is definitely
+/// dropped at the point of the node identified by post_order_id.
+impl DropRangesBuilder {
+ /// Returns the number of values (hir_ids) that are tracked
+ fn num_values(&self) -> usize {
+ self.tracked_value_map.len()
+ }
+
+ fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
+ let size = self.num_values();
+ self.nodes.ensure_contains_elem(id, || NodeInfo::new(size));
+ &mut self.nodes[id]
+ }
+
+ fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
+ trace!("adding control edge from {:?} to {:?}", from, to);
+ self.node_mut(from).successors.push(to);
+ }
+}
+
+#[derive(Debug)]
+struct NodeInfo {
+ /// IDs of nodes that can follow this one in the control flow
+ ///
+ /// If the vec is empty, then control proceeds to the next node.
+ successors: Vec<PostOrderId>,
+
+ /// List of hir_ids that are dropped by this node.
+ drops: Vec<TrackedValueIndex>,
+
+ /// List of hir_ids that are reinitialized by this node.
+ reinits: Vec<TrackedValueIndex>,
+
+ /// Set of values that are definitely dropped at this point.
+ drop_state: BitSet<TrackedValueIndex>,
+}
+
+impl NodeInfo {
+ fn new(num_values: usize) -> Self {
+ Self {
+ successors: vec![],
+ drops: vec![],
+ reinits: vec![],
+ drop_state: BitSet::new_filled(num_values),
+ }
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
new file mode 100644
index 0000000..cfed784
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -0,0 +1,558 @@
+use super::{
+ for_each_consumable, record_consumed_borrow::ConsumedAndBorrowedPlaces, DropRangesBuilder,
+ NodeInfo, PostOrderId, TrackedValue, TrackedValueIndex,
+};
+use hir::{
+ intravisit::{self, Visitor},
+ Body, Expr, ExprKind, Guard, HirId, LoopIdError,
+};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_index::vec::IndexVec;
+use rustc_middle::{
+ hir::map::Map,
+ ty::{TyCtxt, TypeckResults},
+};
+use std::mem::swap;
+
+/// Traverses the body to find the control flow graph and locations for the
+/// relevant places are dropped or reinitialized.
+///
+/// The resulting structure still needs to be iterated to a fixed point, which
+/// can be done with propagate_to_fixpoint in cfg_propagate.
+pub(super) fn build_control_flow_graph<'tcx>(
+ hir: Map<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &TypeckResults<'tcx>,
+ consumed_borrowed_places: ConsumedAndBorrowedPlaces,
+ body: &'tcx Body<'tcx>,
+ num_exprs: usize,
+) -> DropRangesBuilder {
+ let mut drop_range_visitor =
+ DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
+ intravisit::walk_body(&mut drop_range_visitor, body);
+
+ drop_range_visitor.drop_ranges.process_deferred_edges();
+
+ drop_range_visitor.drop_ranges
+}
+
+/// This struct is used to gather the information for `DropRanges` to determine the regions of the
+/// HIR tree for which a value is dropped.
+///
+/// We are interested in points where a variables is dropped or initialized, and the control flow
+/// of the code. We identify locations in code by their post-order traversal index, so it is
+/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
+///
+/// We make several simplifying assumptions, with the goal of being more conservative than
+/// necessary rather than less conservative (since being less conservative is unsound, but more
+/// conservative is still safe). These assumptions are:
+///
+/// 1. Moving a variable `a` counts as a move of the whole variable.
+/// 2. Moving a partial path like `a.b.c` is ignored.
+/// 3. Reinitializing through a field (e.g. `a.b.c = 5`) counds as a reinitialization of all of
+/// `a`.
+///
+/// Some examples:
+///
+/// Rule 1:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a);
+/// // `a` is not considered initialized.
+/// ```
+///
+/// Rule 2:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a.0);
+/// drop(a.1);
+/// // `a` is still considered initialized.
+/// ```
+///
+/// Rule 3:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a);
+/// a.1 = vec![1];
+/// // all of `a` is considered initialized
+/// ```
+
+struct DropRangeVisitor<'a, 'tcx> {
+ hir: Map<'tcx>,
+ places: ConsumedAndBorrowedPlaces,
+ drop_ranges: DropRangesBuilder,
+ expr_index: PostOrderId,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'a TypeckResults<'tcx>,
+ label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
+}
+
+impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
+ fn new(
+ hir: Map<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'a TypeckResults<'tcx>,
+ places: ConsumedAndBorrowedPlaces,
+ num_exprs: usize,
+ ) -> Self {
+ debug!("consumed_places: {:?}", places.consumed);
+ let drop_ranges = DropRangesBuilder::new(
+ places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
+ hir,
+ num_exprs,
+ );
+ Self {
+ hir,
+ places,
+ drop_ranges,
+ expr_index: PostOrderId::from_u32(0),
+ typeck_results,
+ tcx,
+ label_stack: vec![],
+ }
+ }
+
+ fn record_drop(&mut self, value: TrackedValue) {
+ if self.places.borrowed.contains(&value) {
+ debug!("not marking {:?} as dropped because it is borrowed at some point", value);
+ } else {
+ debug!("marking {:?} as dropped at {:?}", value, self.expr_index);
+ let count = self.expr_index;
+ self.drop_ranges.drop_at(value, count);
+ }
+ }
+
+ /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
+ /// expressions. This method consumes a little deeper into the expression when needed.
+ fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
+ debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index);
+ let places = self
+ .places
+ .consumed
+ .get(&expr.hir_id)
+ .map_or(vec![], |places| places.iter().cloned().collect());
+ for place in places {
+ for_each_consumable(self.hir, place, |value| self.record_drop(value));
+ }
+ }
+
+ /// Marks an expression as being reinitialized.
+ ///
+ /// Note that we always approximated on the side of things being more
+ /// initialized than they actually are, as opposed to less. In cases such
+ /// as `x.y = ...`, we would consider all of `x` as being initialized
+ /// instead of just the `y` field.
+ ///
+ /// This is because it is always safe to consider something initialized
+ /// even when it is not, but the other way around will cause problems.
+ ///
+ /// In the future, we will hopefully tighten up these rules to be more
+ /// precise.
+ fn reinit_expr(&mut self, expr: &hir::Expr<'_>) {
+ // Walk the expression to find the base. For example, in an expression
+ // like `*a[i].x`, we want to find the `a` and mark that as
+ // reinitialized.
+ match expr.kind {
+ ExprKind::Path(hir::QPath::Resolved(
+ _,
+ hir::Path { res: hir::def::Res::Local(hir_id), .. },
+ )) => {
+ // This is the base case, where we have found an actual named variable.
+
+ let location = self.expr_index;
+ debug!("reinitializing {:?} at {:?}", hir_id, location);
+ self.drop_ranges.reinit_at(TrackedValue::Variable(*hir_id), location);
+ }
+
+ ExprKind::Field(base, _) => self.reinit_expr(base),
+
+ // Most expressions do not refer to something where we need to track
+ // reinitializations.
+ //
+ // Some of these may be interesting in the future
+ ExprKind::Path(..)
+ | ExprKind::Box(..)
+ | ExprKind::ConstBlock(..)
+ | ExprKind::Array(..)
+ | ExprKind::Call(..)
+ | ExprKind::MethodCall(..)
+ | ExprKind::Tup(..)
+ | ExprKind::Binary(..)
+ | ExprKind::Unary(..)
+ | ExprKind::Lit(..)
+ | ExprKind::Cast(..)
+ | ExprKind::Type(..)
+ | ExprKind::DropTemps(..)
+ | ExprKind::Let(..)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ | ExprKind::Closure(..)
+ | ExprKind::Block(..)
+ | ExprKind::Assign(..)
+ | ExprKind::AssignOp(..)
+ | ExprKind::Index(..)
+ | ExprKind::AddrOf(..)
+ | ExprKind::Break(..)
+ | ExprKind::Continue(..)
+ | ExprKind::Ret(..)
+ | ExprKind::InlineAsm(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Yield(..)
+ | ExprKind::Err => (),
+ }
+ }
+
+ /// For an expression with an uninhabited return type (e.g. a function that returns !),
+ /// this adds a self edge to to the CFG to model the fact that the function does not
+ /// return.
+ fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
+ let ty = self.typeck_results.expr_ty(expr);
+ let ty = self.tcx.erase_regions(ty);
+ let m = self.tcx.parent_module(expr.hir_id).to_def_id();
+ let param_env = self.tcx.param_env(m.expect_local());
+ if self.tcx.is_ty_uninhabited_from(m, ty, param_env) {
+ // This function will not return. We model this fact as an infinite loop.
+ self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
+ }
+ }
+
+ /// Map a Destination to an equivalent expression node
+ ///
+ /// The destination field of a Break or Continue expression can target either an
+ /// expression or a block. The drop range analysis, however, only deals in
+ /// expression nodes, so blocks that might be the destination of a Break or Continue
+ /// will not have a PostOrderId.
+ ///
+ /// If the destination is an expression, this function will simply return that expression's
+ /// hir_id. If the destination is a block, this function will return the hir_id of last
+ /// expression in the block.
+ fn find_target_expression_from_destination(
+ &self,
+ destination: hir::Destination,
+ ) -> Result<HirId, LoopIdError> {
+ destination.target_id.map(|target| {
+ let node = self.hir.get(target);
+ match node {
+ hir::Node::Expr(_) => target,
+ hir::Node::Block(b) => find_last_block_expression(b),
+ hir::Node::Param(..)
+ | hir::Node::Item(..)
+ | hir::Node::ForeignItem(..)
+ | hir::Node::TraitItem(..)
+ | hir::Node::ImplItem(..)
+ | hir::Node::Variant(..)
+ | hir::Node::Field(..)
+ | hir::Node::AnonConst(..)
+ | hir::Node::Stmt(..)
+ | hir::Node::PathSegment(..)
+ | hir::Node::Ty(..)
+ | hir::Node::TraitRef(..)
+ | hir::Node::Binding(..)
+ | hir::Node::Pat(..)
+ | hir::Node::Arm(..)
+ | hir::Node::Local(..)
+ | hir::Node::Ctor(..)
+ | hir::Node::Lifetime(..)
+ | hir::Node::GenericParam(..)
+ | hir::Node::Visibility(..)
+ | hir::Node::Crate(..)
+ | hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node),
+ }
+ })
+ }
+}
+
+fn find_last_block_expression(block: &hir::Block<'_>) -> HirId {
+ block.expr.map_or_else(
+ // If there is no tail expression, there will be at least one statement in the
+ // block because the block contains a break or continue statement.
+ || block.stmts.last().unwrap().hir_id,
+ |expr| expr.hir_id,
+ )
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
+ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ let mut reinit = None;
+ match expr.kind {
+ ExprKind::Assign(lhs, rhs, _) => {
+ self.visit_expr(lhs);
+ self.visit_expr(rhs);
+
+ reinit = Some(lhs);
+ }
+
+ ExprKind::If(test, if_true, if_false) => {
+ self.visit_expr(test);
+
+ let fork = self.expr_index;
+
+ self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
+ self.visit_expr(if_true);
+ let true_end = self.expr_index;
+
+ self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
+ if let Some(if_false) = if_false {
+ self.visit_expr(if_false);
+ }
+
+ self.drop_ranges.add_control_edge(true_end, self.expr_index + 1);
+ }
+ ExprKind::Match(scrutinee, arms, ..) => {
+ // We walk through the match expression almost like a chain of if expressions.
+ // Here's a diagram to follow along with:
+ //
+ // ┌─┐
+ // match │A│ {
+ // ┌───┴─┘
+ // │
+ // ┌▼┌───►┌─┐ ┌─┐
+ // │B│ if │C│ =>│D│,
+ // └─┘ ├─┴──►└─┴──────┐
+ // ┌──┘ │
+ // ┌──┘ │
+ // │ │
+ // ┌▼┌───►┌─┐ ┌─┐ │
+ // │E│ if │F│ =>│G│, │
+ // └─┘ ├─┴──►└─┴┐ │
+ // │ │ │
+ // } ▼ ▼ │
+ // ┌─┐◄───────────────────┘
+ // │H│
+ // └─┘
+ //
+ // The order we want is that the scrutinee (A) flows into the first pattern (B),
+ // which flows into the guard (C). Then the guard either flows into the arm body
+ // (D) or into the start of the next arm (E). Finally, the body flows to the end
+ // of the match block (H).
+ //
+ // The subsequent arms follow the same ordering. First we go to the pattern, then
+ // the guard (if present, otherwise it flows straight into the body), then into
+ // the body and then to the end of the match expression.
+ //
+ // The comments below show which edge is being added.
+ self.visit_expr(scrutinee);
+
+ let (guard_exit, arm_end_ids) = arms.iter().fold(
+ (self.expr_index, vec![]),
+ |(incoming_edge, mut arm_end_ids), hir::Arm { pat, body, guard, .. }| {
+ // A -> B, or C -> E
+ self.drop_ranges.add_control_edge(incoming_edge, self.expr_index + 1);
+ self.visit_pat(pat);
+ // B -> C and E -> F are added implicitly due to the traversal order.
+ match guard {
+ Some(Guard::If(expr)) => self.visit_expr(expr),
+ Some(Guard::IfLet(pat, expr)) => {
+ self.visit_pat(pat);
+ self.visit_expr(expr);
+ }
+ None => (),
+ }
+ // Likewise, C -> D and F -> G are added implicitly.
+
+ // Save C, F, so we can add the other outgoing edge.
+ let to_next_arm = self.expr_index;
+
+ // The default edge does not get added since we also have an explicit edge,
+ // so we also need to add an edge to the next node as well.
+ //
+ // This adds C -> D, F -> G
+ self.drop_ranges.add_control_edge(self.expr_index, self.expr_index + 1);
+ self.visit_expr(body);
+
+ // Save the end of the body so we can add the exit edge once we know where
+ // the exit is.
+ arm_end_ids.push(self.expr_index);
+
+ // Pass C to the next iteration, as well as vec![D]
+ //
+ // On the last round through, we pass F and vec![D, G] so that we can
+ // add all the exit edges.
+ (to_next_arm, arm_end_ids)
+ },
+ );
+ // F -> H
+ self.drop_ranges.add_control_edge(guard_exit, self.expr_index + 1);
+
+ arm_end_ids.into_iter().for_each(|arm_end| {
+ // D -> H, G -> H
+ self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1)
+ });
+ }
+
+ ExprKind::Loop(body, label, ..) => {
+ let loop_begin = self.expr_index + 1;
+ self.label_stack.push((label, loop_begin));
+ if body.stmts.is_empty() && body.expr.is_none() {
+ // For empty loops we won't have updated self.expr_index after visiting the
+ // body, meaning we'd get an edge from expr_index to expr_index + 1, but
+ // instead we want an edge from expr_index + 1 to expr_index + 1.
+ self.drop_ranges.add_control_edge(loop_begin, loop_begin);
+ } else {
+ self.visit_block(body);
+ self.drop_ranges.add_control_edge(self.expr_index, loop_begin);
+ }
+ self.label_stack.pop();
+ }
+ // Find the loop entry by searching through the label stack for either the last entry
+ // (if label is none), or the first entry where the label matches this one. The Loop
+ // case maintains this stack mapping labels to the PostOrderId for the loop entry.
+ ExprKind::Continue(hir::Destination { label, .. }, ..) => self
+ .label_stack
+ .iter()
+ .rev()
+ .find(|(loop_label, _)| label.is_none() || *loop_label == label)
+ .map_or((), |(_, target)| {
+ self.drop_ranges.add_control_edge(self.expr_index, *target)
+ }),
+
+ ExprKind::Break(destination, ..) => {
+ // destination either points to an expression or to a block. We use
+ // find_target_expression_from_destination to use the last expression of the block
+ // if destination points to a block.
+ //
+ // We add an edge to the hir_id of the expression/block we are breaking out of, and
+ // then in process_deferred_edges we will map this hir_id to its PostOrderId, which
+ // will refer to the end of the block due to the post order traversal.
+ self.find_target_expression_from_destination(destination).map_or((), |target| {
+ self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
+ })
+ }
+
+ ExprKind::Call(f, args) => {
+ self.visit_expr(f);
+ for arg in args {
+ self.visit_expr(arg);
+ }
+
+ self.handle_uninhabited_return(expr);
+ }
+ ExprKind::MethodCall(_, exprs, _) => {
+ for expr in exprs {
+ self.visit_expr(expr);
+ }
+
+ self.handle_uninhabited_return(expr);
+ }
+
+ ExprKind::AddrOf(..)
+ | ExprKind::Array(..)
+ | ExprKind::AssignOp(..)
+ | ExprKind::Binary(..)
+ | ExprKind::Block(..)
+ | ExprKind::Box(..)
+ | ExprKind::Cast(..)
+ | ExprKind::Closure(..)
+ | ExprKind::ConstBlock(..)
+ | ExprKind::DropTemps(..)
+ | ExprKind::Err
+ | ExprKind::Field(..)
+ | ExprKind::Index(..)
+ | ExprKind::InlineAsm(..)
+ | ExprKind::Let(..)
+ | ExprKind::Lit(..)
+ | ExprKind::Path(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Ret(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Tup(..)
+ | ExprKind::Type(..)
+ | ExprKind::Unary(..)
+ | ExprKind::Yield(..) => intravisit::walk_expr(self, expr),
+ }
+
+ self.expr_index = self.expr_index + 1;
+ self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_index);
+ self.consume_expr(expr);
+ if let Some(expr) = reinit {
+ self.reinit_expr(expr);
+ }
+ }
+
+ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
+ intravisit::walk_pat(self, pat);
+
+ // Increment expr_count here to match what InteriorVisitor expects.
+ self.expr_index = self.expr_index + 1;
+ }
+}
+
+impl DropRangesBuilder {
+ fn new(
+ tracked_values: impl Iterator<Item = TrackedValue>,
+ hir: Map<'_>,
+ num_exprs: usize,
+ ) -> Self {
+ let mut tracked_value_map = FxHashMap::<_, TrackedValueIndex>::default();
+ let mut next = <_>::from(0u32);
+ for value in tracked_values {
+ for_each_consumable(hir, value, |value| {
+ if !tracked_value_map.contains_key(&value) {
+ tracked_value_map.insert(value, next);
+ next = next + 1;
+ }
+ });
+ }
+ debug!("hir_id_map: {:?}", tracked_value_map);
+ let num_values = tracked_value_map.len();
+ Self {
+ tracked_value_map,
+ nodes: IndexVec::from_fn_n(|_| NodeInfo::new(num_values), num_exprs + 1),
+ deferred_edges: <_>::default(),
+ post_order_map: <_>::default(),
+ }
+ }
+
+ fn tracked_value_index(&self, tracked_value: TrackedValue) -> TrackedValueIndex {
+ *self.tracked_value_map.get(&tracked_value).unwrap()
+ }
+
+ /// Adds an entry in the mapping from HirIds to PostOrderIds
+ ///
+ /// Needed so that `add_control_edge_hir_id` can work.
+ fn add_node_mapping(&mut self, node_hir_id: HirId, post_order_id: PostOrderId) {
+ self.post_order_map.insert(node_hir_id, post_order_id);
+ }
+
+ /// Like add_control_edge, but uses a hir_id as the target.
+ ///
+ /// This can be used for branches where we do not know the PostOrderId of the target yet,
+ /// such as when handling `break` or `continue`.
+ fn add_control_edge_hir_id(&mut self, from: PostOrderId, to: HirId) {
+ self.deferred_edges.push((from, to));
+ }
+
+ fn drop_at(&mut self, value: TrackedValue, location: PostOrderId) {
+ let value = self.tracked_value_index(value);
+ self.node_mut(location).drops.push(value);
+ }
+
+ fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) {
+ let value = match self.tracked_value_map.get(&value) {
+ Some(value) => *value,
+ // If there's no value, this is never consumed and therefore is never dropped. We can
+ // ignore this.
+ None => return,
+ };
+ self.node_mut(location).reinits.push(value);
+ }
+
+ /// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
+ ///
+ /// Should be called after visiting the HIR but before solving the control flow, otherwise some
+ /// edges will be missed.
+ fn process_deferred_edges(&mut self) {
+ trace!("processing deferred edges. post_order_map={:#?}", self.post_order_map);
+ let mut edges = vec![];
+ swap(&mut edges, &mut self.deferred_edges);
+ edges.into_iter().for_each(|(from, to)| {
+ trace!("Adding deferred edge from {:?} to {:?}", from, to);
+ let to = *self.post_order_map.get(&to).expect("Expression ID not found");
+ trace!("target edge PostOrderId={:?}", to);
+ self.add_control_edge(from, to)
+ });
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
new file mode 100644
index 0000000..139d17d
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
@@ -0,0 +1,92 @@
+use super::{DropRangesBuilder, PostOrderId};
+use rustc_index::{bit_set::BitSet, vec::IndexVec};
+use std::collections::BTreeMap;
+
+impl DropRangesBuilder {
+ pub fn propagate_to_fixpoint(&mut self) {
+ trace!("before fixpoint: {:#?}", self);
+ let preds = self.compute_predecessors();
+
+ trace!("predecessors: {:#?}", preds.iter_enumerated().collect::<BTreeMap<_, _>>());
+
+ let mut new_state = BitSet::new_empty(self.num_values());
+ let mut changed_nodes = BitSet::new_empty(self.nodes.len());
+ let mut unchanged_mask = BitSet::new_filled(self.nodes.len());
+ changed_nodes.insert(0u32.into());
+
+ let mut propagate = || {
+ let mut changed = false;
+ unchanged_mask.insert_all();
+ for id in self.nodes.indices() {
+ trace!("processing {:?}, changed_nodes: {:?}", id, changed_nodes);
+ // Check if any predecessor has changed, and if not then short-circuit.
+ //
+ // We handle the start node specially, since it doesn't have any predecessors,
+ // but we need to start somewhere.
+ if match id.index() {
+ 0 => !changed_nodes.contains(id),
+ _ => !preds[id].iter().any(|pred| changed_nodes.contains(*pred)),
+ } {
+ trace!("short-circuiting because none of {:?} have changed", preds[id]);
+ unchanged_mask.remove(id);
+ continue;
+ }
+
+ if id.index() == 0 {
+ new_state.clear();
+ } else {
+ // If we are not the start node and we have no predecessors, treat
+ // everything as dropped because there's no way to get here anyway.
+ new_state.insert_all();
+ };
+
+ for pred in &preds[id] {
+ new_state.intersect(&self.nodes[*pred].drop_state);
+ }
+
+ for drop in &self.nodes[id].drops {
+ new_state.insert(*drop);
+ }
+
+ for reinit in &self.nodes[id].reinits {
+ new_state.remove(*reinit);
+ }
+
+ if self.nodes[id].drop_state.intersect(&new_state) {
+ changed_nodes.insert(id);
+ changed = true;
+ } else {
+ unchanged_mask.remove(id);
+ }
+ }
+
+ changed_nodes.intersect(&unchanged_mask);
+ changed
+ };
+
+ while propagate() {
+ trace!("drop_state changed, re-running propagation");
+ }
+
+ trace!("after fixpoint: {:#?}", self);
+ }
+
+ fn compute_predecessors(&self) -> IndexVec<PostOrderId, Vec<PostOrderId>> {
+ let mut preds = IndexVec::from_fn_n(|_| vec![], self.nodes.len());
+ for (id, node) in self.nodes.iter_enumerated() {
+ // If the node has no explicit successors, we assume that control
+ // will from this node into the next one.
+ //
+ // If there are successors listed, then we assume that all
+ // possible successors are given and we do not include the default.
+ if node.successors.len() == 0 && id.index() != self.nodes.len() - 1 {
+ preds[id + 1].push(id);
+ } else {
+ for succ in &node.successors {
+ preds[*succ].push(id);
+ }
+ }
+ }
+ preds
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
new file mode 100644
index 0000000..20aad7a
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
@@ -0,0 +1,77 @@
+//! Implementation of GraphWalk for DropRanges so we can visualize the control
+//! flow graph when needed for debugging.
+
+use rustc_graphviz as dot;
+
+use super::{DropRangesBuilder, PostOrderId};
+
+/// Writes the CFG for DropRangesBuilder to a .dot file for visualization.
+///
+/// It is not normally called, but is kept around to easily add debugging
+/// code when needed.
+#[allow(dead_code)]
+pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
+ dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
+}
+
+impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
+ type Node = PostOrderId;
+
+ type Edge = (PostOrderId, PostOrderId);
+
+ fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
+ self.nodes.iter_enumerated().map(|(i, _)| i).collect()
+ }
+
+ fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
+ self.nodes
+ .iter_enumerated()
+ .flat_map(|(i, node)| {
+ if node.successors.len() == 0 {
+ vec![(i, i + 1)]
+ } else {
+ node.successors.iter().map(move |&s| (i, s)).collect()
+ }
+ })
+ .collect()
+ }
+
+ fn source(&'a self, edge: &Self::Edge) -> Self::Node {
+ edge.0
+ }
+
+ fn target(&'a self, edge: &Self::Edge) -> Self::Node {
+ edge.1
+ }
+}
+
+impl<'a> dot::Labeller<'a> for DropRangesBuilder {
+ type Node = PostOrderId;
+
+ type Edge = (PostOrderId, PostOrderId);
+
+ fn graph_id(&'a self) -> dot::Id<'a> {
+ dot::Id::new("drop_ranges").unwrap()
+ }
+
+ fn node_id(&'a self, n: &Self::Node) -> dot::Id<'a> {
+ dot::Id::new(format!("id{}", n.index())).unwrap()
+ }
+
+ fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
+ dot::LabelText::LabelStr(
+ format!(
+ "{:?}, local_id: {}",
+ n,
+ self.post_order_map
+ .iter()
+ .find(|(_hir_id, &post_order_id)| post_order_id == *n)
+ .map_or("<unknown>".into(), |(hir_id, _)| format!(
+ "{}",
+ hir_id.local_id.index()
+ ))
+ )
+ .into(),
+ )
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
new file mode 100644
index 0000000..9a30858
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -0,0 +1,118 @@
+use super::TrackedValue;
+use crate::{
+ check::FnCtxt,
+ expr_use_visitor::{self, ExprUseVisitor},
+};
+use hir::{def_id::DefId, Body, HirId, HirIdMap};
+use rustc_data_structures::stable_set::FxHashSet;
+use rustc_hir as hir;
+use rustc_middle::hir::map::Map;
+
+pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
+ fcx: &'a FnCtxt<'a, 'tcx>,
+ def_id: DefId,
+ body: &'tcx Body<'tcx>,
+) -> ConsumedAndBorrowedPlaces {
+ let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx.hir());
+ expr_use_visitor.consume_body(fcx, def_id, body);
+ expr_use_visitor.places
+}
+
+pub(super) struct ConsumedAndBorrowedPlaces {
+ /// Records the variables/expressions that are dropped by a given expression.
+ ///
+ /// The key is the hir-id of the expression, and the value is a set or hir-ids for variables
+ /// or values that are consumed by that expression.
+ ///
+ /// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is
+ /// not considered a drop of `x`, although it would be a drop of `x.y`.
+ pub(super) consumed: HirIdMap<FxHashSet<TrackedValue>>,
+ /// A set of hir-ids of values or variables that are borrowed at some point within the body.
+ pub(super) borrowed: FxHashSet<TrackedValue>,
+}
+
+/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
+///
+/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
+/// record the parent expression, which is the point where the drop actually takes place.
+struct ExprUseDelegate<'tcx> {
+ hir: Map<'tcx>,
+ places: ConsumedAndBorrowedPlaces,
+}
+
+impl<'tcx> ExprUseDelegate<'tcx> {
+ fn new(hir: Map<'tcx>) -> Self {
+ Self {
+ hir,
+ places: ConsumedAndBorrowedPlaces {
+ consumed: <_>::default(),
+ borrowed: <_>::default(),
+ },
+ }
+ }
+
+ fn consume_body(&mut self, fcx: &'_ FnCtxt<'_, 'tcx>, def_id: DefId, body: &'tcx Body<'tcx>) {
+ // Run ExprUseVisitor to find where values are consumed.
+ ExprUseVisitor::new(
+ self,
+ &fcx.infcx,
+ def_id.expect_local(),
+ fcx.param_env,
+ &fcx.typeck_results.borrow(),
+ )
+ .consume_body(body);
+ }
+
+ fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
+ if !self.places.consumed.contains_key(&consumer) {
+ self.places.consumed.insert(consumer, <_>::default());
+ }
+ self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
+ }
+}
+
+impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
+ fn consume(
+ &mut self,
+ place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+ diag_expr_id: HirId,
+ ) {
+ let parent = match self.hir.find_parent_node(place_with_id.hir_id) {
+ Some(parent) => parent,
+ None => place_with_id.hir_id,
+ };
+ debug!(
+ "consume {:?}; diag_expr_id={:?}, using parent {:?}",
+ place_with_id, diag_expr_id, parent
+ );
+ place_with_id
+ .try_into()
+ .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
+ }
+
+ fn borrow(
+ &mut self,
+ place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+ _diag_expr_id: HirId,
+ _bk: rustc_middle::ty::BorrowKind,
+ ) {
+ self.places
+ .borrowed
+ .insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
+ }
+
+ fn mutate(
+ &mut self,
+ _assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
+ _diag_expr_id: HirId,
+ ) {
+ }
+
+ fn fake_read(
+ &mut self,
+ _place: expr_use_visitor::Place<'tcx>,
+ _cause: rustc_middle::mir::FakeReadCause,
+ _diag_expr_id: HirId,
+ ) {
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 6314f2a..74f6f50 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -297,6 +297,11 @@
sym::const_allocate => {
(0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
}
+ sym::const_deallocate => (
+ 0,
+ vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize],
+ tcx.mk_unit(),
+ ),
sym::ptr_offset_from => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
@@ -453,7 +458,7 @@
sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()),
sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)),
- sym::simd_cast => (2, vec![param(0)], param(1)),
+ sym::simd_cast | sym::simd_as => (2, vec![param(0)], param(1)),
sym::simd_bitmask => (2, vec![param(0)], param(1)),
sym::simd_select | sym::simd_select_bitmask => {
(2, vec![param(0), param(1), param(1)], param(1))
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index dabfe92..fdc3ba1 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -149,7 +149,7 @@
// time writing the results into the various typeck results.
let mut autoderef =
self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
- let (_, n) = match autoderef.nth(pick.autoderefs) {
+ let (ty, n) = match autoderef.nth(pick.autoderefs) {
Some(n) => n,
None => {
return self.tcx.ty_error_with_message(
@@ -161,14 +161,15 @@
assert_eq!(n, pick.autoderefs);
let mut adjustments = self.adjust_steps(&autoderef);
+ let mut target = self.structurally_resolved_type(autoderef.span(), ty);
- let mut target =
- self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
-
- match &pick.autoref_or_ptr_adjustment {
+ match pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
let region = self.next_region_var(infer::Autoref(self.span));
- target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
+ // Type we're wrapping in a reference, used later for unsizing
+ let base_ty = target;
+
+ target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
let mutbl = match mutbl {
hir::Mutability::Not => AutoBorrowMutability::Not,
hir::Mutability::Mut => AutoBorrowMutability::Mut {
@@ -182,18 +183,26 @@
target,
});
- if let Some(unsize_target) = unsize {
+ if unsize {
+ let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
+ self.tcx.mk_slice(*elem_ty)
+ } else {
+ bug!(
+ "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
+ base_ty
+ )
+ };
target = self
.tcx
- .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
+ .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
adjustments
.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
}
}
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
target = match target.kind() {
- ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
- assert_eq!(*mutbl, hir::Mutability::Mut);
+ &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
+ assert_eq!(mutbl, hir::Mutability::Mut);
self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
}
other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index f7f4c52..e5ef52e 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -227,7 +227,7 @@
if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
let trait_type = self
.tcx
- .mk_ref(region, ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() });
+ .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
// We probe again to see if there might be a borrow mutability discrepancy.
match self.lookup_probe(
span,
@@ -359,6 +359,8 @@
let (obligation, substs) =
self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
+ debug!(?obligation);
+
// Now we want to know if this can be matched
if !self.predicate_may_hold(&obligation) {
debug!("--> Cannot match obligation");
@@ -369,7 +371,7 @@
// Trait must have a method named `m_name` and it should not have
// type parameters or early-bound regions.
let tcx = self.tcx;
- let method_item = match self.associated_item(trait_def_id, m_name, Namespace::ValueNS) {
+ let method_item = match self.associated_value(trait_def_id, m_name) {
Some(method_item) => method_item,
None => {
tcx.sess.delay_span_bug(
@@ -482,7 +484,7 @@
let variant_def = adt_def
.variants
.iter()
- .find(|vd| tcx.hygienic_eq(method_name, vd.ident, adt_def.did));
+ .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did));
if let Some(variant_def) = variant_def {
// Braced variants generate unusable names in value namespace (reserved for
// possible future use), so variants resolved as associated items may refer to
@@ -538,15 +540,10 @@
/// Finds item with name `item_name` defined in impl/trait `def_id`
/// and return it, or `None`, if no such item was defined there.
- pub fn associated_item(
- &self,
- def_id: DefId,
- item_name: Ident,
- ns: Namespace,
- ) -> Option<ty::AssocItem> {
+ pub fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<ty::AssocItem> {
self.tcx
.associated_items(def_id)
- .find_by_name_and_namespace(self.tcx, item_name, ns, def_id)
+ .find_by_name_and_namespace(self.tcx, item_name, Namespace::ValueNS, def_id)
.copied()
}
}
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 5615a08..c429e0f 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -9,7 +9,6 @@
use crate::hir::def_id::DefId;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::Namespace;
@@ -59,7 +58,7 @@
/// This is the OriginalQueryValues for the steps queries
/// that are answered in steps.
orig_steps_var_values: OriginalQueryValues<'tcx>,
- steps: Lrc<Vec<CandidateStep<'tcx>>>,
+ steps: &'tcx [CandidateStep<'tcx>],
inherent_candidates: Vec<Candidate<'tcx>>,
extension_candidates: Vec<Candidate<'tcx>>,
@@ -167,26 +166,26 @@
/// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
/// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
-#[derive(Debug, PartialEq, Clone)]
-pub enum AutorefOrPtrAdjustment<'tcx> {
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum AutorefOrPtrAdjustment {
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
/// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
Autoref {
mutbl: hir::Mutability,
- /// Indicates that the source expression should be "unsized" to a target type. This should
- /// probably eventually go away in favor of just coercing method receivers.
- unsize: Option<Ty<'tcx>>,
+ /// Indicates that the source expression should be "unsized" to a target type.
+ /// This is special-cased for just arrays unsizing to slices.
+ unsize: bool,
},
/// Receiver has type `*mut T`, convert to `*const T`
ToConstPtr,
}
-impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
- fn get_unsize(&self) -> Option<Ty<'tcx>> {
+impl AutorefOrPtrAdjustment {
+ fn get_unsize(&self) -> bool {
match self {
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
- AutorefOrPtrAdjustment::ToConstPtr => None,
+ AutorefOrPtrAdjustment::ToConstPtr => false,
}
}
}
@@ -204,7 +203,7 @@
/// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
/// `*mut T`, convert it to `*const T`.
- pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
+ pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
pub self_ty: Ty<'tcx>,
}
@@ -364,7 +363,7 @@
param_env_and_self_ty, self_ty
);
MethodAutoderefStepsResult {
- steps: Lrc::new(vec![CandidateStep {
+ steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
self_ty: self.make_query_response_ignoring_pending_obligations(
canonical_inference_vars,
self_ty,
@@ -516,7 +515,7 @@
steps.push(CandidateStep {
self_ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
- infcx.tcx.mk_slice(elem_ty),
+ infcx.tcx.mk_slice(*elem_ty),
),
autoderefs: dereferences,
// this could be from an unsafe deref if we had
@@ -533,8 +532,8 @@
debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
MethodAutoderefStepsResult {
- steps: Lrc::new(steps),
- opt_bad_ty: opt_bad_ty.map(Lrc::new),
+ steps: tcx.arena.alloc_from_iter(steps),
+ opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
reached_recursion_limit: autoderef.reached_recursion_limit(),
}
})
@@ -548,7 +547,7 @@
method_name: Option<Ident>,
return_type: Option<Ty<'tcx>>,
orig_steps_var_values: OriginalQueryValues<'tcx>,
- steps: Lrc<Vec<CandidateStep<'tcx>>>,
+ steps: &'tcx [CandidateStep<'tcx>],
is_suggestion: IsSuggestion,
scope_expr_id: hir::HirId,
) -> ProbeContext<'a, 'tcx> {
@@ -605,8 +604,7 @@
}
fn assemble_inherent_candidates(&mut self) {
- let steps = Lrc::clone(&self.steps);
- for step in steps.iter() {
+ for step in self.steps.iter() {
self.assemble_probe(&step.self_ty);
}
}
@@ -1033,7 +1031,7 @@
true
}
})
- .map(|candidate| candidate.item.ident)
+ .map(|candidate| candidate.item.ident(self.tcx))
.filter(|&name| set.insert(name))
.collect();
@@ -1202,7 +1200,7 @@
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
- unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
+ unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
})
}
@@ -1227,10 +1225,8 @@
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
- pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
- mutbl,
- unsize: step.unsize.then_some(self_ty),
- });
+ pick.autoref_or_ptr_adjustment =
+ Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
pick
})
})
@@ -1251,7 +1247,7 @@
}
let ty = match self_ty.kind() {
- ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty,
+ &ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty,
_ => return None,
};
@@ -1440,7 +1436,7 @@
"<{} as {}>::{}",
stable_pick.self_ty,
self.tcx.def_path_str(def_id),
- stable_pick.item.ident
+ stable_pick.item.name
),
Applicability::MachineApplicable,
);
@@ -1750,14 +1746,12 @@
let best_name = {
let names = applicable_close_candidates
.iter()
- .map(|cand| cand.ident.name)
+ .map(|cand| cand.name)
.collect::<Vec<Symbol>>();
find_best_match_for_name(&names, self.method_name.unwrap().name, None)
}
.unwrap();
- Ok(applicable_close_candidates
- .into_iter()
- .find(|method| method.ident.name == best_name))
+ Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name))
}
})
}
@@ -1908,14 +1902,19 @@
.associated_items(def_id)
.in_definition_order()
.filter(|x| {
- let dist = lev_distance(name.as_str(), x.ident.as_str());
- x.kind.namespace() == Namespace::ValueNS && dist > 0 && dist <= max_dist
+ if x.kind.namespace() != Namespace::ValueNS {
+ return false;
+ }
+ match lev_distance(name.as_str(), x.name.as_str(), max_dist) {
+ Some(d) => d > 0,
+ None => false,
+ }
})
.copied()
.collect()
} else {
self.fcx
- .associated_item(def_id, name, Namespace::ValueNS)
+ .associated_value(def_id, name)
.map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
}
} else {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 7f9c75c..a523ba2 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -5,17 +5,18 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
-use rustc_hir::def::Namespace;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, Node, QPath};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
+use rustc_middle::traits::util::supertraits;
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams};
use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
+use rustc_span::{source_map, FileName, MultiSpan, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
@@ -41,7 +42,19 @@
Err(..) => return false,
};
+ // This conditional prevents us from asking to call errors and unresolved types.
+ // It might seem that we can use `predicate_must_hold_modulo_regions`,
+ // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
+ // type resolution always gives a "maybe" here.
+ if self.autoderef(span, ty).any(|(ty, _)| {
+ info!("check deref {:?} error", ty);
+ matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
+ }) {
+ return false;
+ }
+
self.autoderef(span, ty).any(|(ty, _)| {
+ info!("check deref {:?} impl FnOnce", ty);
self.probe(|_| {
let fn_once_substs = tcx.mk_substs_trait(
ty,
@@ -99,16 +112,10 @@
CandidateSource::ImplSource(impl_did) => {
// Provide the best span we can. Use the item, if local to crate, else
// the impl, if local to crate (item may be defaulted), else nothing.
- let item = match self
- .associated_item(impl_did, item_name, Namespace::ValueNS)
- .or_else(|| {
- let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
- self.associated_item(
- impl_trait_ref.def_id,
- item_name,
- Namespace::ValueNS,
- )
- }) {
+ let item = match self.associated_value(impl_did, item_name).or_else(|| {
+ let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+ self.associated_value(impl_trait_ref.def_id, item_name)
+ }) {
Some(item) => item,
None => continue,
};
@@ -187,11 +194,10 @@
}
}
CandidateSource::TraitSource(trait_did) => {
- let item =
- match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
- Some(item) => item,
- None => continue,
- };
+ let item = match self.associated_value(trait_did, item_name) {
+ Some(item) => item,
+ None => continue,
+ };
let item_span = self
.tcx
.sess
@@ -271,16 +277,14 @@
// Suggest clamping down the type if the method that is being attempted to
// be used exists at all, and the type is an ambiguous numeric type
// ({integer}/{float}).
- let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
- self.associated_item(info.def_id, item_name, Namespace::ValueNS)
- });
+ let mut candidates = all_traits(self.tcx)
+ .into_iter()
+ .filter_map(|info| self.associated_value(info.def_id, item_name));
// There are methods that are defined on the primitive types and won't be
// found when exploring `all_traits`, but we also need them to be acurate on
// our suggestions (#47759).
let fund_assoc = |opt_def_id: Option<DefId>| {
- opt_def_id
- .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS))
- .is_some()
+ opt_def_id.and_then(|id| self.associated_value(id, item_name)).is_some()
};
let lang_items = tcx.lang_items();
let found_candidate = candidates.next().is_some()
@@ -398,11 +402,7 @@
.inherent_impls(adt_deref.did)
.iter()
.filter_map(|def_id| {
- self.associated_item(
- *def_id,
- item_name,
- Namespace::ValueNS,
- )
+ self.associated_value(*def_id, item_name)
})
.count()
>= 1
@@ -515,9 +515,7 @@
.iter()
.copied()
.filter(|def_id| {
- if let Some(assoc) =
- self.associated_item(*def_id, item_name, Namespace::ValueNS)
- {
+ if let Some(assoc) = self.associated_value(*def_id, item_name) {
// Check for both mode is the same so we avoid suggesting
// incorrect associated item.
match (mode, assoc.fn_has_self_parameter, source) {
@@ -719,7 +717,7 @@
let mut bound_spans = vec![];
let mut collect_type_param_suggestions =
- |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
+ |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)) =
(self_ty.kind(), parent_pred.kind().skip_binder())
@@ -805,10 +803,10 @@
item_def_id: projection_ty.item_def_id,
};
- let ty = pred.skip_binder().ty;
+ let term = pred.skip_binder().term;
- let obligation = format!("{} = {}", projection_ty, ty);
- let quiet = format!("{} = {}", quiet_projection_ty, ty);
+ let obligation = format!("{} = {}", projection_ty, term);
+ let quiet = format!("{} = {}", quiet_projection_ty, term);
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
@@ -839,9 +837,9 @@
_ => None,
})
{
- let parent_trait_ref = data.parent_trait_ref;
+ let parent_trait_ref = data.parent_trait_pred;
let parent_def_id = parent_trait_ref.def_id();
- let path = parent_trait_ref.print_only_trait_path();
+ let path = parent_trait_ref.print_modifiers_and_trait_path();
let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
let mut candidates = vec![];
self.tcx.for_each_relevant_impl(
@@ -908,7 +906,7 @@
.filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
.filter_map(|(pred, parent_pred, _cause)| {
format_pred(*pred).map(|(p, self_ty)| {
- collect_type_param_suggestions(self_ty, pred, &p);
+ collect_type_param_suggestions(self_ty, *pred, &p);
match parent_pred {
None => format!("`{}`", &p),
Some(parent_pred) => match format_pred(*parent_pred) {
@@ -916,7 +914,7 @@
Some((parent_p, _)) => {
collect_type_param_suggestions(
self_ty,
- parent_pred,
+ *parent_pred,
&p,
);
format!("`{}`\nwhich is required by `{}`", p, parent_p)
@@ -997,7 +995,7 @@
if unsatisfied_predicates.is_empty() && actual.is_enum() {
let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
- &adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
+ &adt_def.variants.iter().map(|s| s.name).collect::<Vec<_>>(),
item_name.name,
None,
) {
@@ -1041,7 +1039,7 @@
def_kind.article(),
def_kind.descr(lev_candidate.def_id),
),
- lev_candidate.ident.to_string(),
+ lev_candidate.name.to_string(),
Applicability::MaybeIncorrect,
);
}
@@ -1102,8 +1100,8 @@
if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
if needs_mut {
let trait_type = self.tcx.mk_ref(
- region,
- ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
+ *region,
+ ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
);
err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
}
@@ -1212,9 +1210,9 @@
Some(adt) if adt.did.is_local() => adt,
_ => continue,
};
- let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) {
- Some(sym::Default) => !adt.is_enum(),
- Some(
+ if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
+ let can_derive = match diagnostic_name {
+ sym::Default => !adt.is_enum(),
sym::Eq
| sym::PartialEq
| sym::Ord
@@ -1222,16 +1220,30 @@
| sym::Clone
| sym::Copy
| sym::Hash
- | sym::Debug,
- ) => true,
- _ => false,
- };
- if can_derive {
- derives.push((
- format!("{}", trait_pred.self_ty()),
- self.tcx.def_span(adt.did),
- format!("{}", trait_pred.trait_ref.print_only_trait_name()),
- ));
+ | sym::Debug => true,
+ _ => false,
+ };
+ if can_derive {
+ let self_name = trait_pred.self_ty().to_string();
+ let self_span = self.tcx.def_span(adt.did);
+ if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
+ for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
+ {
+ if let Some(parent_diagnostic_name) =
+ self.tcx.get_diagnostic_name(super_trait.def_id())
+ {
+ derives.push((
+ self_name.clone(),
+ self_span.clone(),
+ parent_diagnostic_name.to_string(),
+ ));
+ }
+ }
+ }
+ derives.push((self_name, self_span, diagnostic_name.to_string()));
+ } else {
+ traits.push(self.tcx.def_span(trait_pred.def_id()));
+ }
} else {
traits.push(self.tcx.def_span(trait_pred.def_id()));
}
@@ -1290,7 +1302,7 @@
span: Span,
) {
let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
- Some(output_ty) => self.resolve_vars_if_possible(output_ty),
+ Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
_ => return,
};
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
@@ -1321,7 +1333,7 @@
if Some(*parent_did) != self.tcx.parent(*trait_did)
&& self
.tcx
- .item_children(*parent_did)
+ .module_children(*parent_did)
.iter()
.filter(|child| child.res.opt_def_id() == Some(*trait_did))
.all(|child| child.ident.name == kw::Underscore)
@@ -1478,13 +1490,13 @@
// just this list.
for (rcvr_ty, post) in &[
(rcvr_ty, ""),
- (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
- (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
+ (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
+ (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
] {
if let Ok(pick) = self.lookup_probe(
span,
item_name,
- rcvr_ty,
+ *rcvr_ty,
rcvr,
crate::check::method::probe::ProbeScope::AllTraits,
) {
@@ -1496,17 +1508,17 @@
let skip = skippable.contains(&did);
if pick.autoderefs == 0 && !skip {
err.span_label(
- pick.item.ident.span,
+ pick.item.ident(self.tcx).span,
&format!("the method is available for `{}` here", rcvr_ty),
);
}
break;
}
for (rcvr_ty, pre) in &[
- (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
- (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
- (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
- (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
+ (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"),
+ (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"),
+ (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
+ (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
] {
if let Some(new_rcvr_t) = *rcvr_ty {
if let Ok(pick) = self.lookup_probe(
@@ -1524,14 +1536,13 @@
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
// implement the `AsRef` trait.
let skip = skippable.contains(&did)
- || (("Pin::new" == *pre)
- && (Symbol::intern("as_ref") == item_name.name));
+ || (("Pin::new" == *pre) && (sym::as_ref == item_name.name));
// Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self`
if pick.autoderefs == 0 && !skip {
err.span_label(
- pick.item.ident.span,
+ pick.item.ident(self.tcx).span,
&format!("the method is available for `{}` here", new_rcvr_t),
);
err.multipart_suggestion(
@@ -1588,7 +1599,7 @@
}
}) && (type_is_local || info.def_id.is_local())
&& self
- .associated_item(info.def_id, item_name, Namespace::ValueNS)
+ .associated_value(info.def_id, item_name)
.filter(|item| {
if let ty::AssocKind::Fn = item.kind {
let id = item
@@ -1680,7 +1691,7 @@
let table_owner = table.borrow().hir_owner;
let generics = self.tcx.generics_of(table_owner.to_def_id());
let type_param = generics.type_param(param, self.tcx);
- let hir = &self.tcx.hir();
+ let hir = self.tcx.hir();
if let Some(def_id) = type_param.def_id.as_local() {
let id = hir.local_def_id_to_hir_id(def_id);
// Get the `hir::Param` to verify whether it already has any bounds.
@@ -1765,8 +1776,7 @@
// FIXME: Even though negative bounds are not implemented, we could maybe handle
// cases where a positive bound implies a negative impl.
(candidates, Vec::new())
- } else if let Some(simp_rcvr_ty) =
- simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes, StripReferences::No)
+ } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes)
{
let mut potential_candidates = Vec::new();
let mut explicitly_negative = Vec::new();
@@ -1780,12 +1790,8 @@
})
.any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
- let imp_simp = simplify_type(
- self.tcx,
- imp.self_ty(),
- SimplifyParams::Yes,
- StripReferences::No,
- );
+ let imp_simp =
+ simplify_type(self.tcx, imp.self_ty(), SimplifyParams::Yes);
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
})
{
@@ -1836,7 +1842,7 @@
[] => {}
[trait_info] => {
let msg = format!(
- "the trait `{}` defines an item `{}`, but is explicitely unimplemented",
+ "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
self.tcx.def_path_str(trait_info.def_id),
item_name
);
@@ -1844,7 +1850,7 @@
}
trait_infos => {
let mut msg = format!(
- "the following traits define an item `{}`, but are explicitely unimplemented:",
+ "the following traits define an item `{}`, but are explicitly unimplemented:",
item_name
);
for trait_info in trait_infos {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index a9e6b1c..6e0b902 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -511,19 +511,15 @@
fn get_owner_return_paths<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
-) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> {
+) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let id = tcx.hir().get_parent_item(hir_id);
- tcx.hir()
- .find(id)
- .map(|n| (id, n))
- .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b)))
- .map(|(hir_id, body_id)| {
- let body = tcx.hir().body(body_id);
- let mut visitor = ReturnsVisitor::default();
- visitor.visit_body(body);
- (hir_id, visitor)
- })
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
+ let body = tcx.hir().body(body_id);
+ let mut visitor = ReturnsVisitor::default();
+ visitor.visit_body(body);
+ (parent_id, visitor)
+ })
}
// Forbid defining intrinsics in Rust code,
@@ -566,7 +562,7 @@
fn report_forbidden_specialization(
tcx: TyCtxt<'_>,
- impl_item: &hir::ImplItem<'_>,
+ impl_item: &hir::ImplItemRef,
parent_impl: DefId,
) {
let mut err = struct_span_err!(
@@ -598,12 +594,12 @@
fn missing_items_err(
tcx: TyCtxt<'_>,
impl_span: Span,
- missing_items: &[ty::AssocItem],
+ missing_items: &[&ty::AssocItem],
full_impl_span: Span,
) {
let missing_items_msg = missing_items
.iter()
- .map(|trait_item| trait_item.ident.to_string())
+ .map(|trait_item| trait_item.name.to_string())
.collect::<Vec<_>>()
.join("`, `");
@@ -632,7 +628,7 @@
let msg = format!("implement the missing item: `{}`", snippet);
let appl = Applicability::HasPlaceholders;
if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
- err.span_label(span, format!("`{}` from trait", trait_item.ident));
+ err.span_label(span, format!("`{}` from trait", trait_item.name));
err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
} else {
err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
@@ -641,6 +637,31 @@
err.emit();
}
+fn missing_items_must_implement_one_of_err(
+ tcx: TyCtxt<'_>,
+ impl_span: Span,
+ missing_items: &[Ident],
+ annotation_span: Option<Span>,
+) {
+ let missing_items_msg =
+ missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_span,
+ E0046,
+ "not all trait items implemented, missing one of: `{}`",
+ missing_items_msg
+ );
+ err.span_label(impl_span, format!("missing one of `{}` in implementation", missing_items_msg));
+
+ if let Some(annotation_span) = annotation_span {
+ err.span_note(annotation_span, "required because of this annotation");
+ }
+
+ err.emit();
+}
+
/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
fn bounds_from_generic_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -695,7 +716,11 @@
// insert the associated types where they correspond, but for now let's be "lazy" and
// propose this instead of the following valid resugaring:
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
- where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty));
+ where_clauses.push(format!(
+ "{} = {}",
+ tcx.def_path_str(p.projection_ty.item_def_id),
+ p.term,
+ ));
}
let where_clauses = if where_clauses.is_empty() {
String::new()
@@ -780,16 +805,16 @@
fn_sig_suggestion(
tcx,
tcx.fn_sig(assoc.def_id).skip_binder(),
- assoc.ident,
+ assoc.ident(tcx),
tcx.predicates_of(assoc.def_id),
assoc,
)
}
- ty::AssocKind::Type => format!("type {} = Type;", assoc.ident),
+ ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
ty::AssocKind::Const => {
let ty = tcx.type_of(assoc.def_id);
let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
- format!("const {}: {} = {};", assoc.ident, ty, val)
+ format!("const {}: {} = {};", assoc.name, ty, val)
}
}
}
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 8ebfcdd..dd49d6f 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -221,7 +221,7 @@
},
};
let autoref = Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+ kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
target: method.sig.inputs()[0],
};
self.apply_adjustments(lhs_expr, vec![autoref]);
@@ -238,7 +238,7 @@
},
};
let autoref = Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+ kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
target: method.sig.inputs()[1],
};
// HACK(eddyb) Bypass checks due to reborrows being in
@@ -399,8 +399,8 @@
}
};
if let Ref(_, rty, _) = lhs_ty.kind() {
- if self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
- && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok()
+ if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
+ && self.lookup_op_method(*rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok()
{
if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
let msg = &format!(
@@ -423,7 +423,7 @@
}
}
if let Some(missing_trait) = missing_trait {
- let mut visitor = TypeParamVisitor(self.tcx, vec![]);
+ let mut visitor = TypeParamVisitor(vec![]);
visitor.visit_ty(lhs_ty);
if op.node == hir::BinOpKind::Add
@@ -434,7 +434,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.1[..] {
+ } else if let [ty] = &visitor.0[..] {
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
@@ -452,7 +452,7 @@
self.tcx,
self.body_id,
&mut err,
- ty,
+ *ty,
rhs_ty,
missing_trait,
p,
@@ -549,16 +549,9 @@
is_assign: IsAssign,
op: hir::BinOp,
) -> bool {
- let source_map = self.tcx.sess.source_map();
- let remove_borrow_msg = "String concatenation appends the string on the right to the \
- string on the left and may require reallocation. This \
- requires ownership of the string on the left";
-
- let msg = "`to_owned()` can be used to create an owned `String` \
- from a string reference. String concatenation \
- appends the string on the right to the string \
- on the left and may require reallocation. This \
- requires ownership of the string on the left";
+ let str_concat_note = "string concatenation requires an owned `String` on the left";
+ let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
+ let to_owned_msg = "create an owned `String` from a string reference";
let string_type = self.tcx.get_diagnostic_item(sym::String);
let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
@@ -574,31 +567,23 @@
) =>
{
if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
- err.span_label(
- op.span,
- "`+` cannot be used to concatenate two `&str` strings",
- );
- match source_map.span_to_snippet(lhs_expr.span) {
- Ok(lstring) => {
- err.span_suggestion(
- lhs_expr.span,
- if lstring.starts_with('&') {
- remove_borrow_msg
- } else {
- msg
- },
- if let Some(stripped) = lstring.strip_prefix('&') {
- // let a = String::new();
- // let _ = &a + "bar";
- stripped.to_string()
- } else {
- format!("{}.to_owned()", lstring)
- },
- Applicability::MachineApplicable,
- )
- }
- _ => err.help(msg),
- };
+ err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings");
+ err.note(str_concat_note);
+ if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
+ err.span_suggestion_verbose(
+ lhs_expr.span.until(lhs_inner_expr.span),
+ rm_borrow_msg,
+ "".to_owned(),
+ Applicability::MachineApplicable
+ );
+ } else {
+ err.span_suggestion_verbose(
+ lhs_expr.span.shrink_to_hi(),
+ to_owned_msg,
+ ".to_owned()".to_owned(),
+ Applicability::MachineApplicable
+ );
+ }
}
true
}
@@ -609,32 +594,30 @@
op.span,
"`+` cannot be used to concatenate a `&str` with a `String`",
);
- match (
- source_map.span_to_snippet(lhs_expr.span),
- source_map.span_to_snippet(rhs_expr.span),
- is_assign,
- ) {
- (Ok(l), Ok(r), IsAssign::No) => {
- let to_string = if let Some(stripped) = l.strip_prefix('&') {
- // let a = String::new(); let b = String::new();
- // let _ = &a + b;
- stripped.to_string()
+ match is_assign {
+ IsAssign::No => {
+ let sugg_msg;
+ let lhs_sugg = if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
+ sugg_msg = "remove the borrow on the left and add one on the right";
+ (lhs_expr.span.until(lhs_inner_expr.span), "".to_owned())
} else {
- format!("{}.to_owned()", l)
+ sugg_msg = "create an owned `String` on the left and add a borrow on the right";
+ (lhs_expr.span.shrink_to_hi(), ".to_owned()".to_owned())
};
- err.multipart_suggestion(
- msg,
- vec![
- (lhs_expr.span, to_string),
- (rhs_expr.span, format!("&{}", r)),
- ],
+ let suggestions = vec![
+ lhs_sugg,
+ (rhs_expr.span.shrink_to_lo(), "&".to_owned()),
+ ];
+ err.multipart_suggestion_verbose(
+ sugg_msg,
+ suggestions,
Applicability::MachineApplicable,
);
}
- _ => {
- err.help(msg);
+ IsAssign::Yes => {
+ err.note(str_concat_note);
}
- };
+ }
true
}
_ => false,
@@ -895,7 +878,7 @@
/// Dereferences a single level of immutable referencing.
fn deref_ty_if_possible<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.kind() {
- ty::Ref(_, ty, hir::Mutability::Not) => ty,
+ ty::Ref(_, ty, hir::Mutability::Not) => *ty,
_ => ty,
}
}
@@ -972,7 +955,7 @@
if let Some(generics) = param_def_id
.as_local()
.map(|id| hir.local_def_id_to_hir_id(id))
- .and_then(|id| hir.find(hir.get_parent_item(id)))
+ .and_then(|id| hir.find_by_def_id(hir.get_parent_item(id)))
.as_ref()
.and_then(|node| node.generics())
{
@@ -991,15 +974,12 @@
}
}
-struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec<Ty<'tcx>>);
+struct TypeParamVisitor<'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.1.push(ty);
+ self.0.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 ec06e0b..e034add 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -15,7 +15,7 @@
use rustc_span::hygiene::DesugaringKind;
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::symbol::{sym, Ident};
use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
@@ -1029,7 +1029,7 @@
let field_def_spans = if fields.is_empty() {
vec![res_span]
} else {
- fields.iter().map(|f| f.ident.span).collect()
+ fields.iter().map(|f| f.ident(self.tcx).span).collect()
};
let last_field_def_span = *field_def_spans.last().unwrap();
@@ -1231,7 +1231,7 @@
.fields
.iter()
.enumerate()
- .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field)))
+ .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
.collect::<FxHashMap<_, _>>();
// Keep track of which fields have already appeared in the pattern.
@@ -1272,7 +1272,7 @@
let mut unmentioned_fields = variant
.fields
.iter()
- .map(|field| (field, field.ident.normalize_to_macros_2_0()))
+ .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
.filter(|(_, ident)| !used_fields.contains_key(ident))
.collect::<Vec<_>>();
@@ -1579,7 +1579,8 @@
fields: &[hir::PatField<'_>],
variant: &VariantDef,
) -> String {
- let variant_field_idents = variant.fields.iter().map(|f| f.ident).collect::<Vec<Ident>>();
+ let variant_field_idents =
+ variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
fields
.iter()
.map(|field| {
@@ -1934,7 +1935,7 @@
element_ty: Ty<'tcx>,
arr_ty: Ty<'tcx>,
slice: Option<&'tcx Pat<'tcx>>,
- len: &ty::Const<'tcx>,
+ len: ty::Const<'tcx>,
min_len: u64,
) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
@@ -2028,16 +2029,51 @@
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(..)))
+ .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
{
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(
+ let applicability = Autoderef::new(
+ &self.infcx,
+ self.param_env,
+ self.body_id,
span,
- "consider slicing here",
- format!("{}[..]", snippet),
- Applicability::MachineApplicable,
- );
+ self.resolve_vars_if_possible(ti.expected),
+ span,
+ )
+ .find_map(|(ty, _)| {
+ match ty.kind() {
+ ty::Adt(adt_def, _)
+ if self.tcx.is_diagnostic_item(sym::Option, adt_def.did)
+ || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) =>
+ {
+ // Slicing won't work here, but `.as_deref()` might (issue #91328).
+ err.span_suggestion(
+ span,
+ "consider using `as_deref` here",
+ format!("{}.as_deref()", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ Some(None)
+ }
+
+ ty::Slice(..) | ty::Array(..) => {
+ Some(Some(Applicability::MachineApplicable))
+ }
+
+ _ => None,
+ }
+ })
+ .unwrap_or(Some(Applicability::MaybeIncorrect));
+
+ if let Some(applicability) = applicability {
+ err.span_suggestion(
+ span,
+ "consider slicing here",
+ format!("{}[..]", snippet),
+ applicability,
+ );
+ }
}
}
}
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index d01e21b..318979b 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -31,7 +31,7 @@
self.apply_adjustments(
oprnd_expr,
vec![Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+ kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
target: method.sig.inputs()[0],
}],
);
@@ -142,7 +142,7 @@
if unsize {
// We only unsize arrays here.
if let ty::Array(element_ty, _) = adjusted_ty.kind() {
- self_ty = self.tcx.mk_slice(element_ty);
+ self_ty = self.tcx.mk_slice(*element_ty);
} else {
continue;
}
@@ -165,9 +165,9 @@
let mut adjustments = self.adjust_steps(autoderef);
if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
adjustments.push(Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+ kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
target: self.tcx.mk_ref(
- region,
+ *region,
ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
),
});
@@ -432,9 +432,10 @@
// not the case today.
allow_two_phase_borrow: AllowTwoPhase::No,
};
- adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
- adjustment.target =
- self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+ adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl));
+ adjustment.target = self
+ .tcx
+ .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
}
source = adjustment.target;
}
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 1b42edc..513e857 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -80,7 +80,7 @@
use rustc_data_structures::stable_set::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode};
@@ -406,12 +406,6 @@
// hierarchy, and in particular the relationships between free
// regions, until regionck, as described in #3238.
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_fn(
&mut self,
fk: intravisit::FnKind<'tcx>,
@@ -695,7 +689,7 @@
let rptr_ty = self.resolve_node_type(id);
if let ty::Ref(r, _, _) = rptr_ty.kind() {
debug!("rptr_ty={}", rptr_ty);
- self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed);
+ self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed);
}
}
@@ -859,15 +853,15 @@
self.sub_regions(
infer::ReborrowUpvar(span, upvar_id),
borrow_region,
- upvar_borrow.region,
+ captured_place.region.unwrap(),
);
- if let ty::ImmBorrow = upvar_borrow.kind {
+ if let ty::ImmBorrow = upvar_borrow {
debug!("link_upvar_region: capture by shared ref");
} else {
all_captures_are_imm_borrow = false;
}
}
- ty::UpvarCapture::ByValue(_) => {
+ ty::UpvarCapture::ByValue => {
all_captures_are_imm_borrow = false;
}
}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index ffd7d29..949d857 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -33,12 +33,11 @@
use super::FnCtxt;
use crate::expr_use_visitor as euv;
-use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_infer::infer::UpvarRegion;
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
use rustc_middle::mir::FakeReadCause;
@@ -72,7 +71,7 @@
/// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
/// during capture analysis. Information in this map feeds into the minimum capture
/// analysis pass.
-type InferredCaptureInformation<'tcx> = FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>;
+type InferredCaptureInformation<'tcx> = Vec<(Place<'tcx>, ty::CaptureInfo)>;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
@@ -141,12 +140,6 @@
}
impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
match expr.kind {
hir::ExprKind::Closure(cc, _, body_id, _, _) => {
@@ -207,8 +200,7 @@
assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
let mut delegate = InferBorrowKind {
fcx: self,
- closure_def_id,
- closure_span: span,
+ closure_def_id: local_def_id,
capture_information: Default::default(),
fake_reads: Default::default(),
};
@@ -231,7 +223,7 @@
let (capture_information, closure_kind, origin) = self
.process_collected_capture_information(capture_clause, delegate.capture_information);
- self.compute_min_captures(closure_def_id, capture_information);
+ self.compute_min_captures(closure_def_id, capture_information, span);
let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
@@ -252,21 +244,19 @@
debug!("seed place {:?}", place);
- let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
- let capture_kind =
- self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span);
+ let capture_kind = self.init_capture_kind_for_place(&place, capture_clause);
let fake_info = ty::CaptureInfo {
capture_kind_expr_id: None,
path_expr_id: None,
capture_kind,
};
- capture_information.insert(place, fake_info);
+ capture_information.push((place, fake_info));
}
}
// This will update the min captures based on this new fake information.
- self.compute_min_captures(closure_def_id, capture_information);
+ self.compute_min_captures(closure_def_id, capture_information, span);
}
let before_feature_tys = self.final_upvar_tys(closure_def_id);
@@ -362,7 +352,7 @@
captured_place.place, upvar_ty, capture, captured_place.mutability,
);
- apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture)
+ apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
})
.collect()
}
@@ -387,77 +377,68 @@
capture_clause: hir::CaptureBy,
capture_information: InferredCaptureInformation<'tcx>,
) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) {
- let mut processed: InferredCaptureInformation<'tcx> = Default::default();
-
let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM;
let mut origin: Option<(Span, Place<'tcx>)> = None;
- for (place, mut capture_info) in capture_information {
- // Apply rules for safety before inferring closure kind
- let (place, capture_kind) =
- restrict_capture_precision(place, capture_info.capture_kind);
- capture_info.capture_kind = capture_kind;
+ let processed = capture_information
+ .into_iter()
+ .map(|(place, mut capture_info)| {
+ // Apply rules for safety before inferring closure kind
+ let (place, capture_kind) =
+ restrict_capture_precision(place, capture_info.capture_kind);
- let (place, capture_kind) =
- truncate_capture_for_optimization(place, capture_info.capture_kind);
- capture_info.capture_kind = capture_kind;
+ let (place, capture_kind) = truncate_capture_for_optimization(place, capture_kind);
- let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
- self.tcx.hir().span(usage_expr)
- } else {
- unreachable!()
- };
+ let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
+ self.tcx.hir().span(usage_expr)
+ } else {
+ unreachable!()
+ };
- let updated = match capture_info.capture_kind {
- ty::UpvarCapture::ByValue(..) => match closure_kind {
- ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
- (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
- }
- // If closure is already FnOnce, don't update
- ty::ClosureKind::FnOnce => (closure_kind, origin),
- },
-
- ty::UpvarCapture::ByRef(ty::UpvarBorrow {
- kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
- ..
- }) => {
- match closure_kind {
- ty::ClosureKind::Fn => {
- (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+ let updated = match capture_kind {
+ ty::UpvarCapture::ByValue => match closure_kind {
+ ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+ (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
}
- // Don't update the origin
- ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => (closure_kind, origin),
+ // If closure is already FnOnce, don't update
+ ty::ClosureKind::FnOnce => (closure_kind, origin.take()),
+ },
+
+ ty::UpvarCapture::ByRef(
+ ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+ ) => {
+ match closure_kind {
+ ty::ClosureKind::Fn => {
+ (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+ }
+ // Don't update the origin
+ ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => {
+ (closure_kind, origin.take())
+ }
+ }
}
- }
- _ => (closure_kind, origin),
- };
+ _ => (closure_kind, origin.take()),
+ };
- closure_kind = updated.0;
- origin = updated.1;
+ closure_kind = updated.0;
+ origin = updated.1;
- let (place, capture_kind) = match capture_clause {
- hir::CaptureBy::Value => adjust_for_move_closure(place, capture_info.capture_kind),
- hir::CaptureBy::Ref => {
- adjust_for_non_move_closure(place, capture_info.capture_kind)
- }
- };
+ let (place, capture_kind) = match capture_clause {
+ hir::CaptureBy::Value => adjust_for_move_closure(place, capture_kind),
+ hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
+ };
- // 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);
+ // 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);
- }
+ capture_info.capture_kind = capture_kind;
+ (place, capture_info)
+ })
+ .collect();
(processed, closure_kind, origin)
}
@@ -535,6 +516,7 @@
&self,
closure_def_id: DefId,
capture_information: InferredCaptureInformation<'tcx>,
+ closure_span: Span,
) {
if capture_information.is_empty() {
return;
@@ -554,8 +536,12 @@
let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
None => {
let mutability = self.determine_capture_mutability(&typeck_results, &place);
- let min_cap_list =
- vec![ty::CapturedPlace { place, info: capture_info, mutability }];
+ let min_cap_list = vec![ty::CapturedPlace {
+ place,
+ info: capture_info,
+ mutability,
+ region: None,
+ }];
root_var_min_capture_list.insert(var_hir_id, min_cap_list);
continue;
}
@@ -608,8 +594,18 @@
if !descendant_found {
for possible_ancestor in min_cap_list.iter_mut() {
match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
+ PlaceAncestryRelation::SamePlace => {
+ ancestor_found = true;
+ possible_ancestor.info = determine_capture_info(
+ possible_ancestor.info,
+ updated_capture_info,
+ );
+
+ // Only one related place will be in the list.
+ break;
+ }
// current place is descendant of possible_ancestor
- PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
+ PlaceAncestryRelation::Descendant => {
ancestor_found = true;
let backup_path_expr_id = possible_ancestor.info.path_expr_id;
@@ -629,7 +625,7 @@
// we need to keep the ancestor's `path_expr_id`
possible_ancestor.info.path_expr_id = backup_path_expr_id;
- // Only one ancestor of the current place will be in the list.
+ // Only one related place will be in the list.
break;
}
_ => {}
@@ -640,12 +636,31 @@
// Only need to insert when we don't have an ancestor in the existing min capture list
if !ancestor_found {
let mutability = self.determine_capture_mutability(&typeck_results, &place);
- let captured_place =
- ty::CapturedPlace { place, info: updated_capture_info, mutability };
+ let captured_place = ty::CapturedPlace {
+ place,
+ info: updated_capture_info,
+ mutability,
+ region: None,
+ };
min_cap_list.push(captured_place);
}
}
+ // For each capture that is determined to be captured by ref, add region info.
+ for (_, captures) in &mut root_var_min_capture_list {
+ for capture in captures {
+ match capture.info.capture_kind {
+ ty::UpvarCapture::ByRef(_) => {
+ let PlaceBase::Upvar(upvar_id) = capture.place.base else { bug!("expected upvar") };
+ let origin = UpvarRegion(upvar_id, closure_span);
+ let upvar_region = self.next_region_var(origin);
+ capture.region = Some(upvar_region);
+ }
+ _ => (),
+ }
+ }
+ }
+
debug!(
"For closure={:?}, min_captures before sorting={:?}",
closure_def_id, root_var_min_capture_list
@@ -947,7 +962,12 @@
max_capture_info = determine_capture_info(max_capture_info, capture.info);
}
- apply_capture_kind_on_capture_ty(self.tcx, ty, max_capture_info.capture_kind)
+ apply_capture_kind_on_capture_ty(
+ self.tcx,
+ ty,
+ max_capture_info.capture_kind,
+ Some(self.tcx.lifetimes.re_erased),
+ )
}
};
@@ -977,6 +997,7 @@
self.tcx,
capture.place.ty(),
capture.info.capture_kind,
+ Some(self.tcx.lifetimes.re_erased),
);
// Checks if a capture implements any of the auto traits
@@ -1086,7 +1107,7 @@
for captured_place in root_var_min_capture_list.iter() {
match captured_place.info.capture_kind {
// Only care about captures that are moved into the closure
- ty::UpvarCapture::ByValue(..) => {
+ ty::UpvarCapture::ByValue => {
projections_list.push(captured_place.place.projections.as_slice());
diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
source_expr: captured_place.info.path_expr_id,
@@ -1470,9 +1491,7 @@
&self,
place: &Place<'tcx>,
capture_clause: hir::CaptureBy,
- upvar_id: ty::UpvarId,
- closure_span: Span,
- ) -> ty::UpvarCapture<'tcx> {
+ ) -> ty::UpvarCapture {
match capture_clause {
// In case of a move closure if the data is accessed through a reference we
// want to capture by ref to allow precise capture using reborrows.
@@ -1480,15 +1499,10 @@
// If the data will be moved out of this place, then the place will be truncated
// at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
// the closure.
- hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => {
- ty::UpvarCapture::ByValue(None)
+ hir::CaptureBy::Value if !place.deref_tys().any(Ty::is_ref) => {
+ ty::UpvarCapture::ByValue
}
- hir::CaptureBy::Value | hir::CaptureBy::Ref => {
- let origin = UpvarRegion(upvar_id, closure_span);
- let upvar_region = self.next_region_var(origin);
- let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
- ty::UpvarCapture::ByRef(upvar_borrow)
- }
+ hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow),
}
}
@@ -1513,7 +1527,7 @@
fn log_capture_analysis_first_pass(
&self,
closure_def_id: rustc_hir::def_id::DefId,
- capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
+ capture_information: &InferredCaptureInformation<'tcx>,
closure_span: Span,
) {
if self.should_log_capture_analysis(closure_def_id) {
@@ -1629,9 +1643,9 @@
fn restrict_repr_packed_field_ref_capture<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- place: &Place<'tcx>,
- mut curr_borrow_kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ mut place: Place<'tcx>,
+ mut curr_borrow_kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
let pos = place.projections.iter().enumerate().position(|(i, p)| {
let ty = place.ty_before_projection(i);
@@ -1639,7 +1653,8 @@
match p.kind {
ProjectionKind::Field(..) => match ty.kind() {
ty::Adt(def, _) if def.repr.packed() => {
- match tcx.layout_of(param_env.and(p.ty)) {
+ // We erase regions here because they cannot be hashed
+ match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
Ok(layout) if layout.align.abi.bytes() == 1 => {
// if the alignment is 1, the type can't be further
// disaligned.
@@ -1662,8 +1677,6 @@
}
});
- let mut place = place.clone();
-
if let Some(pos) = pos {
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos);
}
@@ -1675,12 +1688,14 @@
fn apply_capture_kind_on_capture_ty<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
- capture_kind: UpvarCapture<'tcx>,
+ capture_kind: UpvarCapture,
+ region: Option<ty::Region<'tcx>>,
) -> Ty<'tcx> {
match capture_kind {
- ty::UpvarCapture::ByValue(_) => ty,
- ty::UpvarCapture::ByRef(borrow) => tcx
- .mk_ref(borrow.region, ty::TypeAndMut { ty: ty, mutbl: borrow.kind.to_mutbl_lossy() }),
+ ty::UpvarCapture::ByValue => ty,
+ ty::UpvarCapture::ByRef(kind) => {
+ tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() })
+ }
}
}
@@ -1708,9 +1723,7 @@
fcx: &'a FnCtxt<'a, 'tcx>,
// The def-id of the closure whose kind and upvar accesses are being inferred.
- closure_def_id: DefId,
-
- closure_span: Span,
+ closure_def_id: LocalDefId,
/// For each Place that is captured by the closure, we track the minimal kind of
/// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
@@ -1742,184 +1755,38 @@
fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
}
-impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
- #[instrument(skip(self), level = "debug")]
- fn adjust_upvar_borrow_kind_for_consume(
- &mut self,
- place_with_id: &PlaceWithHirId<'tcx>,
- diag_expr_id: hir::HirId,
- ) {
- let tcx = self.fcx.tcx;
- let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else {
- return;
- };
-
- debug!(?upvar_id);
-
- let usage_span = tcx.hir().span(diag_expr_id);
-
- let capture_info = ty::CaptureInfo {
- capture_kind_expr_id: Some(diag_expr_id),
- path_expr_id: Some(diag_expr_id),
- capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
- };
-
- let curr_info = self.capture_information[&place_with_id.place];
- let updated_info = determine_capture_info(curr_info, capture_info);
-
- self.capture_information[&place_with_id.place] = updated_info;
- }
-
- /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
- /// to). If the place is based on a by-ref upvar, this implies that
- /// the upvar must be borrowed using an `&mut` borrow.
- #[instrument(skip(self), level = "debug")]
- fn adjust_upvar_borrow_kind_for_mut(
- &mut self,
- place_with_id: &PlaceWithHirId<'tcx>,
- diag_expr_id: hir::HirId,
- ) {
- if let PlaceBase::Upvar(_) = place_with_id.place.base {
- // 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, ty::MutBorrow);
- }
- }
-
- #[instrument(skip(self), level = "debug")]
- fn adjust_upvar_borrow_kind_for_unique(
- &mut self,
- place_with_id: &PlaceWithHirId<'tcx>,
- diag_expr_id: hir::HirId,
- ) {
- if let PlaceBase::Upvar(_) = place_with_id.place.base {
- if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
- // Raw pointers don't inherit mutability.
- return;
- }
- // for a borrowed pointer to be unique, its base must be unique
- self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow);
- }
- }
-
- fn adjust_upvar_deref(
- &mut self,
- place_with_id: &PlaceWithHirId<'tcx>,
- diag_expr_id: hir::HirId,
- borrow_kind: ty::BorrowKind,
- ) {
- assert!(match borrow_kind {
- ty::MutBorrow => true,
- ty::UniqueImmBorrow => true,
-
- // imm borrows never require adjusting any kinds, so we don't wind up here
- ty::ImmBorrow => false,
- });
-
- // if this is an implicit deref of an
- // upvar, then we need to modify the
- // borrow_kind of the upvar to make sure it
- // is inferred to mutable if necessary
- self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind);
- }
-
- /// We infer the borrow_kind with which to borrow upvars in a stack closure.
- /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`,
- /// moving from left to right as needed (but never right to left).
- /// Here the argument `mutbl` is the borrow_kind that is required by
- /// some particular use.
- #[instrument(skip(self), level = "debug")]
- fn adjust_upvar_borrow_kind(
- &mut self,
- place_with_id: &PlaceWithHirId<'tcx>,
- diag_expr_id: hir::HirId,
- kind: ty::BorrowKind,
- ) {
- let curr_capture_info = self.capture_information[&place_with_id.place];
-
- debug!(?curr_capture_info);
-
- if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
- // It's already captured by value, we don't need to do anything here
- return;
- } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind {
- // Use the same region as the current capture information
- // Doesn't matter since only one of the UpvarBorrow will be used.
- let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
-
- let capture_info = ty::CaptureInfo {
- capture_kind_expr_id: Some(diag_expr_id),
- path_expr_id: Some(diag_expr_id),
- capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
- };
- let updated_info = determine_capture_info(curr_capture_info, capture_info);
- self.capture_information[&place_with_id.place] = updated_info;
- };
- }
-
- #[instrument(skip(self, diag_expr_id), level = "debug")]
- fn init_capture_info_for_place(
- &mut self,
- place_with_id: &PlaceWithHirId<'tcx>,
- diag_expr_id: hir::HirId,
- ) {
- if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
- assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
-
- // Initialize to ImmBorrow
- // We will escalate the CaptureKind based on any uses we see or in `process_collected_capture_information`.
- let origin = UpvarRegion(upvar_id, self.closure_span);
- let upvar_region = self.fcx.next_region_var(origin);
- let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
- let capture_kind = ty::UpvarCapture::ByRef(upvar_borrow);
-
- let expr_id = Some(diag_expr_id);
- let capture_info = ty::CaptureInfo {
- capture_kind_expr_id: expr_id,
- path_expr_id: expr_id,
- capture_kind,
- };
-
- debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
-
- self.capture_information.insert(place_with_id.place.clone(), capture_info);
- } else {
- debug!("Not upvar");
- }
- }
-}
-
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
- 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 dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
- kind: ty::BorrowKind::ImmBorrow,
- region: &ty::ReErased,
- });
+ let PlaceBase::Upvar(_) = place.base else { return };
- let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+ // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+ // such as deref of a raw pointer.
+ let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
- 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));
- }
+ 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));
}
#[instrument(skip(self), level = "debug")]
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
- if !self.capture_information.contains_key(&place_with_id.place) {
- self.init_capture_info_for_place(place_with_id, diag_expr_id);
- }
+ let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+ assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
- self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id);
+ self.capture_information.push((
+ place_with_id.place.clone(),
+ ty::CaptureInfo {
+ capture_kind_expr_id: Some(diag_expr_id),
+ path_expr_id: Some(diag_expr_id),
+ capture_kind: ty::UpvarCapture::ByValue,
+ },
+ ));
}
#[instrument(skip(self), level = "debug")]
@@ -1929,40 +1796,35 @@
diag_expr_id: hir::HirId,
bk: ty::BorrowKind,
) {
+ let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+ assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
+
// The region here will get discarded/ignored
- let dummy_capture_kind =
- ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased });
+ let capture_kind = ty::UpvarCapture::ByRef(bk);
// 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, updated_kind) = restrict_repr_packed_field_ref_capture(
+ let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
self.fcx.tcx,
self.fcx.param_env,
- &place_with_id.place,
- dummy_capture_kind,
+ place_with_id.place.clone(),
+ capture_kind,
);
- let place_with_id = PlaceWithHirId { place, ..*place_with_id };
-
- if !self.capture_information.contains_key(&place_with_id.place) {
- self.init_capture_info_for_place(&place_with_id, diag_expr_id);
+ // Raw pointers don't inherit mutability
+ if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) {
+ capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
}
- 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);
- }
+ self.capture_information.push((
+ place,
+ ty::CaptureInfo {
+ capture_kind_expr_id: Some(diag_expr_id),
+ path_expr_id: Some(diag_expr_id),
+ capture_kind,
},
-
- // Just truncating the place will never cause capture kind to be updated to ByValue
- ty::UpvarCapture::ByValue(..) => unreachable!(),
- }
+ ));
}
#[instrument(skip(self), level = "debug")]
@@ -1975,12 +1837,12 @@
fn restrict_precision_for_drop_types<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
mut place: Place<'tcx>,
- mut curr_mode: ty::UpvarCapture<'tcx>,
+ mut curr_mode: ty::UpvarCapture,
span: Span,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+) -> (Place<'tcx>, ty::UpvarCapture) {
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) {
+ 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() => {
@@ -2001,8 +1863,8 @@
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
fn restrict_precision_for_unsafe<'tcx>(
mut place: Place<'tcx>,
- mut curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ mut curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
if place.base_ty.is_unsafe_ptr() {
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
}
@@ -2034,8 +1896,8 @@
/// 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>) {
+ curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode);
if place.projections.is_empty() {
@@ -2062,30 +1924,28 @@
/// Truncate deref of any reference.
fn adjust_for_move_closure<'tcx>(
mut place: Place<'tcx>,
- mut kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ mut kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
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))
+ (place, ty::UpvarCapture::ByValue)
}
/// 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>,
- mut kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ mut kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
let contains_deref =
place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
match kind {
- ty::UpvarCapture::ByValue(..) => {
+ ty::UpvarCapture::ByValue => {
if let Some(idx) = contains_deref {
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
}
@@ -2123,13 +1983,13 @@
fn construct_capture_kind_reason_string<'tcx>(
tcx: TyCtxt<'_>,
place: &Place<'tcx>,
- capture_info: &ty::CaptureInfo<'tcx>,
+ capture_info: &ty::CaptureInfo,
) -> String {
let place_str = construct_place_string(tcx, place);
let capture_kind_str = match capture_info.capture_kind {
- ty::UpvarCapture::ByValue(_) => "ByValue".into(),
- ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+ ty::UpvarCapture::ByValue => "ByValue".into(),
+ ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
};
format!("{} captured as {} here", place_str, capture_kind_str)
@@ -2144,13 +2004,13 @@
fn construct_capture_info_string<'tcx>(
tcx: TyCtxt<'_>,
place: &Place<'tcx>,
- capture_info: &ty::CaptureInfo<'tcx>,
+ capture_info: &ty::CaptureInfo,
) -> String {
let place_str = construct_place_string(tcx, place);
let capture_kind_str = match capture_info.capture_kind {
- ty::UpvarCapture::ByValue(_) => "ByValue".into(),
- ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+ ty::UpvarCapture::ByValue => "ByValue".into(),
+ ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
};
format!("{} -> {}", place_str, capture_kind_str)
}
@@ -2233,25 +2093,16 @@
/// would've already handled `E1`, and have an existing capture_information for it.
/// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
/// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
-fn determine_capture_info<'tcx>(
- capture_info_a: ty::CaptureInfo<'tcx>,
- capture_info_b: ty::CaptureInfo<'tcx>,
-) -> ty::CaptureInfo<'tcx> {
+fn determine_capture_info(
+ capture_info_a: ty::CaptureInfo,
+ capture_info_b: ty::CaptureInfo,
+) -> ty::CaptureInfo {
// If the capture kind is equivalent then, we don't need to escalate and can compare the
// expressions.
let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
- (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => {
- // We don't need to worry about the spans being ignored here.
- //
- // The expr_id in capture_info corresponds to the span that is stored within
- // ByValue(span) and therefore it gets handled with priortizing based on
- // expressions below.
- true
- }
- (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
- ref_a.kind == ref_b.kind
- }
- (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false,
+ (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
+ (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
+ (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
};
if eq_capture_kind {
@@ -2263,10 +2114,10 @@
// We select the CaptureKind which ranks higher based the following priority order:
// ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
- (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
- (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
+ (ty::UpvarCapture::ByValue, _) => capture_info_a,
+ (_, ty::UpvarCapture::ByValue) => capture_info_b,
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
- match (ref_a.kind, ref_b.kind) {
+ match (ref_a, ref_b) {
// Take LHS:
(ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
| (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
@@ -2294,7 +2145,7 @@
/// contained `Deref` of `&mut`.
fn truncate_place_to_len_and_update_capture_kind<'tcx>(
place: &mut Place<'tcx>,
- curr_mode: &mut ty::UpvarCapture<'tcx>,
+ curr_mode: &mut ty::UpvarCapture,
len: usize,
) {
let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut));
@@ -2304,22 +2155,19 @@
// 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 }) => {
+ ty::UpvarCapture::ByRef(ty::BorrowKind::MutBorrow) => {
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,
- });
+ *curr_mode = ty::UpvarCapture::ByRef(ty::BorrowKind::UniqueImmBorrow);
break;
}
}
}
ty::UpvarCapture::ByRef(..) => {}
- ty::UpvarCapture::ByValue(..) => {}
+ ty::UpvarCapture::ByValue => {}
}
place.projections.truncate(len);
@@ -2390,8 +2238,8 @@
/// ```
fn truncate_capture_for_optimization<'tcx>(
mut place: Place<'tcx>,
- mut curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ mut curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
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
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 7c4f5d1..5575725 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -3,7 +3,7 @@
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -14,9 +14,10 @@
use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::outlives::obligations::TypeOutlives;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
-use rustc_middle::hir::map as hir_map;
+use rustc_infer::infer::region_constraints::GenericKind;
+use rustc_infer::infer::{self, RegionckMode};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_middle::hir::nested_filter;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
@@ -205,7 +206,7 @@
check_object_unsafe_self_trait_by_name(tcx, trait_item);
check_associated_item(tcx, trait_item.def_id, span, method_sig);
- let encl_trait_def_id = tcx.hir().get_parent_did(hir_id);
+ let encl_trait_def_id = tcx.hir().get_parent_item(hir_id);
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
let encl_trait_def_id = encl_trait.def_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
@@ -257,236 +258,186 @@
.emit();
}
}
-
- check_gat_where_clauses(tcx, trait_item, encl_trait_def_id);
}
/// Require that the user writes where clauses on GATs for the implicit
/// outlives bounds involving trait parameters in trait functions and
/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
///
-/// This trait will be our running example. We are currently WF checking the `Item` item...
-///
-/// ```rust
-/// trait LendingIterator {
-/// type Item<'me>; // <-- WF checking this trait item
-///
-/// fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
+/// We use the following trait as an example throughout this function:
+/// ```rust,ignore (this code fails due to this lint)
+/// trait IntoIter {
+/// type Iter<'a>: Iterator<Item = Self::Item<'a>>;
+/// type Item<'a>;
+/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
/// }
/// ```
-fn check_gat_where_clauses(
- tcx: TyCtxt<'_>,
- trait_item: &hir::TraitItem<'_>,
- encl_trait_def_id: DefId,
-) {
- let item = tcx.associated_item(trait_item.def_id);
- // If the current trait item isn't a type, it isn't a GAT
- if !matches!(item.kind, ty::AssocKind::Type) {
- return;
- }
- let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
- // If the current associated type doesn't have any (own) params, it's not a GAT
- // FIXME(jackh726): we can also warn in the more general case
- if generics.params.len() == 0 {
- return;
- }
- let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
- let mut clauses: Option<FxHashSet<ty::Predicate<'_>>> = None;
- // For every function in this trait...
- // In our example, this would be the `next` method
- for item in
- associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
- {
- // The clauses we that we would require from this function
- let mut function_clauses = FxHashSet::default();
+fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) {
+ // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
+ let mut required_bounds_by_item = FxHashMap::default();
- let id = hir::HirId::make_owner(item.def_id.expect_local());
- let param_env = tcx.param_env(item.def_id.expect_local());
-
- let sig = tcx.fn_sig(item.def_id);
- // Get the signature using placeholders. In our example, this would
- // convert the late-bound 'a into a free region.
- let sig = tcx.liberate_late_bound_regions(item.def_id, sig);
- // Collect the arguments that are given to this GAT in the return type
- // of the function signature. In our example, the GAT in the return
- // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
- let (regions, types) =
- GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output());
-
- // If both regions and types are empty, then this GAT isn't in the
- // return type, and we shouldn't try to do clause analysis
- // (particularly, doing so would end up with an empty set of clauses,
- // since the current method would require none, and we take the
- // intersection of requirements of all methods)
- if types.is_empty() && regions.is_empty() {
- continue;
- }
-
- // The types we can assume to be well-formed. In our example, this
- // would be &'a mut Self, from the first argument.
- let mut wf_tys = FxHashSet::default();
- wf_tys.extend(sig.inputs());
-
- // For each region argument (e.g., 'a in our example), check for a
- // relationship to the type arguments (e.g., Self). If there is an
- // outlives relationship (`Self: 'a`), then we want to ensure that is
- // reflected in a where clause on the GAT itself.
- for (region, region_idx) in ®ions {
- for (ty, ty_idx) in &types {
- // In our example, requires that Self: 'a
- if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
- debug!(?ty_idx, ?region_idx);
- debug!("required clause: {} must outlive {}", ty, region);
- // Translate into the generic parameters of the GAT. In
- // our example, the type was Self, which will also be
- // Self in the GAT.
- let ty_param = generics.param_at(*ty_idx, tcx);
- let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
- index: ty_param.index,
- name: ty_param.name,
- }));
- // Same for the region. In our example, 'a corresponds
- // to the 'me parameter.
- let region_param = generics.param_at(*region_idx, tcx);
- let region_param =
- tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: region_param.def_id,
- index: region_param.index,
- name: region_param.name,
- }));
- // The predicate we expect to see. (In our example,
- // `Self: 'me`.)
- let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
- ty_param,
- region_param,
- ));
- let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
- function_clauses.insert(clause);
- }
+ // Loop over all GATs together, because if this lint suggests adding a where-clause bound
+ // to one GAT, it might then require us to an additional bound on another GAT.
+ // In our `IntoIter` example, we discover a missing `Self: 'a` bound on `Iter<'a>`, which
+ // then in a second loop adds a `Self: 'a` bound to `Item` due to the relationship between
+ // those GATs.
+ loop {
+ let mut should_continue = false;
+ for gat_item in associated_items {
+ let gat_def_id = gat_item.id.def_id;
+ let gat_item = tcx.associated_item(gat_def_id);
+ // If this item is not an assoc ty, or has no substs, then it's not a GAT
+ if gat_item.kind != ty::AssocKind::Type {
+ continue;
}
- }
+ let gat_generics = tcx.generics_of(gat_def_id);
+ // FIXME(jackh726): we can also warn in the more general case
+ if gat_generics.params.is_empty() {
+ continue;
+ }
- // For each region argument (e.g., 'a in our example), also check for a
- // relationship to the other region arguments. If there is an
- // outlives relationship, then we want to ensure that is
- // reflected in a where clause on the GAT itself.
- for (region_a, region_a_idx) in ®ions {
- for (region_b, region_b_idx) in ®ions {
- if region_a == region_b {
+ // Gather the bounds with which all other items inside of this trait constrain the GAT.
+ // This is calculated by taking the intersection of the bounds that each item
+ // constrains the GAT with individually.
+ let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
+ for item in associated_items {
+ let item_def_id = item.id.def_id;
+ // Skip our own GAT, since it does not constrain itself at all.
+ if item_def_id == gat_def_id {
continue;
}
- if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
- debug!(?region_a_idx, ?region_b_idx);
- debug!("required clause: {} must outlive {}", region_a, region_b);
- // Translate into the generic parameters of the GAT.
- let region_a_param = generics.param_at(*region_a_idx, tcx);
- let region_a_param =
- tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: region_a_param.def_id,
- index: region_a_param.index,
- name: region_a_param.name,
- }));
- // Same for the region.
- let region_b_param = generics.param_at(*region_b_idx, tcx);
- let region_b_param =
- tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: region_b_param.def_id,
- index: region_b_param.index,
- name: region_b_param.name,
- }));
- // The predicate we expect to see.
- let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
- region_a_param,
- region_b_param,
- ));
- let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
- function_clauses.insert(clause);
+ let item_hir_id = item.id.hir_id();
+ let param_env = tcx.param_env(item_def_id);
+
+ let item_required_bounds = match item.kind {
+ // In our example, this corresponds to `into_iter` method
+ hir::AssocItemKind::Fn { .. } => {
+ // For methods, we check the function signature's return type for any GATs
+ // to constrain. In the `into_iter` case, we see that the return type
+ // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
+ let sig: ty::FnSig<'_> = tcx.liberate_late_bound_regions(
+ item_def_id.to_def_id(),
+ tcx.fn_sig(item_def_id),
+ );
+ gather_gat_bounds(
+ tcx,
+ param_env,
+ item_hir_id,
+ sig.output(),
+ // We also assume that all of the function signature's parameter types
+ // are well formed.
+ &sig.inputs().iter().copied().collect(),
+ gat_def_id,
+ gat_generics,
+ )
+ }
+ // In our example, this corresponds to the `Iter` and `Item` associated types
+ hir::AssocItemKind::Type => {
+ // If our associated item is a GAT with missing bounds, add them to
+ // the param-env here. This allows this GAT to propagate missing bounds
+ // to other GATs.
+ let param_env = augment_param_env(
+ tcx,
+ param_env,
+ required_bounds_by_item.get(&item_def_id),
+ );
+ gather_gat_bounds(
+ tcx,
+ param_env,
+ item_hir_id,
+ tcx.explicit_item_bounds(item_def_id)
+ .iter()
+ .copied()
+ .collect::<Vec<_>>(),
+ &FxHashSet::default(),
+ gat_def_id,
+ gat_generics,
+ )
+ }
+ hir::AssocItemKind::Const => None,
+ };
+
+ if let Some(item_required_bounds) = item_required_bounds {
+ // Take the intersection of the required bounds for this GAT, and
+ // the item_required_bounds which are the ones implied by just
+ // this item alone.
+ // This is why we use an Option<_>, since we need to distinguish
+ // the empty set of bounds from the _uninitialized_ set of bounds.
+ if let Some(new_required_bounds) = &mut new_required_bounds {
+ new_required_bounds.retain(|b| item_required_bounds.contains(b));
+ } else {
+ new_required_bounds = Some(item_required_bounds);
+ }
+ }
+ }
+
+ if let Some(new_required_bounds) = new_required_bounds {
+ let required_bounds = required_bounds_by_item.entry(gat_def_id).or_default();
+ if new_required_bounds.into_iter().any(|p| required_bounds.insert(p)) {
+ // Iterate until our required_bounds no longer change
+ // Since they changed here, we should continue the loop
+ should_continue = true;
}
}
}
-
- // Imagine we have:
- // ```
- // trait Foo {
- // type Bar<'me>;
- // fn gimme(&self) -> Self::Bar<'_>;
- // fn gimme_default(&self) -> Self::Bar<'static>;
- // }
- // ```
- // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
- // case, `'me` can be `static` from `gimme_default`)
- match clauses.as_mut() {
- Some(clauses) => {
- clauses.drain_filter(|p| !function_clauses.contains(p));
- }
- None => {
- clauses = Some(function_clauses);
- }
+ // We know that this loop will eventually halt, since we only set `should_continue` if the
+ // `required_bounds` for this item grows. Since we are not creating any new region or type
+ // variables, the set of all region and type bounds that we could ever insert are limited
+ // by the number of unique types and regions we observe in a given item.
+ if !should_continue {
+ break;
}
}
- // If there are any clauses that aren't provable, emit an error
- let clauses = clauses.unwrap_or_default();
- debug!(?clauses);
- if !clauses.is_empty() {
- let param_env = tcx.param_env(trait_item.def_id);
+ for (gat_def_id, required_bounds) in required_bounds_by_item {
+ let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
+ debug!(?required_bounds);
+ let param_env = tcx.param_env(gat_def_id);
+ let gat_hir = gat_item_hir.hir_id();
- let mut clauses: Vec<_> = clauses
+ let mut unsatisfied_bounds: Vec<_> = required_bounds
.into_iter()
.filter(|clause| match clause.kind().skip_binder() {
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
- !region_known_to_outlive(
- tcx,
- trait_item.hir_id(),
- param_env,
- &FxHashSet::default(),
- a,
- b,
- )
+ !region_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
- !ty_known_to_outlive(
- tcx,
- trait_item.hir_id(),
- param_env,
- &FxHashSet::default(),
- a,
- b,
- )
+ !ty_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
}
_ => bug!("Unexpected PredicateKind"),
})
- .map(|clause| format!("{}", clause))
+ .map(|clause| clause.to_string())
.collect();
// We sort so that order is predictable
- clauses.sort();
+ unsatisfied_bounds.sort();
- if !clauses.is_empty() {
- let plural = if clauses.len() > 1 { "s" } else { "" };
+ if !unsatisfied_bounds.is_empty() {
+ let plural = if unsatisfied_bounds.len() > 1 { "s" } else { "" };
let mut err = tcx.sess.struct_span_err(
- trait_item.span,
- &format!("missing required bound{} on `{}`", plural, trait_item.ident),
+ gat_item_hir.span,
+ &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
);
let suggestion = format!(
"{} {}",
- if !trait_item.generics.where_clause.predicates.is_empty() {
+ if !gat_item_hir.generics.where_clause.predicates.is_empty() {
","
} else {
" where"
},
- clauses.join(", "),
+ unsatisfied_bounds.join(", "),
);
err.span_suggestion(
- trait_item.generics.where_clause.tail_span_for_suggestion(),
+ gat_item_hir.generics.where_clause.tail_span_for_suggestion(),
&format!("add the required where clause{}", plural),
suggestion,
Applicability::MachineApplicable,
);
- let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" };
+ let bound =
+ if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" };
err.note(&format!(
"{} currently required to ensure that impls have maximum flexibility",
bound
@@ -502,7 +453,142 @@
}
}
-// FIXME(jackh726): refactor some of the shared logic between the two functions below
+/// Add a new set of predicates to the caller_bounds of an existing param_env.
+fn augment_param_env<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>,
+) -> ty::ParamEnv<'tcx> {
+ let Some(new_predicates) = new_predicates else {
+ return param_env;
+ };
+
+ if new_predicates.is_empty() {
+ return param_env;
+ }
+
+ let bounds =
+ tcx.mk_predicates(param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()));
+ // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
+ // i.e. traits::normalize_param_env_or_error
+ ty::ParamEnv::new(bounds, param_env.reveal(), param_env.constness())
+}
+
+/// We use the following trait as an example throughout this function.
+/// Specifically, let's assume that `to_check` here is the return type
+/// of `into_iter`, and the GAT we are checking this for is `Iter`.
+/// ```rust,ignore (this code fails due to this lint)
+/// trait IntoIter {
+/// type Iter<'a>: Iterator<Item = Self::Item<'a>>;
+/// type Item<'a>;
+/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
+/// }
+/// ```
+fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ item_hir: hir::HirId,
+ to_check: T,
+ wf_tys: &FxHashSet<Ty<'tcx>>,
+ gat_def_id: LocalDefId,
+ gat_generics: &'tcx ty::Generics,
+) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
+ // The bounds we that we would require from `to_check`
+ let mut bounds = FxHashSet::default();
+
+ let (regions, types) = GATSubstCollector::visit(tcx, gat_def_id.to_def_id(), to_check);
+
+ // If both regions and types are empty, then this GAT isn't in the
+ // set of types we are checking, and we shouldn't try to do clause analysis
+ // (particularly, doing so would end up with an empty set of clauses,
+ // since the current method would require none, and we take the
+ // intersection of requirements of all methods)
+ if types.is_empty() && regions.is_empty() {
+ return None;
+ }
+
+ for (region_a, region_a_idx) in ®ions {
+ // Ignore `'static` lifetimes for the purpose of this lint: it's
+ // because we know it outlives everything and so doesn't give meaninful
+ // clues
+ if let ty::ReStatic = **region_a {
+ continue;
+ }
+ // For each region argument (e.g., `'a` in our example), check for a
+ // relationship to the type arguments (e.g., `Self`). If there is an
+ // outlives relationship (`Self: 'a`), then we want to ensure that is
+ // reflected in a where clause on the GAT itself.
+ for (ty, ty_idx) in &types {
+ // In our example, requires that `Self: 'a`
+ if ty_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *ty, *region_a) {
+ debug!(?ty_idx, ?region_a_idx);
+ debug!("required clause: {} must outlive {}", ty, region_a);
+ // Translate into the generic parameters of the GAT. In
+ // our example, the type was `Self`, which will also be
+ // `Self` in the GAT.
+ let ty_param = gat_generics.param_at(*ty_idx, tcx);
+ let ty_param = tcx
+ .mk_ty(ty::Param(ty::ParamTy { index: ty_param.index, name: ty_param.name }));
+ // Same for the region. In our example, 'a corresponds
+ // to the 'me parameter.
+ let region_param = gat_generics.param_at(*region_a_idx, tcx);
+ let region_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_param.def_id,
+ index: region_param.index,
+ name: region_param.name,
+ }));
+ // The predicate we expect to see. (In our example,
+ // `Self: 'me`.)
+ let clause =
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param));
+ let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+ bounds.insert(clause);
+ }
+ }
+
+ // For each region argument (e.g., `'a` in our example), also check for a
+ // relationship to the other region arguments. If there is an outlives
+ // relationship, then we want to ensure that is reflected in the where clause
+ // on the GAT itself.
+ for (region_b, region_b_idx) in ®ions {
+ // Again, skip `'static` because it outlives everything. Also, we trivially
+ // know that a region outlives itself.
+ if ty::ReStatic == **region_b || region_a == region_b {
+ continue;
+ }
+ if region_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *region_a, *region_b) {
+ debug!(?region_a_idx, ?region_b_idx);
+ debug!("required clause: {} must outlive {}", region_a, region_b);
+ // Translate into the generic parameters of the GAT.
+ let region_a_param = gat_generics.param_at(*region_a_idx, tcx);
+ let region_a_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_a_param.def_id,
+ index: region_a_param.index,
+ name: region_a_param.name,
+ }));
+ // Same for the region.
+ let region_b_param = gat_generics.param_at(*region_b_idx, tcx);
+ let region_b_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_b_param.def_id,
+ index: region_b_param.index,
+ name: region_b_param.name,
+ }));
+ // The predicate we expect to see.
+ let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+ region_a_param,
+ region_b_param,
+ ));
+ let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+ bounds.insert(clause);
+ }
+ }
+ }
+
+ Some(bounds)
+}
/// Given a known `param_env` and a set of well formed types, can we prove that
/// `ty` outlives `region`.
@@ -514,6 +600,50 @@
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
) -> bool {
+ resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
+ let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
+ let outlives = &mut TypeOutlives::new(
+ infcx,
+ tcx,
+ region_bound_pairs,
+ Some(infcx.tcx.lifetimes.re_root_empty),
+ param_env,
+ );
+ outlives.type_must_outlive(origin, ty, region);
+ })
+}
+
+/// Given a known `param_env` and a set of well formed types, can we prove that
+/// `region_a` outlives `region_b`
+fn region_known_to_outlive<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ wf_tys: &FxHashSet<Ty<'tcx>>,
+ region_a: ty::Region<'tcx>,
+ region_b: ty::Region<'tcx>,
+) -> bool {
+ resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| {
+ use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
+ let origin = infer::RelateRegionParamBound(DUMMY_SP);
+ // `region_a: region_b` -> `region_b <= region_a`
+ infcx.push_sub_region_constraint(origin, region_b, region_a);
+ })
+}
+
+/// Given a known `param_env` and a set of well formed types, set up an
+/// `InferCtxt`, call the passed function (to e.g. set up region constraints
+/// to be tested), then resolve region and return errors
+fn resolve_regions_with_wf_tys<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ wf_tys: &FxHashSet<Ty<'tcx>>,
+ add_constraints: impl for<'a> FnOnce(
+ &'a InferCtxt<'a, 'tcx>,
+ &'a Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
+ ),
+) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
// region constraints get added and solved there and we need to test each
// call individually.
@@ -523,63 +653,7 @@
outlives_environment.save_implied_bounds(id);
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
- let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
-
- let sup_type = ty;
- let sub_region = region;
-
- let origin = SubregionOrigin::from_obligation_cause(&cause, || {
- infer::RelateParamBound(cause.span, sup_type, None)
- });
-
- let outlives = &mut TypeOutlives::new(
- &infcx,
- tcx,
- ®ion_bound_pairs,
- Some(infcx.tcx.lifetimes.re_root_empty),
- param_env,
- );
- outlives.type_must_outlive(origin, sup_type, sub_region);
-
- let errors = infcx.resolve_regions(
- id.expect_owner().to_def_id(),
- &outlives_environment,
- RegionckMode::default(),
- );
-
- debug!(?errors, "errors");
-
- // If we were able to prove that the type outlives the region without
- // an error, it must be because of the implied or explicit bounds...
- errors.is_empty()
- })
-}
-
-fn region_known_to_outlive<'tcx>(
- tcx: TyCtxt<'tcx>,
- id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
- region_a: ty::Region<'tcx>,
- region_b: ty::Region<'tcx>,
-) -> bool {
- // Unfortunately, we have to use a new `InferCtxt` each call, because
- // region constraints get added and solved there and we need to test each
- // call individually.
- tcx.infer_ctxt().enter(|infcx| {
- let mut outlives_environment = OutlivesEnvironment::new(param_env);
- outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
- outlives_environment.save_implied_bounds(id);
-
- let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
-
- let origin = SubregionOrigin::from_obligation_cause(&cause, || {
- infer::RelateRegionParamBound(cause.span)
- });
-
- use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
- // `region_a: region_b` -> `region_b <= region_a`
- (&infcx).push_sub_region_constraint(origin, region_b, region_a);
+ add_constraints(&infcx, region_bound_pairs);
let errors = infcx.resolve_regions(
id.expect_owner().to_def_id(),
@@ -628,6 +702,13 @@
impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
type BreakTy = !;
+ fn visit_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ self.tcx.liberate_late_bound_regions(self.gat, t.clone()).visit_with(self)
+ }
+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
ty::Projection(p) if p.item_def_id == self.gat => {
@@ -647,10 +728,6 @@
}
t.super_visit_with(self)
}
-
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
}
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@@ -666,13 +743,14 @@
/// Detect when an object unsafe trait is referring to itself in one of its associated items.
/// When this is done, suggest using `Self` instead.
fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
- let (trait_name, trait_def_id) = match tcx.hir().get(tcx.hir().get_parent_item(item.hir_id())) {
- hir::Node::Item(item) => match item.kind {
- hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+ let (trait_name, trait_def_id) =
+ match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id())) {
+ hir::Node::Item(item) => match item.kind {
+ hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+ _ => return,
+ },
_ => return,
- },
- _ => return,
- };
+ };
let mut trait_should_be_self = vec![];
match &item.kind {
hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
@@ -784,9 +862,7 @@
}
};
- if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
- .is_some()
- {
+ if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
// We use the same error code in both branches, because this is really the same
// issue: we just special-case the message for type parameters to make it
// clearer.
@@ -860,7 +936,7 @@
let hir_sig = sig_if_method.expect("bad signature for method");
check_fn_or_method(
fcx,
- item.ident.span,
+ item.ident(fcx.tcx).span,
sig,
hir_sig.decl,
item.def_id,
@@ -1023,6 +1099,11 @@
FxHashSet::default()
});
+
+ // Only check traits, don't check trait aliases
+ if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind {
+ check_gat_where_clauses(tcx, items);
+ }
}
/// Checks all associated type defaults of trait `trait_def_id`.
@@ -1197,7 +1278,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.definitely_needs_subst(tcx) {
+ if !ty.needs_subst() {
fcx.register_wf_obligation(
ty.into(),
tcx.def_span(param.def_id),
@@ -1213,7 +1294,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.definitely_needs_subst(tcx) {
+ if !default_ct.needs_subst() {
fcx.register_wf_obligation(
default_ct.into(),
tcx.def_span(param.def_id),
@@ -1247,7 +1328,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.definitely_needs_subst(tcx) {
+ if !default_ty.needs_subst() {
// ... then substitute it with the default.
return default_ty.into();
}
@@ -1260,7 +1341,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.definitely_needs_subst(tcx) {
+ if !default_ct.needs_subst() {
// ... then substitute it with the default.
return default_ct.into();
}
@@ -1276,15 +1357,12 @@
.predicates
.iter()
.flat_map(|&(pred, sp)| {
- struct CountParams<'tcx> {
- tcx: TyCtxt<'tcx>,
+ #[derive(Default)]
+ struct CountParams {
params: FxHashSet<u32>,
}
- impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> {
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
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() {
@@ -1297,19 +1375,19 @@
ControlFlow::BREAK
}
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::ConstKind::Param(param) = c.val {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ConstKind::Param(param) = c.val() {
self.params.insert(param.index);
}
c.super_visit_with(self)
}
}
- let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() };
+ let mut param_count = CountParams::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.definitely_has_param_types_or_consts(tcx)
+ if substituted_pred.has_param_types_or_consts()
|| param_count.params.len() > 1
|| has_region
{
@@ -1697,7 +1775,7 @@
for obligation in implied_obligations {
let pred = obligation.predicate;
// Match the existing behavior.
- if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() {
+ if pred.is_global() && !pred.has_late_bound_regions() {
let pred = fcx.normalize_associated_types_in(span, pred);
let hir_node = fcx.tcx.hir().find(id);
@@ -1759,10 +1837,10 @@
}
impl<'tcx> Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
- type Map = hir_map::Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
- hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
#[instrument(skip(self, i), level = "debug")]
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index fdc8b6b..3843e7e 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -8,7 +8,7 @@
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::Place as HirPlace;
@@ -43,7 +43,7 @@
let item_def_id = self.tcx.hir().local_def_id(item_id);
// This attribute causes us to dump some writeback information
- // in the form of errors, which is uSymbol for unit tests.
+ // in the form of errors, which is used for unit tests.
let rustc_dump_user_substs =
self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs);
@@ -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(self.tcx()));
+ assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
self.typeck_results.node_types_mut().insert(hir_id, ty);
}
@@ -253,12 +253,6 @@
// traffic in node-ids or update typeck results in the type context etc.
impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
self.fix_scalar_builtin_expr(e);
self.fix_index_builtin_expr(e);
@@ -726,7 +720,7 @@
}
}
- fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) {
+ fn report_const_error(&self, c: ty::Const<'tcx>) {
if !self.tcx.sess.has_errors() {
self.infcx
.emit_inference_failure_err(
@@ -750,14 +744,14 @@
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+ if ty.has_type_flags(ty::TypeFlags::HAS_FREE_REGIONS) {
ty.super_fold_with(self)
} else {
ty
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
+ if r.is_late_bound() { r } else { self.tcx.lifetimes.re_erased }
}
}
@@ -789,14 +783,14 @@
self.tcx.lifetimes.re_erased
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match self.infcx.fully_resolve(ct) {
Ok(ct) => self.infcx.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
self.report_const_error(ct);
self.replaced_with_error = true;
- self.tcx().const_error(ct.ty)
+ self.tcx().const_error(ct.ty())
}
}
}
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index d5494c5..401ba18 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -147,7 +147,7 @@
use ty::TyKind::*;
match (source.kind(), target.kind()) {
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
- if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => {}
+ if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
(&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
(&Adt(def_a, substs_a), &Adt(def_b, substs_b))
if def_a.is_struct() && def_b.is_struct() =>
@@ -199,7 +199,7 @@
)
.note(&format!(
"extra field `{}` of type `{}` is not allowed",
- field.ident, ty_a,
+ field.name, ty_a,
))
.emit();
@@ -235,7 +235,7 @@
.map(|field| {
format!(
"`{}` (`{}` to `{}`)",
- field.ident,
+ field.name,
field.ty(tcx, substs_a),
field.ty(tcx, substs_b),
)
@@ -479,7 +479,7 @@
diff_fields
.iter()
.map(|&(i, a, b)| {
- format!("`{}` (`{}` to `{}`)", fields[i].ident, a, b)
+ format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
})
.collect::<Vec<_>>()
.join(", ")
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index 59f211b..cf71e0f 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -4,6 +4,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_index::vec::IndexVec;
+use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Symbol;
use rustc_trait_selection::traits::{self, SkipLeakCheck};
@@ -36,7 +37,7 @@
for item1 in impl_items1.in_definition_order() {
let collision = impl_items2
- .filter_by_name_unhygienic(item1.ident.name)
+ .filter_by_name_unhygienic(item1.name)
.any(|item2| self.compare_hygienically(item1, item2));
if collision {
@@ -50,7 +51,8 @@
fn compare_hygienically(&self, item1: &ty::AssocItem, item2: &ty::AssocItem) -> bool {
// Symbols and namespace match, compare hygienically.
item1.kind.namespace() == item2.kind.namespace()
- && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0()
+ && item1.ident(self.tcx).normalize_to_macros_2_0()
+ == item2.ident(self.tcx).normalize_to_macros_2_0()
}
fn check_for_common_items_in_impls(
@@ -64,11 +66,11 @@
for item1 in impl_items1.in_definition_order() {
let collision = impl_items2
- .filter_by_name_unhygienic(item1.ident.name)
+ .filter_by_name_unhygienic(item1.name)
.find(|item2| self.compare_hygienically(item1, item2));
if let Some(item2) = collision {
- let name = item1.ident.normalize_to_macros_2_0();
+ let name = item1.ident(self.tcx).normalize_to_macros_2_0();
let mut err = struct_span_err!(
self.tcx.sess,
self.tcx.span_of_impl(item1.def_id).unwrap(),
@@ -98,7 +100,12 @@
}
}
- fn check_for_overlapping_inherent_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId) {
+ fn check_for_overlapping_inherent_impls(
+ &self,
+ overlap_mode: OverlapMode,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ ) {
traits::overlapping_impls(
self.tcx,
impl1_def_id,
@@ -106,6 +113,7 @@
// We go ahead and just skip the leak check for
// inherent impls without warning.
SkipLeakCheck::Yes,
+ overlap_mode,
|overlap| {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
false
@@ -130,6 +138,8 @@
return;
}
+ let overlap_mode = OverlapMode::get(self.tcx, item.def_id.to_def_id());
+
let impls_items = impls
.iter()
.map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
@@ -144,6 +154,7 @@
for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
if self.impls_have_common_items(impl_items1, impl_items2) {
self.check_for_overlapping_inherent_impls(
+ overlap_mode,
impl1_def_id,
impl2_def_id,
);
@@ -181,11 +192,11 @@
let mut ids = impl_items
.in_definition_order()
.filter_map(|item| {
- let entry = connected_region_ids.entry(item.ident.name);
+ let entry = connected_region_ids.entry(item.name);
if let Entry::Occupied(e) = &entry {
Some(*e.get())
} else {
- idents_to_add.push(item.ident.name);
+ idents_to_add.push(item.name);
None
}
})
@@ -287,6 +298,7 @@
let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
if self.impls_have_common_items(impl_items1, impl_items2) {
self.check_for_overlapping_inherent_impls(
+ overlap_mode,
impl1_def_id,
impl2_def_id,
);
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 377ebf1..055818f 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -121,28 +121,6 @@
return;
}
}
-
- let trait_name = if did == li.fn_trait() {
- "Fn"
- } else if did == li.fn_mut_trait() {
- "FnMut"
- } else if did == li.fn_once_trait() {
- "FnOnce"
- } else {
- return; // everything OK
- };
-
- let span = impl_header_span(tcx, impl_def_id);
- struct_span_err!(
- tcx.sess,
- span,
- E0183,
- "manual implementations of `{}` are experimental",
- trait_name
- )
- .span_label(span, format!("manual implementations of `{}` are experimental", trait_name))
- .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
- .emit();
}
/// We allow impls of marker traits to overlap, so they can't override impls
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index e954b4c..20f42b1 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -1,24 +1,33 @@
//! Orphan checker: every impl either implements a trait defined in this
//! crate or pertains to a type defined in this crate.
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
+use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::LocalDefId;
+use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
+use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_session::lint;
+use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;
use rustc_trait_selection::traits;
+use std::ops::ControlFlow;
pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] {
let mut errors = Vec::new();
- for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) {
+ for (&trait_def_id, impls_of_trait) in tcx.all_local_trait_impls(()) {
for &impl_of_trait in impls_of_trait {
match orphan_check_impl(tcx, impl_of_trait) {
Ok(()) => {}
Err(ErrorReported) => errors.push(impl_of_trait),
}
}
+
+ if tcx.trait_is_auto(trait_def_id) {
+ lint_auto_trait_impls(tcx, trait_def_id, impls_of_trait);
+ }
}
tcx.arena.alloc_slice(&errors)
}
@@ -265,3 +274,196 @@
Err(ErrorReported)
}
+
+#[derive(Default)]
+struct AreUniqueParamsVisitor {
+ seen: GrowableBitSet<u32>,
+}
+
+#[derive(Copy, Clone)]
+enum NotUniqueParam<'tcx> {
+ DuplicateParam(GenericArg<'tcx>),
+ NotParam(GenericArg<'tcx>),
+}
+
+impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor {
+ type BreakTy = NotUniqueParam<'tcx>;
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ ty::Param(p) => {
+ if self.seen.insert(p.index) {
+ ControlFlow::CONTINUE
+ } else {
+ ControlFlow::Break(NotUniqueParam::DuplicateParam(t.into()))
+ }
+ }
+ _ => ControlFlow::Break(NotUniqueParam::NotParam(t.into())),
+ }
+ }
+ fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // We don't drop candidates during candidate assembly because of region
+ // constraints, so the behavior for impls only constrained by regions
+ // will not change.
+ ControlFlow::CONTINUE
+ }
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match c.val() {
+ ty::ConstKind::Param(p) => {
+ if self.seen.insert(p.index) {
+ ControlFlow::CONTINUE
+ } else {
+ ControlFlow::Break(NotUniqueParam::DuplicateParam(c.into()))
+ }
+ }
+ _ => ControlFlow::Break(NotUniqueParam::NotParam(c.into())),
+ }
+ }
+}
+
+/// Lint impls of auto traits if they are likely to have
+/// unsound or surprising effects on auto impls.
+fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDefId]) {
+ let mut non_covering_impls = Vec::new();
+ for &impl_def_id in impls {
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ if trait_ref.references_error() {
+ return;
+ }
+
+ if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive {
+ return;
+ }
+
+ assert_eq!(trait_ref.substs.len(), 1);
+ let self_ty = trait_ref.self_ty();
+ let (self_type_did, substs) = match self_ty.kind() {
+ ty::Adt(def, substs) => (def.did, substs),
+ _ => {
+ // FIXME: should also lint for stuff like `&i32` but
+ // considering that auto traits are unstable, that
+ // isn't too important for now as this only affects
+ // crates using `nightly`, and std.
+ continue;
+ }
+ };
+
+ // Impls which completely cover a given root type are fine as they
+ // disable auto impls entirely. So only lint if the substs
+ // are not a permutation of the identity substs.
+ match substs.visit_with(&mut AreUniqueParamsVisitor::default()) {
+ ControlFlow::Continue(()) => {} // ok
+ ControlFlow::Break(arg) => {
+ // Ideally:
+ //
+ // - compute the requirements for the auto impl candidate
+ // - check whether these are implied by the non covering impls
+ // - if not, emit the lint
+ //
+ // What we do here is a bit simpler:
+ //
+ // - badly check if an auto impl candidate definitely does not apply
+ // for the given simplified type
+ // - if so, do not lint
+ if fast_reject_auto_impl(tcx, trait_def_id, self_ty) {
+ // ok
+ } else {
+ non_covering_impls.push((impl_def_id, self_type_did, arg));
+ }
+ }
+ }
+ }
+
+ for &(impl_def_id, self_type_did, arg) in &non_covering_impls {
+ tcx.struct_span_lint_hir(
+ lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
+ tcx.hir().local_def_id_to_hir_id(impl_def_id),
+ tcx.def_span(impl_def_id),
+ |err| {
+ let mut err = err.build(&format!(
+ "cross-crate traits with a default impl, like `{}`, \
+ should not be specialized",
+ tcx.def_path_str(trait_def_id),
+ ));
+ let item_span = tcx.def_span(self_type_did);
+ let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
+ err.span_note(
+ item_span,
+ &format!(
+ "try using the same sequence of generic parameters as the {} definition",
+ self_descr,
+ ),
+ );
+ match arg {
+ NotUniqueParam::DuplicateParam(arg) => {
+ err.note(&format!("`{}` is mentioned multiple times", arg));
+ }
+ NotUniqueParam::NotParam(arg) => {
+ err.note(&format!("`{}` is not a generic parameter", arg));
+ }
+ }
+ err.emit();
+ },
+ );
+ }
+}
+
+fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool {
+ struct DisableAutoTraitVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ self_ty_root: Ty<'tcx>,
+ seen: FxHashSet<DefId>,
+ }
+
+ impl<'tcx> TypeVisitor<'tcx> for DisableAutoTraitVisitor<'tcx> {
+ type BreakTy = ();
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let tcx = self.tcx;
+ if t != self.self_ty_root {
+ for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
+ match tcx.impl_polarity(impl_def_id) {
+ ImplPolarity::Negative => return ControlFlow::BREAK,
+ ImplPolarity::Reservation => {}
+ // FIXME(@lcnr): That's probably not good enough, idk
+ //
+ // We might just want to take the rustdoc code and somehow avoid
+ // explicit impls for `Self`.
+ ImplPolarity::Positive => return ControlFlow::CONTINUE,
+ }
+ }
+ }
+
+ match t.kind() {
+ ty::Adt(def, substs) if def.is_phantom_data() => substs.super_visit_with(self),
+ ty::Adt(def, substs) => {
+ // @lcnr: This is the only place where cycles can happen. We avoid this
+ // by only visiting each `DefId` once.
+ //
+ // This will be is incorrect in subtle cases, but I don't care :)
+ if self.seen.insert(def.did) {
+ for ty in def.all_fields().map(|field| field.ty(tcx, substs)) {
+ ty.visit_with(self)?;
+ }
+ }
+
+ ControlFlow::CONTINUE
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
+ }
+
+ let self_ty_root = match self_ty.kind() {
+ ty::Adt(def, _) => tcx.mk_adt(def, InternalSubsts::identity_for_item(tcx, def.did)),
+ _ => unimplemented!("unexpected self ty {:?}", self_ty),
+ };
+
+ self_ty_root
+ .visit_with(&mut DisableAutoTraitVisitor {
+ tcx,
+ self_ty_root,
+ trait_def_id,
+ seen: FxHashSet::default(),
+ })
+ .is_break()
+}
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 41c8a37..18f54eb 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1,3 +1,4 @@
+// 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
@@ -21,7 +22,6 @@
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;
@@ -29,11 +29,11 @@
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::weak_lang_items;
use rustc_hir::{GenericParamKind, HirId, Node};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
@@ -68,7 +68,6 @@
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,
@@ -114,14 +113,9 @@
///////////////////////////////////////////////////////////////////////////
#[derive(Default)]
-crate struct PlaceholderHirTyCollector(crate Vec<Span>);
+crate struct HirPlaceholderCollector(crate Vec<Span>);
-impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
+impl<'v> Visitor<'v> for HirPlaceholderCollector {
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
if let hir::TyKind::Infer = t.kind {
self.0.push(t.span);
@@ -138,6 +132,12 @@
_ => {}
}
}
+ fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
+ if let &hir::ArrayLen::Infer(_, span) = length {
+ self.0.push(span);
+ }
+ intravisit::walk_array_len(self, length)
+ }
}
struct CollectItemTypesVisitor<'tcx> {
@@ -182,7 +182,7 @@
sugg.push((span, format!(", {}", type_name)));
}
- let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
+ let mut err = bad_placeholder(tcx, placeholder_types, kind);
// Suggest, but only if it is not a function in const or static
if suggest {
@@ -240,7 +240,7 @@
_ => return,
};
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(item);
placeholder_type_error(
@@ -255,10 +255,10 @@
}
impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::OnlyBodies;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -318,7 +318,6 @@
fn bad_placeholder<'tcx>(
tcx: TyCtxt<'tcx>,
- placeholder_kind: &'static str,
mut spans: Vec<Span>,
kind: &'static str,
) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -329,8 +328,7 @@
tcx.sess,
spans.clone(),
E0121,
- "the {} placeholder `_` is not allowed within types on item signatures for {}",
- placeholder_kind,
+ "the placeholder `_` is not allowed within types on item signatures for {}",
kind
);
for span in spans {
@@ -388,22 +386,15 @@
}
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
- self.tcx().ty_error_with_message(span, "bad_placeholder_type")
+ self.tcx().ty_error_with_message(span, "bad placeholder type")
}
- fn ct_infer(
- &self,
- ty: Ty<'tcx>,
- _: Option<&ty::GenericParamDef>,
- span: Span,
- ) -> &'tcx Const<'tcx> {
- bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
- // Typeck doesn't expect erased regions to be returned from `type_of`.
- let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
+ fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
+ let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match *r {
ty::ReErased => self.tcx.lifetimes.re_static,
_ => r,
});
- self.tcx().const_error(ty)
+ self.tcx().const_error_with_message(ty, span, "bad placeholder constant")
}
fn projected_ty_from_poly_trait_ref(
@@ -436,7 +427,7 @@
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
let item =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(self.hir_id()));
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
@@ -570,13 +561,12 @@
let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
let param_owner = tcx.hir().ty_param_owner(param_id);
- let param_owner_def_id = tcx.hir().local_def_id(param_owner);
- let generics = tcx.generics_of(param_owner_def_id);
+ let generics = tcx.generics_of(param_owner);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(param_id));
// Don't look for bounds where the type parameter isn't in scope.
- let parent = if item_def_id == param_owner_def_id.to_def_id() {
+ let parent = if item_def_id == param_owner.to_def_id() {
None
} else {
tcx.generics_of(item_def_id).parent
@@ -667,7 +657,11 @@
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Type { .. } if param.hir_id == param_id => Some(¶m.bounds),
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
+ if param.hir_id == param_id =>
+ {
+ Some(¶m.bounds)
+ }
_ => None,
})
.flat_map(|bounds| bounds.iter())
@@ -747,7 +741,7 @@
match item.kind {
hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
hir::ForeignItemKind::Static(..) => {
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
placeholder_type_error(
tcx,
@@ -830,7 +824,7 @@
hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => {
// (#75889): Account for `const C: dyn Fn() -> _ = "";`
if let hir::TyKind::TraitObject(..) = ty.kind {
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(it);
placeholder_type_error(
tcx,
@@ -866,7 +860,7 @@
hir::TraitItemKind::Const(..) => {
tcx.ensure().type_of(trait_item_id.def_id);
// Account for `const C: _;`.
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant");
}
@@ -875,7 +869,7 @@
tcx.ensure().item_bounds(trait_item_id.def_id);
tcx.ensure().type_of(trait_item_id.def_id);
// Account for `type T = _;`.
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
}
@@ -884,7 +878,7 @@
tcx.ensure().item_bounds(trait_item_id.def_id);
// #74612: Visit and try to find bad placeholders
// even if there is no concrete type.
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
@@ -906,7 +900,7 @@
}
hir::ImplItemKind::TyAlias(_) => {
// Account for `type T = _;`
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);
placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
@@ -995,7 +989,7 @@
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
}
- ty::FieldDef { did: fid.to_def_id(), ident: f.ident, vis: tcx.visibility(fid) }
+ ty::FieldDef { did: fid.to_def_id(), name: f.ident.name, vis: tcx.visibility(fid) }
})
.collect();
let recovered = match def {
@@ -1003,7 +997,7 @@
_ => false,
};
ty::VariantDef::new(
- ident,
+ ident.name,
variant_did.map(LocalDefId::to_def_id),
ctor_did.map(LocalDefId::to_def_id),
discr,
@@ -1198,9 +1192,11 @@
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
let item = tcx.hir().expect_item(def_id.expect_local());
- let (is_auto, unsafety) = match item.kind {
- hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
- hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal),
+ let (is_auto, unsafety, items) = match item.kind {
+ hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
+ (is_auto == hir::IsAuto::Yes, unsafety, items)
+ }
+ hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
};
@@ -1227,6 +1223,103 @@
ty::trait_def::TraitSpecializationKind::None
};
let def_path_hash = tcx.def_path_hash(def_id);
+
+ let must_implement_one_of = tcx
+ .get_attrs(def_id)
+ .iter()
+ .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+ // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
+ // and that they are all identifiers
+ .and_then(|attr| match attr.meta_item_list() {
+ Some(items) if items.len() < 2 => {
+ tcx.sess
+ .struct_span_err(
+ attr.span,
+ "the `#[rustc_must_implement_one_of]` attribute must be \
+ used with at least 2 args",
+ )
+ .emit();
+
+ None
+ }
+ Some(items) => items
+ .into_iter()
+ .map(|item| item.ident().ok_or(item.span()))
+ .collect::<Result<Box<[_]>, _>>()
+ .map_err(|span| {
+ tcx.sess
+ .struct_span_err(span, "must be a name of an associated function")
+ .emit();
+ })
+ .ok()
+ .zip(Some(attr.span)),
+ // Error is reported by `rustc_attr!`
+ None => None,
+ })
+ // Check that all arguments of `#[rustc_must_implement_one_of]` reference
+ // functions in the trait with default implementations
+ .and_then(|(list, attr_span)| {
+ let errors = list.iter().filter_map(|ident| {
+ let item = items.iter().find(|item| item.ident == *ident);
+
+ match item {
+ Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
+ if !item.defaultness.has_value() {
+ tcx.sess
+ .struct_span_err(
+ item.span,
+ "This function doesn't have a default implementation",
+ )
+ .span_note(attr_span, "required by this annotation")
+ .emit();
+
+ return Some(());
+ }
+
+ return None;
+ }
+ Some(item) => tcx
+ .sess
+ .struct_span_err(item.span, "Not a function")
+ .span_note(attr_span, "required by this annotation")
+ .note(
+ "All `#[rustc_must_implement_one_of]` arguments \
+ must be associated function names",
+ )
+ .emit(),
+ None => tcx
+ .sess
+ .struct_span_err(ident.span, "Function not found in this trait")
+ .emit(),
+ }
+
+ Some(())
+ });
+
+ (errors.count() == 0).then_some(list)
+ })
+ // Check for duplicates
+ .and_then(|list| {
+ let mut set: FxHashMap<Symbol, Span> = FxHashMap::default();
+ let mut no_dups = true;
+
+ for ident in &*list {
+ if let Some(dup) = set.insert(ident.name, ident.span) {
+ tcx.sess
+ .struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
+ .note(
+ "All `#[rustc_must_implement_one_of]` arguments \
+ must be unique",
+ )
+ .emit();
+
+ no_dups = false;
+ }
+ }
+
+ no_dups.then_some(list)
+ });
+
ty::TraitDef::new(
def_id,
unsafety,
@@ -1236,6 +1329,7 @@
skip_array_during_method_dispatch,
spec_kind,
def_path_hash,
+ must_implement_one_of,
)
}
@@ -1247,12 +1341,6 @@
}
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
if self.has_late_bound_regions.is_some() {
return;
@@ -1360,12 +1448,6 @@
}
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
if let GenericParamKind::Const { ty, default: _ } = p.kind {
let prev = self.in_param_ty;
@@ -1397,13 +1479,12 @@
| Node::Ctor(..)
| Node::Field(_) => {
let parent_id = tcx.hir().get_parent_item(hir_id);
- Some(tcx.hir().local_def_id(parent_id).to_def_id())
+ Some(parent_id.to_def_id())
}
// FIXME(#43408) always enable this once `lazy_normalization` is
// stable enough and does not need a feature gate anymore.
Node::AnonConst(_) => {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- let parent_def_id = tcx.hir().local_def_id(parent_id);
+ let parent_def_id = tcx.hir().get_parent_item(hir_id);
let mut in_param_ty = false;
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
@@ -1513,11 +1594,11 @@
}) => Some(fn_def_id.to_def_id()),
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
let parent_id = tcx.hir().get_parent_item(hir_id);
- assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID);
+ assert_ne!(parent_id, CRATE_DEF_ID);
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
// Opaque types are always nested within another item, and
// inherit the generics of the item.
- Some(tcx.hir().local_def_id(parent_id).to_def_id())
+ Some(parent_id.to_def_id())
}
_ => None,
},
@@ -1610,7 +1691,7 @@
kind: ty::GenericParamDefKind::Lifetime,
}));
- let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id);
+ let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner);
// Now create the real type and const parameters.
let type_start = own_start - has_self as u32 + params.len() as u32;
@@ -1739,10 +1820,14 @@
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
/// use inference to provide suggestions for the appropriate type if possible.
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
+ debug!(?ty);
use hir::TyKind::*;
match &ty.kind {
Infer => true,
- Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
+ Slice(ty) => is_suggestable_infer_ty(ty),
+ Array(ty, length) => {
+ is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
+ }
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
@@ -1788,15 +1873,15 @@
Some(ty) => {
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
// Typeck doesn't expect erased regions to be returned from `type_of`.
- let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match r {
+ let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r {
ty::ReErased => tcx.lifetimes.re_static,
_ => r,
});
let fn_sig = ty::Binder::dummy(fn_sig);
- let mut visitor = PlaceholderHirTyCollector::default();
+ let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(ty);
- let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
+ let mut diag = bad_placeholder(tcx, visitor.0, "return type");
let ret_ty = fn_sig.skip_binder().output();
if !ret_ty.references_error() {
if !ret_ty.is_closure() {
@@ -1862,7 +1947,7 @@
}
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
- let ty = tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id());
+ let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id));
let inputs =
data.fields().iter().map(|f| tcx.type_of(tcx.hir().local_def_id(f.hir_id)));
ty::Binder::dummy(tcx.mk_fn_sig(
@@ -2280,7 +2365,7 @@
tcx,
&mut predicates,
trait_ref,
- &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref),
+ &mut cgp::parameters_for_impl(self_ty, trait_ref),
);
}
@@ -2302,16 +2387,10 @@
}
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
- type Map = Map<'tcx>;
-
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
- }
-
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
let def_id = self.tcx.hir().local_def_id(c.hir_id);
let ct = ty::Const::from_anon_const(self.tcx, def_id);
- if let ty::ConstKind::Unevaluated(uv) = ct.val {
+ if let ty::ConstKind::Unevaluated(uv) = ct.val() {
assert_eq!(uv.promoted, None);
let span = self.tcx.hir().span(c.hir_id);
self.preds.insert((
@@ -2432,8 +2511,7 @@
// 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();
+ let item_def_id = tcx.hir().get_parent_item(hir_id);
// In the above code example we would be calling `explicit_predicates_of(Foo)` here
return tcx.explicit_predicates_of(item_def_id);
}
@@ -2455,7 +2533,7 @@
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
- bounds.predicates(astconv.tcx(), param_ty)
+ bounds.predicates(astconv.tcx(), param_ty).collect()
}
fn compute_sig_of_foreign_fn_decl<'tcx>(
@@ -2509,7 +2587,7 @@
}
};
for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
- check(input, ty)
+ check(input, *ty)
}
if let hir::FnRetTy::Return(ref ty) = decl.output {
check(ty, fty.output().skip_binder())
@@ -2696,6 +2774,13 @@
}
}
+ // The panic_no_unwind function called by TerminatorKind::Abort will never
+ // unwind. If the panic handler that it invokes unwind then it will simply
+ // call the panic handler again.
+ if Some(id) == tcx.lang_items().panic_no_unwind() {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ }
+
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
let mut inline_span = None;
@@ -2767,7 +2852,42 @@
} else if attr.has_name(sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} else if attr.has_name(sym::used) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+ let inner = attr.meta_item_list();
+ match inner.as_deref() {
+ Some([item]) if item.has_name(sym::linker) => {
+ if !tcx.features().used_with_arg {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::used_with_arg,
+ attr.span,
+ "`#[used(linker)]` is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
+ }
+ Some([item]) if item.has_name(sym::compiler) => {
+ if !tcx.features().used_with_arg {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::used_with_arg,
+ attr.span,
+ "`#[used(compiler)]` is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+ }
+ Some(_) => {
+ tcx.sess
+ .struct_span_err(
+ attr.span,
+ "expected `used`, `used(compiler)` or `used(linker)`",
+ )
+ .emit();
+ }
+ None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
+ }
} else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
struct_span_err!(
@@ -2889,6 +3009,8 @@
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
} else if item.has_name(sym::memory) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
+ } else if item.has_name(sym::memtag) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
} else if item.has_name(sym::thread) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
} else if item.has_name(sym::hwaddress) {
@@ -2896,7 +3018,7 @@
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
- .note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
+ .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
.emit();
}
}
@@ -3120,8 +3242,7 @@
if tcx.is_weak_lang_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
- let check_name = |attr: &Attribute, sym| attr.has_name(sym);
- if let Some(name) = weak_lang_items::link_name(check_name, attrs) {
+ if let Some(name) = weak_lang_items::link_name(attrs) {
codegen_fn_attrs.export_name = Some(name);
codegen_fn_attrs.link_name = Some(name);
}
@@ -3150,21 +3271,12 @@
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(impl_item) = tcx.opt_associated_item(def_id) {
- if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
- if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
- if let Some(trait_item) = tcx
- .associated_items(trait_def_id)
- .filter_by_name_unhygienic(impl_item.ident.name)
- .find(move |trait_item| {
- trait_item.kind == ty::AssocKind::Fn
- && tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
- })
- {
- return tcx
- .codegen_fn_attrs(trait_item.def_id)
- .flags
- .intersects(CodegenFnAttrFlags::TRACK_CALLER);
- }
+ if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container {
+ if let Some(trait_item) = impl_item.trait_item_def_id {
+ return tcx
+ .codegen_fn_attrs(trait_item)
+ .flags
+ .intersects(CodegenFnAttrFlags::TRACK_CALLER);
}
}
}
@@ -3241,7 +3353,7 @@
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
- let parent_id = tcx.hir().get_parent_did(hir_id);
+ let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_item = tcx.hir().expect_item(parent_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 26cad8f..87a67c4 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -67,11 +67,7 @@
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
- let bounds = bounds.predicates(tcx, item_ty);
-
- debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
-
- tcx.arena.alloc_slice(&bounds)
+ tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
})
}
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index ae8d262..39da7c8 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -1,14 +1,14 @@
use rustc_errors::{Applicability, ErrorReported, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node};
-use rustc_middle::hir::map::Map;
-use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
@@ -18,78 +18,74 @@
/// Computes the relevant generic parameter for a potential generic const argument.
///
/// This should be called using the query `tcx.opt_const_param_of`.
+#[instrument(level = "debug", skip(tcx))]
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);
- if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
- let parent_node_id = tcx.hir().get_parent_node(hir_id);
- let parent_node = tcx.hir().get(parent_node_id);
+ match tcx.hir().get(hir_id) {
+ Node::AnonConst(_) => (),
+ _ => return None,
+ };
- match parent_node {
- // This match arm is for when the def_id appears in a GAT whose
- // path can't be resolved without typechecking e.g.
- //
- // trait Foo {
- // type Assoc<const N: usize>;
- // fn foo() -> Self::Assoc<3>;
- // }
- //
- // In the above code we would call this query with the def_id of 3 and
- // the parent_node we match on would be the hir node for Self::Assoc<3>
- //
- // `Self::Assoc<3>` cant be resolved without typchecking here as we
- // didnt write <Self as Foo>::Assoc<3>. If we did then another match
- // arm would handle this.
- //
- // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
- Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
- // Find the Item containing the associated type so we can create an ItemCtxt.
- // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
- // ty which is a fully resolved projection.
- // For the code example above, this would mean converting Self::Assoc<3>
- // into a ty::Projection(<Self as Foo>::Assoc<3>)
- let item_hir_id = tcx
- .hir()
- .parent_iter(hir_id)
- .filter(|(_, node)| matches!(node, Node::Item(_)))
- .map(|(id, _)| id)
- .next()
- .unwrap();
- let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
- let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
- let ty = item_ctxt.ast_ty_to_ty(hir_ty);
+ let parent_node_id = tcx.hir().get_parent_node(hir_id);
+ let parent_node = tcx.hir().get(parent_node_id);
- // Iterate through the generics of the projection to find the one that corresponds to
- // the def_id that this query was called with. We filter to only const args here as a
- // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
- // but it can't hurt to be safe ^^
- if let ty::Projection(projection) = ty.kind() {
- let generics = tcx.generics_of(projection.item_def_id);
+ let (generics, arg_idx) = match parent_node {
+ // This match arm is for when the def_id appears in a GAT whose
+ // path can't be resolved without typechecking e.g.
+ //
+ // trait Foo {
+ // type Assoc<const N: usize>;
+ // fn foo() -> Self::Assoc<3>;
+ // }
+ //
+ // In the above code we would call this query with the def_id of 3 and
+ // the parent_node we match on would be the hir node for Self::Assoc<3>
+ //
+ // `Self::Assoc<3>` cant be resolved without typchecking here as we
+ // didnt write <Self as Foo>::Assoc<3>. If we did then another match
+ // arm would handle this.
+ //
+ // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
+ Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
+ // Find the Item containing the associated type so we can create an ItemCtxt.
+ // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
+ // ty which is a fully resolved projection.
+ // For the code example above, this would mean converting Self::Assoc<3>
+ // into a ty::Projection(<Self as Foo>::Assoc<3>)
+ let item_hir_id = tcx
+ .hir()
+ .parent_iter(hir_id)
+ .filter(|(_, node)| matches!(node, Node::Item(_)))
+ .map(|(id, _)| id)
+ .next()
+ .unwrap();
+ let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
+ let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
+ let ty = item_ctxt.ast_ty_to_ty(hir_ty);
- let arg_index = segment
- .args
- .and_then(|args| {
- args.args
- .iter()
- .filter(|arg| arg.is_const())
- .position(|arg| arg.id() == hir_id)
- })
- .unwrap_or_else(|| {
- bug!("no arg matching AnonConst in segment");
- });
+ // Iterate through the generics of the projection to find the one that corresponds to
+ // the def_id that this query was called with. We filter to only const args here as a
+ // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
+ // but it can't hurt to be safe ^^
+ if let ty::Projection(projection) = ty.kind() {
+ let generics = tcx.generics_of(projection.item_def_id);
- return generics
- .params
- .iter()
- .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
- .nth(arg_index)
- .map(|param| param.def_id);
- }
+ let arg_index = segment
+ .args
+ .and_then(|args| {
+ args.args
+ .iter()
+ .filter(|arg| arg.is_ty_or_const())
+ .position(|arg| arg.id() == hir_id)
+ })
+ .unwrap_or_else(|| {
+ bug!("no arg matching AnonConst in segment");
+ });
+ (generics, arg_index)
+ } else {
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
@@ -97,159 +93,143 @@
);
return None;
}
- Node::Expr(&Expr {
- kind:
- ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
- ..
- }) => {
- let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
- let tables = tcx.typeck(body_owner);
- // This may fail in case the method/path does not actually exist.
- // As there is no relevant param for `def_id`, we simply return
- // `None` here.
- let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
- let idx = segment
- .args
- .and_then(|args| {
- args.args
- .iter()
- .filter(|arg| arg.is_const())
- .position(|arg| arg.id() == hir_id)
- })
- .unwrap_or_else(|| {
- bug!("no arg matching AnonConst in segment");
- });
+ }
+ Node::Expr(&Expr {
+ kind:
+ ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
+ ..
+ }) => {
+ let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+ let tables = tcx.typeck(body_owner);
+ // This may fail in case the method/path does not actually exist.
+ // As there is no relevant param for `def_id`, we simply return
+ // `None` here.
+ let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
+ let idx = segment
+ .args
+ .and_then(|args| {
+ args.args
+ .iter()
+ .filter(|arg| arg.is_ty_or_const())
+ .position(|arg| arg.id() == hir_id)
+ })
+ .unwrap_or_else(|| {
+ bug!("no arg matching AnonConst in segment");
+ });
- tcx.generics_of(type_dependent_def)
- .params
- .iter()
- .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
- .nth(idx)
- .map(|param| param.def_id)
- }
+ (tcx.generics_of(type_dependent_def), idx)
+ }
- Node::Ty(&Ty { kind: TyKind::Path(_), .. })
- | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
- | Node::TraitRef(..)
- | Node::Pat(_) => {
- let path = match parent_node {
- Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
- | Node::TraitRef(&TraitRef { path, .. }) => &*path,
- Node::Expr(&Expr {
- kind:
- ExprKind::Path(QPath::Resolved(_, path))
- | ExprKind::Struct(&QPath::Resolved(_, path), ..),
- ..
- }) => {
- let body_owner =
- tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
- let _tables = tcx.typeck(body_owner);
- &*path
+ Node::Ty(&Ty { kind: TyKind::Path(_), .. })
+ | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
+ | Node::TraitRef(..)
+ | Node::Pat(_) => {
+ let path = match parent_node {
+ Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
+ | Node::TraitRef(&TraitRef { path, .. }) => &*path,
+ Node::Expr(&Expr {
+ kind:
+ ExprKind::Path(QPath::Resolved(_, path))
+ | ExprKind::Struct(&QPath::Resolved(_, path), ..),
+ ..
+ }) => {
+ let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+ let _tables = tcx.typeck(body_owner);
+ &*path
+ }
+ Node::Pat(pat) => {
+ if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
+ path
+ } else {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(def_id),
+ &format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
+ );
+ return None;
}
- Node::Pat(pat) => {
- if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
- path
- } else {
+ }
+ _ => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(def_id),
+ &format!("unexpected const parent path {:?}", parent_node),
+ );
+ return None;
+ }
+ };
+
+ // We've encountered an `AnonConst` in some path, so we need to
+ // figure out which generic parameter it corresponds to and return
+ // the relevant type.
+ let filtered = path.segments.iter().find_map(|seg| {
+ seg.args?
+ .args
+ .iter()
+ .filter(|arg| arg.is_ty_or_const())
+ .position(|arg| arg.id() == hir_id)
+ .map(|index| (index, seg))
+ });
+
+ // FIXME(associated_const_generics): can we blend this with iteration above?
+ let (arg_index, segment) = match filtered {
+ None => {
+ let binding_filtered = path.segments.iter().find_map(|seg| {
+ seg.args?
+ .bindings
+ .iter()
+ .filter_map(TypeBinding::opt_const)
+ .position(|ct| ct.hir_id == hir_id)
+ .map(|idx| (idx, seg))
+ });
+ match binding_filtered {
+ Some(inner) => inner,
+ None => {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
- &format!(
- "unable to find const parent for {} in pat {:?}",
- hir_id, pat
- ),
+ "no arg matching AnonConst in path",
);
return None;
}
}
- _ => {
- tcx.sess.delay_span_bug(
- tcx.def_span(def_id),
- &format!("unexpected const parent path {:?}", parent_node),
- );
- return None;
- }
- };
+ }
+ Some(inner) => inner,
+ };
- // We've encountered an `AnonConst` in some path, so we need to
- // figure out which generic parameter it corresponds to and return
- // the relevant type.
- let filtered = path
- .segments
- .iter()
- .filter_map(|seg| seg.args.map(|args| (args.args, seg)))
- .find_map(|(args, seg)| {
- args.iter()
- .filter(|arg| arg.is_const())
- .position(|arg| arg.id() == hir_id)
- .map(|index| (index, seg))
- });
- let (arg_index, segment) = match filtered {
- None => {
- tcx.sess.delay_span_bug(
- tcx.def_span(def_id),
- "no arg matching AnonConst in path",
- );
- return None;
- }
- Some(inner) => inner,
- };
+ // 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);
+ let generics = match tcx.res_generics_def_id(res) {
+ Some(def_id) => tcx.generics_of(def_id),
+ None => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(def_id),
+ &format!("unexpected anon const res {:?} in path: {:?}", res, path),
+ );
+ return None;
+ }
+ };
- // 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(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
- // `generics_of`.
- Res::Def(
- DefKind::Struct
- | DefKind::Union
- | DefKind::Enum
- | DefKind::Trait
- | DefKind::OpaqueTy
- | DefKind::TyAlias
- | DefKind::ForeignTy
- | DefKind::TraitAlias
- | DefKind::AssocTy
- | DefKind::Fn
- | DefKind::AssocFn
- | DefKind::AssocConst
- | DefKind::Impl,
- def_id,
- ) => tcx.generics_of(def_id),
- Res::Err => {
- tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
- return None;
- }
- _ => {
- // If the user tries to specify generics on a type that does not take them,
- // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
- // no arguments have been passed. An error should already have been emitted.
- tcx.sess.delay_span_bug(
- tcx.def_span(def_id),
- &format!("unexpected anon const res {:?} in path: {:?}", res, path),
- );
- return None;
- }
- };
+ (generics, arg_index)
+ }
+ _ => return None,
+ };
- generics
- .params
- .iter()
- .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
- .nth(arg_index)
- .map(|param| param.def_id)
+ debug!(?parent_node);
+ debug!(?generics, ?arg_idx);
+ generics
+ .params
+ .iter()
+ .filter(|param| param.kind.is_ty_or_const())
+ .nth(match generics.has_self && generics.parent.is_none() {
+ true => arg_idx + 1,
+ false => arg_idx,
+ })
+ .and_then(|param| match param.kind {
+ ty::GenericParamDefKind::Const { .. } => {
+ debug!(?param);
+ Some(param.def_id)
}
_ => None,
- }
- } else {
- None
- }
+ })
}
fn get_path_containing_arg_in_pat<'hir>(
@@ -280,32 +260,6 @@
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
- | ty::TypeFlags::HAS_ERROR;
- 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::*;
@@ -350,7 +304,7 @@
}
}
ImplItemKind::TyAlias(ty) => {
- if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() {
+ if tcx.impl_trait_ref(tcx.hir().get_parent_item(hir_id)).is_none() {
check_feature_inherent_assoc_ty(tcx, item.span);
}
@@ -460,7 +414,7 @@
Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
VariantData::Unit(..) | VariantData::Struct(..) => {
- tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id())
+ tcx.type_of(tcx.hir().get_parent_item(hir_id))
}
VariantData::Tuple(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -509,20 +463,55 @@
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
- .adt_def(tcx.hir().get_parent_did(hir_id).to_def_id())
+ .adt_def(tcx.hir().get_parent_item(hir_id))
.repr
.discr_type()
.to_ty(tcx),
+ Node::TraitRef(trait_ref @ &TraitRef {
+ path, ..
+ }) if let Some((binding, seg)) =
+ path
+ .segments
+ .iter()
+ .find_map(|seg| {
+ seg.args?.bindings
+ .iter()
+ .find_map(|binding| if binding.opt_const()?.hir_id == hir_id {
+ Some((binding, seg))
+ } else {
+ None
+ })
+ }) =>
+ {
+ let Some(trait_def_id) = trait_ref.trait_def_id() else {
+ return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+ };
+ let assoc_items = tcx.associated_items(trait_def_id);
+ let assoc_item = assoc_items.find_by_name_and_kind(
+ tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
+ );
+ if let Some(assoc_item) = assoc_item {
+ tcx.type_of(assoc_item.def_id)
+ } else {
+ // FIXME(associated_const_equality): add a useful error message here.
+ tcx.ty_error_with_message(
+ DUMMY_SP,
+ "Could not find associated const on trait",
+ )
+ }
+ }
+
Node::GenericParam(&GenericParam {
hir_id: param_hir_id,
kind: GenericParamKind::Const { default: Some(ct), .. },
..
}) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
- x => tcx.ty_error_with_message(
+ x =>
+ tcx.ty_error_with_message(
DUMMY_SP,
- &format!("unexpected const parent in type_of(): {:?}", x),
+ &format!("unexpected const parent in type_of(): {x:?}"),
),
}
}
@@ -620,17 +609,17 @@
err.emit();
}
} else {
- self.found = Some((span, concrete_type));
+ self.found = Some((span, *concrete_type));
}
}
}
}
impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
- type Map = Map<'tcx>;
+ type NestedFilter = nested_filter::All;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::All(self.tcx.hir())
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
if let hir::ExprKind::Closure(..) = ex.kind {
@@ -757,7 +746,10 @@
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();
+ // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
+ if let Ok(suggestions) = &mut err.suggestions {
+ suggestions.clear();
+ }
// Suggesting unnameable types won't help.
let mut mk_nameable = MakeNameable::new(tcx);
@@ -781,7 +773,7 @@
err.emit();
}
None => {
- let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
+ let mut diag = bad_placeholder(tcx, vec![span], kind);
if !ty.references_error() {
let mut mk_nameable = MakeNameable::new(tcx);
@@ -807,7 +799,7 @@
}
// Typeck doesn't expect erased regions to be returned from `type_of`.
- tcx.fold_regions(ty, &mut false, |r, _| match r {
+ tcx.fold_regions(ty, &mut false, |r, _| match *r {
ty::ReErased => tcx.lifetimes.re_static,
_ => r,
})
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 88877ad..909c99a 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -27,13 +27,12 @@
/// 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(tcx, &tr, false),
- None => parameters_for(tcx, &impl_self_ty, false),
+ Some(tr) => parameters_for(&tr, false),
+ None => parameters_for(&impl_self_ty, false),
};
vec.into_iter().collect()
}
@@ -44,26 +43,20 @@
/// 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 { tcx, parameters: vec![], include_nonconstraining };
+ let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
t.visit_with(&mut collector);
collector.parameters
}
-struct ParameterCollector<'tcx> {
- tcx: TyCtxt<'tcx>,
+struct ParameterCollector {
parameters: Vec<Parameter>,
include_nonconstraining: bool,
}
-impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> {
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
+impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
@@ -86,11 +79,11 @@
ControlFlow::CONTINUE
}
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- match c.val {
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match c.val() {
ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
// Constant expressions are not injective
- return c.ty.visit_with(self);
+ return c.ty().visit_with(self);
}
ty::ConstKind::Param(data) => {
self.parameters.push(Parameter::from(data));
@@ -205,12 +198,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(tcx, &projection.projection_ty, true);
+ let inputs = parameters_for(&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(tcx, &projection.ty, false));
+ input_parameters.extend(parameters_for(&projection.term, false));
} else {
continue;
}
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 1ae0ff3..db1c80a 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -17,7 +17,6 @@
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
-use std::iter;
use crate::mem_categorization as mc;
@@ -360,17 +359,6 @@
}
}
- hir::ExprKind::LlvmInlineAsm(ia) => {
- for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) {
- if o.is_indirect {
- self.consume_expr(output);
- } else {
- self.mutate_expr(output);
- }
- }
- self.consume_exprs(ia.inputs_exprs);
- }
-
hir::ExprKind::Continue(..)
| hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
@@ -796,14 +784,14 @@
);
match capture_info.capture_kind {
- ty::UpvarCapture::ByValue(_) => {
+ ty::UpvarCapture::ByValue => {
self.delegate_consume(&place_with_id, place_with_id.hir_id);
}
ty::UpvarCapture::ByRef(upvar_borrow) => {
self.delegate.borrow(
&place_with_id,
place_with_id.hir_id,
- upvar_borrow.kind,
+ upvar_borrow,
);
}
}
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index a49eda6..7b709b3 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -1,6 +1,6 @@
use crate::collect::ItemCtxt;
use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::TraitEngine;
@@ -64,10 +64,6 @@
}
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| {
let mut fulfill = traits::FulfillmentContext::new();
@@ -184,6 +180,6 @@
self.tcx
}
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
- if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
+ if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r }
}
}
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index ae6321d..1604908 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -117,7 +117,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(tcx, impl_self_ty, impl_trait_ref);
+ let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(
tcx,
impl_predicates,
@@ -134,7 +134,7 @@
match item.kind {
ty::AssocKind::Type => {
if item.defaultness.has_value() {
- cgp::parameters_for(tcx, &tcx.type_of(def_id), true)
+ cgp::parameters_for(&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 4fb422c..92f88a1 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -199,22 +199,22 @@
for (predicate, _) in impl_generic_predicates.predicates.iter() {
if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
let projection_ty = proj.projection_ty;
- let projected_ty = proj.ty;
+ let projected_ty = proj.term;
let unbound_trait_ref = projection_ty.trait_ref(tcx);
if Some(unbound_trait_ref) == impl_trait_ref {
continue;
}
- unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
+ unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true));
- for param in cgp::parameters_for(tcx, &projected_ty, false) {
+ for param in cgp::parameters_for(&projected_ty, false) {
if !unconstrained_parameters.contains(¶m) {
constrained_params.insert(param.0);
}
}
- unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
+ unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true));
}
}
@@ -248,7 +248,7 @@
parent_substs: &Vec<GenericArg<'tcx>>,
span: Span,
) {
- let mut base_params = cgp::parameters_for(tcx, parent_substs, true);
+ let mut base_params = cgp::parameters_for(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];
@@ -269,7 +269,7 @@
parent_substs: &Vec<GenericArg<'tcx>>,
span: Span,
) {
- if tcx.any_free_region_meets(parent_substs, |r| *r == ty::ReStatic) {
+ if tcx.any_free_region_meets(parent_substs, |r| r.is_static()) {
tcx.sess.struct_span_err(span, "cannot specialize on `'static` lifetime").emit();
}
}
@@ -376,7 +376,7 @@
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(tcx) => (),
+ _ if predicate.is_global() => (),
// We allow specializing on explicitly marked traits with no associated
// items.
ty::PredicateKind::Trait(ty::TraitPredicate {
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 24e427f..d415e37 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -69,6 +69,7 @@
#![feature(control_flow_enum)]
#![feature(hash_drain_filter)]
#![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
@@ -121,7 +122,7 @@
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
match (decl.c_variadic, abi) {
// The function has the correct calling convention, or isn't a "C-variadic" function.
- (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl) => {}
+ (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
// The function is a "C-variadic" function with an incorrect calling convention.
(true, _) => {
let mut err = struct_span_err!(
@@ -543,8 +544,7 @@
// In case there are any projections, etc., find the "environment"
// def-ID that will be used to determine the traits/predicates in
// scope. This is derived from the enclosing item-like thing.
- let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
- let env_def_id = tcx.hir().local_def_id(env_node_id);
+ let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
<dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
}
@@ -557,8 +557,7 @@
// In case there are any projections, etc., find the "environment"
// def-ID that will be used to determine the traits/predicates in
// scope. This is derived from the enclosing item-like thing.
- let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
- let env_def_id = tcx.hir().local_def_id(env_hir_id);
+ let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
let mut bounds = Bounds::default();
let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 440ce04..1bbd6d2 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -192,7 +192,7 @@
if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) {
if let Some(first_ty) = vec.first() {
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
- return Ok(first_ty);
+ return Ok(*first_ty);
}
}
@@ -378,7 +378,6 @@
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
- | hir::ExprKind::LlvmInlineAsm(..)
| hir::ExprKind::Box(..)
| hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
}
@@ -563,7 +562,7 @@
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
| Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfCtor(..)
- | Res::SelfTy(..) => {
+ | Res::SelfTy { .. } => {
// Structs and Unions have only have one variant.
Ok(VariantIdx::new(0))
}
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
index 86d712e..89f0bd8 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -114,18 +114,7 @@
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) {
- // 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() {
+ for arg in field_ty.walk() {
let ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty,
@@ -317,7 +306,7 @@
// 'b`.
if let Some(self_ty) = ignored_self_ty {
if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() {
- if ty.walk(tcx).any(|arg| arg == self_ty.into()) {
+ if ty.walk().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 eb3853b..139be8a 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_typeck/src/outlives/mod.rs
@@ -35,8 +35,7 @@
// 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();
+ let item_def_id = tcx.hir().get_parent_item(id);
// In the above code example we would be calling `inferred_outlives_of(Foo)` here
return tcx.inferred_outlives_of(item_def_id);
}
@@ -106,14 +105,14 @@
match kind1.unpack() {
GenericArgKind::Type(ty1) => Some((
ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
- ty::OutlivesPredicate(ty1, region2),
+ ty::OutlivesPredicate(ty1, *region2),
))
.to_predicate(tcx),
span,
)),
GenericArgKind::Lifetime(region1) => Some((
ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
- ty::OutlivesPredicate(region1, region2),
+ ty::OutlivesPredicate(region1, *region2),
))
.to_predicate(tcx),
span,
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs
index 76ae2ee..54a5037 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_typeck/src/outlives/utils.rs
@@ -1,6 +1,6 @@
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Region, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, Region, Ty, TyCtxt};
use rustc_span::Span;
use smallvec::smallvec;
use std::collections::BTreeMap;
@@ -133,7 +133,7 @@
fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
// First, screen for regions that might appear in a type header.
- match region {
+ match *region {
// These correspond to `T: 'a` relationships:
//
// struct Foo<'a, T> {
@@ -141,7 +141,7 @@
// }
//
// We care about these, so fall through.
- RegionKind::ReEarlyBound(_) => true,
+ ty::ReEarlyBound(_) => true,
// These correspond to `T: 'static` relationships which can be
// rather surprising. We are therefore putting this behind a
@@ -150,7 +150,7 @@
// struct Foo<'a, T> {
// field: &'static T, // this would generate a ReStatic
// }
- RegionKind::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements,
+ ty::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements,
// Late-bound regions can appear in `fn` types:
//
@@ -160,19 +160,16 @@
//
// The type above might generate a `T: 'b` bound, but we can
// ignore it. We can't put it on the struct header anyway.
- RegionKind::ReLateBound(..) => false,
+ ty::ReLateBound(..) => false,
// This can appear in `where Self: ` bounds (#64855):
//
// struct Bar<T>(<Self as Foo>::Type) where Self: ;
// struct Baz<'a>(&'a Self) where Self: ;
- RegionKind::ReEmpty(_) => false,
+ ty::ReEmpty(_) => false,
// These regions don't appear in types from type declarations:
- RegionKind::ReErased
- | RegionKind::ReVar(..)
- | RegionKind::RePlaceholder(..)
- | RegionKind::ReFree(..) => {
+ ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => {
bug!("unexpected region in outlives inference: {:?}", region);
}
}
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 33c27ce..1c8f848 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -308,11 +308,14 @@
}
for projection in data.projection_bounds() {
- self.add_constraints_from_ty(
- current,
- projection.skip_binder().ty,
- self.invariant,
- );
+ match projection.skip_binder().term {
+ ty::Term::Ty(ty) => {
+ self.add_constraints_from_ty(current, ty, self.invariant);
+ }
+ ty::Term::Const(c) => {
+ self.add_constraints_from_const(current, c, self.invariant)
+ }
+ }
}
}
@@ -398,15 +401,14 @@
fn add_constraints_from_const(
&mut self,
current: &CurrentItem,
- val: &ty::Const<'tcx>,
+ val: ty::Const<'tcx>,
variance: VarianceTermPtr<'a>,
) {
debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
- match &val.val {
+ match &val.val() {
ty::ConstKind::Unevaluated(uv) => {
- let substs = uv.substs(self.tcx());
- self.add_constraints_from_invariant_substs(current, substs, variance);
+ self.add_constraints_from_invariant_substs(current, uv.substs, variance);
}
_ => {}
}
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs
index d7f9df6..36fbfc2 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_typeck/src/variance/terms.rs
@@ -86,7 +86,7 @@
fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> {
let lang_items = tcx.lang_items();
- let all = vec![
+ let all = [
(lang_items.phantom_data(), vec![ty::Covariant]),
(lang_items.unsafe_cell_type(), vec![ty::Invariant]),
];