Importing rustc-1.58.0
Bug: 213921092
Test: ./build.py --lto=thin
Change-Id: Icc9fe2d5bc3327afd20177fc973a6e44941f787f
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
index 739c6fd..9627795 100644
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ b/compiler/rustc_apfloat/src/ieee.rs
@@ -389,7 +389,6 @@
let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
// Change the exponent from 2^e to 10^e.
- #[allow(clippy::comparison_chain)]
if exp == 0 {
// Nothing to do.
} else if exp > 0 {
@@ -2527,7 +2526,6 @@
if *a_sign ^ b_sign {
let (reverse, loss);
- #[allow(clippy::comparison_chain)]
if bits == 0 {
reverse = cmp(a_sig, b_sig) == Ordering::Less;
loss = Loss::ExactlyZero;
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 6d5f47a..6f9ecb9c 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -19,7 +19,6 @@
#![feature(rustc_attrs)]
#![cfg_attr(test, feature(test))]
-use rustc_data_structures::sync;
use smallvec::SmallVec;
use std::alloc::Layout;
@@ -112,7 +111,7 @@
// alloc() will trigger a grow().
ptr: Cell::new(ptr::null_mut()),
end: Cell::new(ptr::null_mut()),
- chunks: RefCell::new(vec![]),
+ chunks: Default::default(),
_own: PhantomData,
}
}
@@ -326,13 +325,17 @@
unsafe impl<T: Send> Send for TypedArena<T> {}
+/// An arena that can hold objects of multiple different types that impl `Copy`
+/// and/or satisfy `!mem::needs_drop`.
pub struct DroplessArena {
/// A pointer to the start of the free space.
start: Cell<*mut u8>,
/// A pointer to the end of free space.
///
- /// The allocation proceeds from the end of the chunk towards the start.
+ /// The allocation proceeds downwards from the end of the chunk towards the
+ /// start. (This is slightly simpler and faster than allocating upwards,
+ /// see <https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html>.)
/// When this pointer crosses the start pointer, a new chunk is allocated.
end: Cell<*mut u8>,
@@ -517,130 +520,16 @@
}
}
-/// Calls the destructor for an object when dropped.
-struct DropType {
- drop_fn: unsafe fn(*mut u8),
- obj: *mut u8,
-}
-
-// SAFETY: we require `T: Send` before type-erasing into `DropType`.
-#[cfg(parallel_compiler)]
-unsafe impl sync::Send for DropType {}
-
-impl DropType {
- #[inline]
- unsafe fn new<T: sync::Send>(obj: *mut T) -> Self {
- unsafe fn drop_for_type<T>(to_drop: *mut u8) {
- std::ptr::drop_in_place(to_drop as *mut T)
- }
-
- DropType { drop_fn: drop_for_type::<T>, obj: obj as *mut u8 }
- }
-}
-
-impl Drop for DropType {
- fn drop(&mut self) {
- unsafe { (self.drop_fn)(self.obj) }
- }
-}
-
-/// An arena which can be used to allocate any type.
-///
-/// # Safety
-///
-/// Allocating in this arena is unsafe since the type system
-/// doesn't know which types it contains. In order to
-/// allocate safely, you must store a `PhantomData<T>`
-/// alongside this arena for each type `T` you allocate.
-#[derive(Default)]
-pub struct DropArena {
- /// A list of destructors to run when the arena drops.
- /// Ordered so `destructors` gets dropped before the arena
- /// since its destructor can reference memory in the arena.
- destructors: RefCell<Vec<DropType>>,
- arena: DroplessArena,
-}
-
-impl DropArena {
- #[inline]
- pub unsafe fn alloc<T>(&self, object: T) -> &mut T
- where
- T: sync::Send,
- {
- let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T;
- // Write into uninitialized memory.
- ptr::write(mem, object);
- let result = &mut *mem;
- // Record the destructor after doing the allocation as that may panic
- // and would cause `object`'s destructor to run twice if it was recorded before.
- self.destructors.borrow_mut().push(DropType::new(result));
- result
- }
-
- #[inline]
- pub unsafe fn alloc_from_iter<T, I>(&self, iter: I) -> &mut [T]
- where
- T: sync::Send,
- I: IntoIterator<Item = T>,
- {
- let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
- if vec.is_empty() {
- return &mut [];
- }
- let len = vec.len();
-
- let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
-
- let mut destructors = self.destructors.borrow_mut();
- // Reserve space for the destructors so we can't panic while adding them.
- destructors.reserve(len);
-
- // Move the content to the arena by copying it and then forgetting
- // the content of the SmallVec.
- vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
- mem::forget(vec.drain(..));
-
- // Record the destructors after doing the allocation as that may panic
- // and would cause `object`'s destructor to run twice if it was recorded before.
- for i in 0..len {
- destructors.push(DropType::new(start_ptr.add(i)));
- }
-
- slice::from_raw_parts_mut(start_ptr, len)
- }
-}
-
-pub macro arena_for_type {
- ([][$ty:ty]) => {
- $crate::TypedArena<$ty>
- },
- ([few $(, $attrs:ident)*][$ty:ty]) => {
- ::std::marker::PhantomData<$ty>
- },
- ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
- $crate::arena_for_type!([$($attrs),*]$args)
- },
-}
-
-pub macro which_arena_for_type {
- ([][$arena:expr]) => {
- ::std::option::Option::Some($arena)
- },
- ([few$(, $attrs:ident)*][$arena:expr]) => {
- ::std::option::Option::None
- },
- ([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
- $crate::which_arena_for_type!([$($attrs),*]$args)
- },
-}
-
+// 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`.
#[rustc_macro_transparency = "semitransparent"]
-pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
+pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
#[derive(Default)]
- pub struct Arena<$tcx> {
+ pub struct Arena<'tcx> {
pub dropless: $crate::DroplessArena,
- drop: $crate::DropArena,
- $($name: $crate::arena_for_type!($a[$ty]),)*
+ $($name: $crate::TypedArena<$ty>,)*
}
pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
@@ -651,6 +540,7 @@
) -> &'a mut [Self];
}
+ // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
#[inline]
fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
@@ -663,36 +553,27 @@
) -> &'a mut [Self] {
arena.dropless.alloc_from_iter(iter)
}
-
}
$(
- impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
+ impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty {
#[inline]
- fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
+ fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
if !::std::mem::needs_drop::<Self>() {
- return arena.dropless.alloc(self);
- }
- match $crate::which_arena_for_type!($a[&arena.$name]) {
- ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
- ty_arena.alloc(self)
- }
- ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
+ arena.dropless.alloc(self)
+ } else {
+ arena.$name.alloc(self)
}
}
#[inline]
fn allocate_from_iter<'a>(
- arena: &'a Arena<$tcx>,
+ arena: &'a Arena<'tcx>,
iter: impl ::std::iter::IntoIterator<Item = Self>,
) -> &'a mut [Self] {
if !::std::mem::needs_drop::<Self>() {
- return arena.dropless.alloc_from_iter(iter);
- }
- match $crate::which_arena_for_type!($a[&arena.$name]) {
- ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
- ty_arena.alloc_from_iter(iter)
- }
- ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
+ arena.dropless.alloc_from_iter(iter)
+ } else {
+ arena.$name.alloc_from_iter(iter)
}
}
}
@@ -704,6 +585,7 @@
value.allocate_on(self)
}
+ // Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`.
#[inline]
pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
if value.is_empty() {
diff --git a/compiler/rustc_ast/README.md b/compiler/rustc_ast/README.md
index dd407db..b2b90fe 100644
--- a/compiler/rustc_ast/README.md
+++ b/compiler/rustc_ast/README.md
@@ -1,6 +1,5 @@
The `rustc_ast` crate contains those things concerned purely with syntax
-– that is, the AST ("abstract syntax tree"), parser, pretty-printer,
-lexer, macro expander, and utilities for traversing ASTs.
+– that is, the AST ("abstract syntax tree"), along with some definitions for tokens and token streams, data structures/traits for mutating ASTs, and shared definitions for other AST-related parts of the compiler (like the lexer and macro-expansion).
For more information about how these things work in rustc, see the
rustc dev guide:
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e2424e7..55b243a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -405,6 +405,21 @@
pub kind: GenericParamKind,
}
+impl GenericParam {
+ pub fn span(&self) -> Span {
+ match &self.kind {
+ GenericParamKind::Lifetime | GenericParamKind::Type { default: None } => {
+ self.ident.span
+ }
+ GenericParamKind::Type { default: Some(ty) } => self.ident.span.to(ty.span),
+ GenericParamKind::Const { kw_span, default: Some(default), .. } => {
+ kw_span.to(default.value.span)
+ }
+ GenericParamKind::Const { kw_span, default: None, ty } => kw_span.to(ty.span),
+ }
+ }
+}
+
/// Represents lifetime, type and const parameters attached to a declaration of
/// a function, enum, trait, etc.
#[derive(Clone, Encodable, Decodable, Debug)]
@@ -2058,7 +2073,7 @@
pub template: Vec<InlineAsmTemplatePiece>,
pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
pub operands: Vec<(InlineAsmOperand, Span)>,
- pub clobber_abi: Option<(Symbol, Span)>,
+ pub clobber_abis: Vec<(Symbol, Span)>,
pub options: InlineAsmOptions,
pub line_spans: Vec<Span>,
}
@@ -2645,34 +2660,42 @@
}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct TraitKind(
- pub IsAuto,
- pub Unsafe,
- pub Generics,
- pub GenericBounds,
- pub Vec<P<AssocItem>>,
-);
-
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct TyAliasKind(pub Defaultness, pub Generics, pub GenericBounds, pub Option<P<Ty>>);
-
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct ImplKind {
+pub struct Trait {
pub unsafety: Unsafe,
- pub polarity: ImplPolarity,
- pub defaultness: Defaultness,
- pub constness: Const,
+ pub is_auto: IsAuto,
pub generics: Generics,
+ pub bounds: GenericBounds,
+ pub items: Vec<P<AssocItem>>,
+}
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct TyAlias {
+ pub defaultness: Defaultness,
+ pub generics: Generics,
+ pub bounds: GenericBounds,
+ pub ty: Option<P<Ty>>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Impl {
+ pub defaultness: Defaultness,
+ pub unsafety: Unsafe,
+ pub generics: Generics,
+ pub constness: Const,
+ pub polarity: ImplPolarity,
/// The trait being implemented, if any.
pub of_trait: Option<TraitRef>,
-
pub self_ty: P<Ty>,
pub items: Vec<P<AssocItem>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct FnKind(pub Defaultness, pub FnSig, pub Generics, pub Option<P<Block>>);
+pub struct Fn {
+ pub defaultness: Defaultness,
+ pub generics: Generics,
+ pub sig: FnSig,
+ pub body: Option<P<Block>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
@@ -2695,7 +2718,7 @@
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// A module declaration (`mod`).
///
/// E.g., `mod foo;` or `mod foo { .. }`.
@@ -2707,11 +2730,11 @@
/// E.g., `extern {}` or `extern "C" {}`.
ForeignMod(ForeignMod),
/// Module-level inline assembly (from `global_asm!()`).
- GlobalAsm(InlineAsm),
+ GlobalAsm(Box<InlineAsm>),
/// A type alias (`type`).
///
/// E.g., `type Foo = Bar<u8>;`.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// An enum definition (`enum`).
///
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
@@ -2727,7 +2750,7 @@
/// A trait declaration (`trait`).
///
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
- Trait(Box<TraitKind>),
+ Trait(Box<Trait>),
/// Trait alias
///
/// E.g., `trait Foo = Bar + Quux;`.
@@ -2735,7 +2758,7 @@
/// An implementation.
///
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
- Impl(Box<ImplKind>),
+ Impl(Box<Impl>),
/// A macro invocation.
///
/// E.g., `foo!(..)`.
@@ -2782,14 +2805,14 @@
pub fn generics(&self) -> Option<&Generics> {
match self {
- Self::Fn(box FnKind(_, _, generics, _))
- | Self::TyAlias(box TyAliasKind(_, generics, ..))
+ Self::Fn(box Fn { generics, .. })
+ | Self::TyAlias(box TyAlias { generics, .. })
| Self::Enum(_, generics)
| Self::Struct(_, generics)
| Self::Union(_, generics)
- | Self::Trait(box TraitKind(_, _, generics, ..))
+ | Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(generics, _)
- | Self::Impl(box ImplKind { generics, .. }) => Some(generics),
+ | Self::Impl(box Impl { generics, .. }) => Some(generics),
_ => None,
}
}
@@ -2812,9 +2835,9 @@
/// If `def` is parsed, then the constant is provided, and otherwise required.
Const(Defaultness, P<Ty>, Option<P<Expr>>),
/// An associated function.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// An associated type.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// A macro expanding to associated items.
MacCall(MacCall),
}
@@ -2825,9 +2848,9 @@
impl AssocItemKind {
pub fn defaultness(&self) -> Defaultness {
match *self {
- Self::Const(def, ..)
- | Self::Fn(box FnKind(def, ..))
- | Self::TyAlias(box TyAliasKind(def, ..)) => def,
+ Self::Const(defaultness, ..)
+ | Self::Fn(box Fn { defaultness, .. })
+ | Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
}
}
@@ -2864,9 +2887,9 @@
/// A foreign static item (`static FOO: u8`).
Static(P<Ty>, Mutability, Option<P<Expr>>),
/// An foreign function.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// An foreign type.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// A macro expanding to foreign items.
MacCall(MacCall),
}
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 5f17008..927d7c6 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -62,7 +62,7 @@
self.meta_item().and_then(|meta_item| meta_item.ident())
}
pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::invalid).name
+ self.ident().unwrap_or_else(Ident::empty).name
}
/// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
@@ -131,7 +131,7 @@
}
}
pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::invalid).name
+ self.ident().unwrap_or_else(Ident::empty).name
}
pub fn value_str(&self) -> Option<Symbol> {
@@ -166,7 +166,7 @@
if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
}
pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::invalid).name
+ self.ident().unwrap_or_else(Ident::empty).name
}
// Example:
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index e3c6105..b9db2a7 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -1,4 +1,4 @@
-//! The Rust parser and macro expander.
+//! The Rust Abstract Syntax Tree (AST).
//!
//! # Note
//!
@@ -16,6 +16,7 @@
#![feature(nll)]
#![feature(min_specialization)]
#![recursion_limit = "256"]
+#![feature(slice_internals)]
#[macro_use]
extern crate rustc_macros;
@@ -25,6 +26,7 @@
pub mod comments;
pub mod literal;
pub mod parser;
+ pub mod unicode;
}
pub mod ast;
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index ba86036..fc5cc96 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -37,9 +37,7 @@
/// Mutable token visiting only exists for the `macro_rules` token marker and should not be
/// used otherwise. Token visitor would be entirely separate from the regular visitor if
/// the marker didn't have to visit AST fragments in nonterminal tokens.
- fn token_visiting_enabled(&self) -> bool {
- false
- }
+ const VISIT_TOKENS: bool = false;
// Methods in this trait have one of three forms:
//
@@ -363,7 +361,7 @@
}
MacArgs::Eq(eq_span, token) => {
vis.visit_span(eq_span);
- if vis.token_visiting_enabled() {
+ if T::VISIT_TOKENS {
visit_token(token, vis);
} else {
// The value in `#[key = VALUE]` must be visited as an expression for backward
@@ -461,7 +459,8 @@
vis.visit_mt(mt);
}
TyKind::BareFn(bft) => {
- let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut();
+ let BareFnTy { unsafety, ext: _, generic_params, decl } = bft.deref_mut();
+ visit_unsafety(unsafety, vis);
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_fn_decl(decl);
}
@@ -490,7 +489,8 @@
}
pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
- let ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
+ let ForeignMod { unsafety, abi: _, items } = foreign_mod;
+ visit_unsafety(unsafety, vis);
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
}
@@ -682,7 +682,7 @@
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
- if vis.token_visiting_enabled() && !tts.is_empty() {
+ if T::VISIT_TOKENS && !tts.is_empty() {
let tts = Lrc::make_mut(tts);
visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis));
}
@@ -692,14 +692,14 @@
AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
vis: &mut T,
) {
- if vis.token_visiting_enabled() && !tts.is_empty() {
+ if T::VISIT_TOKENS && !tts.is_empty() {
let tts = Lrc::make_mut(tts);
visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
}
}
pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
- if vis.token_visiting_enabled() {
+ if T::VISIT_TOKENS {
if let Some(lazy_tts) = lazy_tts {
let mut tts = lazy_tts.create_token_stream();
visit_attr_annotated_tts(&mut tts, vis);
@@ -790,6 +790,38 @@
}
}
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) {
+ match defaultness {
+ Defaultness::Default(span) => vis.visit_span(span),
+ Defaultness::Final => {}
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) {
+ match unsafety {
+ Unsafe::Yes(span) => vis.visit_span(span),
+ Unsafe::No => {}
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) {
+ match polarity {
+ ImplPolarity::Positive => {}
+ ImplPolarity::Negative(span) => vis.visit_span(span),
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
+ match constness {
+ Const::Yes(span) => vis.visit_span(span),
+ Const::No => {}
+ }
+}
+
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
match asyncness {
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
@@ -957,25 +989,35 @@
match kind {
ItemKind::ExternCrate(_orig_name) => {}
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
- ItemKind::Static(ty, _, expr) | ItemKind::Const(_, ty, expr) => {
+ ItemKind::Static(ty, _, expr) => {
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
}
- ItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ItemKind::Const(defaultness, ty, expr) => {
+ visit_defaultness(defaultness, vis);
+ vis.visit_ty(ty);
+ visit_opt(expr, |expr| vis.visit_expr(expr));
+ }
+ ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, vis);
visit_fn_sig(sig, vis);
vis.visit_generics(generics);
visit_opt(body, |body| vis.visit_block(body));
}
- ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
- ModKind::Loaded(items, _inline, inner_span) => {
- vis.visit_span(inner_span);
- items.flat_map_in_place(|item| vis.flat_map_item(item));
+ ItemKind::Mod(unsafety, mod_kind) => {
+ visit_unsafety(unsafety, vis);
+ match mod_kind {
+ ModKind::Loaded(items, _inline, inner_span) => {
+ vis.visit_span(inner_span);
+ items.flat_map_in_place(|item| vis.flat_map_item(item));
+ }
+ ModKind::Unloaded => {}
}
- ModKind::Unloaded => {}
- },
+ }
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
- ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, vis);
vis.visit_generics(generics);
visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty));
@@ -988,22 +1030,27 @@
vis.visit_variant_data(variant_data);
vis.visit_generics(generics);
}
- ItemKind::Impl(box ImplKind {
- unsafety: _,
- polarity: _,
- defaultness: _,
- constness: _,
+ ItemKind::Impl(box Impl {
+ defaultness,
+ unsafety,
generics,
+ constness,
+ polarity,
of_trait,
self_ty,
items,
}) => {
+ visit_defaultness(defaultness, vis);
+ visit_unsafety(unsafety, vis);
vis.visit_generics(generics);
+ visit_constness(constness, vis);
+ visit_polarity(polarity, vis);
visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
vis.visit_ty(self_ty);
items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
}
- ItemKind::Trait(box TraitKind(.., generics, bounds, items)) => {
+ ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => {
+ visit_unsafety(unsafety, vis);
vis.visit_generics(generics);
visit_bounds(bounds, vis);
items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
@@ -1027,16 +1074,19 @@
visitor.visit_vis(vis);
visit_attrs(attrs, visitor);
match kind {
- AssocItemKind::Const(_, ty, expr) => {
+ AssocItemKind::Const(defaultness, ty, expr) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
@@ -1049,8 +1099,10 @@
}
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
- let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header;
+ let FnHeader { unsafety, asyncness, constness, ext: _ } = header;
+ visit_constness(constness, vis);
vis.visit_asyncness(asyncness);
+ visit_unsafety(unsafety, vis);
}
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
@@ -1060,7 +1112,7 @@
let item_vis =
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
let item = P(Item {
- ident: Ident::invalid(),
+ ident: Ident::empty(),
attrs,
id: DUMMY_NODE_ID,
vis: item_vis,
@@ -1116,12 +1168,14 @@
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 5d994db..51cabb5 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -221,12 +221,6 @@
for attr in &data.attrs {
match attr.style {
crate::AttrStyle::Outer => {
- assert!(
- inner_attrs.len() == 0,
- "Found outer attribute {:?} after inner attrs {:?}",
- attr,
- inner_attrs
- );
outer_attrs.push(attr);
}
crate::AttrStyle::Inner => {
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index 542a330..80a06fa 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -38,7 +38,7 @@
i += 1;
}
// like the first, a last line of all stars should be omitted
- if j > i && lines[j - 1].chars().skip(1).all(|c| c == '*') {
+ if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
j -= 1;
}
@@ -169,7 +169,7 @@
if let Some(mut idx) = token_text.find('\n') {
code_to_the_left = false;
while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
- idx = idx + 1 + next_newline;
+ idx += 1 + next_newline;
comments.push(Comment {
style: CommentStyle::BlankLine,
lines: vec![],
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 078dd4b..742a7d1 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -212,7 +212,8 @@
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
pub fn can_continue_expr_unambiguously(&self) -> bool {
use AssocOp::*;
- match self {
+ matches!(
+ self,
BitXor | // `{ 42 } ^ 3`
Assign | // `{ 42 } = { 42 }`
Divide | // `{ 42 } / 42`
@@ -225,9 +226,8 @@
As | // `{ 42 } as usize`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
- Colon => true, // `{ 42 }: usize`
- _ => false,
- }
+ Colon, // `{ 42 }: usize`
+ )
}
}
@@ -357,13 +357,13 @@
}
}
-/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
+/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
pub fn prec_let_scrutinee_needs_par() -> usize {
AssocOp::LAnd.precedence()
}
/// Suppose we have `let _ = e` and the `order` of `e`.
-/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
+/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
///
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
/// Can we print this as `let _ = a OP b`?
diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs
new file mode 100644
index 0000000..f009f7b
--- /dev/null
+++ b/compiler/rustc_ast/src/util/unicode.rs
@@ -0,0 +1,35 @@
+pub const TEXT_FLOW_CONTROL_CHARS: &[char] = &[
+ '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}',
+ '\u{2069}',
+];
+
+#[inline]
+pub fn contains_text_flow_control_chars(s: &str) -> bool {
+ // Char - UTF-8
+ // U+202A - E2 80 AA
+ // U+202B - E2 80 AB
+ // U+202C - E2 80 AC
+ // U+202D - E2 80 AD
+ // U+202E - E2 80 AE
+ // U+2066 - E2 81 A6
+ // U+2067 - E2 81 A7
+ // U+2068 - E2 81 A8
+ // U+2069 - E2 81 A9
+ let mut bytes = s.as_bytes();
+ loop {
+ match core::slice::memchr::memchr(0xE2, &bytes) {
+ Some(idx) => {
+ // bytes are valid UTF-8 -> E2 must be followed by two bytes
+ let ch = &bytes[idx..idx + 3];
+ match ch {
+ [_, 0x80, 0xAA..=0xAE] | [_, 0x81, 0xA6..=0xA9] => break true,
+ _ => {}
+ }
+ bytes = &bytes[idx + 3..];
+ }
+ None => {
+ break false;
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index b380310..be794ed 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -285,7 +285,7 @@
visitor.visit_ty(typ);
walk_list!(visitor, visit_expr, expr);
}
- ItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) => {
+ ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
@@ -300,7 +300,7 @@
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty)) => {
+ ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
@@ -309,12 +309,12 @@
visitor.visit_generics(generics);
visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
}
- ItemKind::Impl(box ImplKind {
- unsafety: _,
- polarity: _,
+ ItemKind::Impl(box Impl {
defaultness: _,
- constness: _,
+ unsafety: _,
ref generics,
+ constness: _,
+ polarity: _,
ref of_trait,
ref self_ty,
ref items,
@@ -329,7 +329,13 @@
visitor.visit_generics(generics);
visitor.visit_variant_data(struct_definition);
}
- ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref items)) => {
+ ItemKind::Trait(box Trait {
+ unsafety: _,
+ is_auto: _,
+ ref generics,
+ ref bounds,
+ ref items,
+ }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
@@ -547,12 +553,12 @@
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
@@ -653,12 +659,12 @@
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index f4859ee..7989af2 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -14,6 +14,7 @@
rustc_target = { path = "../rustc_target" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }
+rustc_query_system = { path = "../rustc_query_system" }
rustc_span = { path = "../rustc_span" }
rustc_errors = { path = "../rustc_errors" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 957b14f..cfa97ff 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -2,22 +2,45 @@
use rustc_ast::*;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_span::{Span, Symbol};
+use rustc_session::parse::feature_err;
+use rustc_span::{sym, Span, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;
impl<'a, 'hir> LoweringContext<'a, 'hir> {
crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
- // Rustdoc needs to support asm! from foriegn architectures: don't try
- // lowering the register contraints in this case.
+ // Rustdoc needs to support asm! from foreign architectures: don't try
+ // lowering the register constraints in this case.
let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
.emit();
}
+ if let Some(asm_arch) = asm_arch {
+ // Inline assembly is currently only stable for these architectures.
+ let is_stable = matches!(
+ asm_arch,
+ asm::InlineAsmArch::X86
+ | asm::InlineAsmArch::X86_64
+ | asm::InlineAsmArch::Arm
+ | asm::InlineAsmArch::AArch64
+ | asm::InlineAsmArch::RiscV32
+ | asm::InlineAsmArch::RiscV64
+ );
+ if !is_stable && !self.sess.features_untracked().asm_experimental_arch {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_experimental_arch,
+ sp,
+ "inline assembly is not stable yet on this architecture",
+ )
+ .emit();
+ }
+ }
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
&& !self.sess.opts.actually_rustdoc
@@ -27,22 +50,47 @@
.emit();
}
- let mut clobber_abi = None;
+ let mut clobber_abis = FxHashMap::default();
if let Some(asm_arch) = asm_arch {
- if let Some((abi_name, abi_span)) = asm.clobber_abi {
- match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
- Ok(abi) => clobber_abi = Some((abi, abi_span)),
+ for (abi_name, abi_span) in &asm.clobber_abis {
+ match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
+ Ok(abi) => {
+ // If the abi was already in the list, emit an error
+ match clobber_abis.get(&abi) {
+ Some((prev_name, prev_sp)) => {
+ let mut err = self.sess.struct_span_err(
+ *abi_span,
+ &format!("`{}` ABI specified multiple times", prev_name),
+ );
+ err.span_label(*prev_sp, "previously specified here");
+
+ // Multiple different abi names may actually be the same ABI
+ // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
+ let source_map = self.sess.source_map();
+ if source_map.span_to_snippet(*prev_sp)
+ != source_map.span_to_snippet(*abi_span)
+ {
+ err.note("these ABIs are equivalent on the current target");
+ }
+
+ err.emit();
+ }
+ None => {
+ clobber_abis.insert(abi, (abi_name, *abi_span));
+ }
+ }
+ }
Err(&[]) => {
self.sess
.struct_span_err(
- abi_span,
+ *abi_span,
"`clobber_abi` is not supported on this target",
)
.emit();
}
Err(supported_abis) => {
let mut err =
- self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
+ self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
let mut abis = format!("`{}`", supported_abis[0]);
for m in &supported_abis[1..] {
let _ = write!(abis, ", `{}`", m);
@@ -121,10 +169,30 @@
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
}
}
- InlineAsmOperand::Const { ref anon_const } => hir::InlineAsmOperand::Const {
- anon_const: self.lower_anon_const(anon_const),
- },
+ InlineAsmOperand::Const { ref anon_const } => {
+ if !self.sess.features_untracked().asm_const {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_const,
+ *op_sp,
+ "const operands for inline assembly are unstable",
+ )
+ .emit();
+ }
+ hir::InlineAsmOperand::Const {
+ anon_const: self.lower_anon_const(anon_const),
+ }
+ }
InlineAsmOperand::Sym { ref expr } => {
+ if !self.sess.features_untracked().asm_sym {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_sym,
+ *op_sp,
+ "sym operands for inline assembly are unstable",
+ )
+ .emit();
+ }
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
}
};
@@ -214,9 +282,7 @@
// means that we disallow passing a value in/out of the asm and
// require that the operand name an explicit register, not a
// register class.
- if reg_class.is_clobber_only(asm_arch.unwrap())
- && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
- {
+ if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
let msg = format!(
"register class `{}` can only be used as a clobber, \
not as an input or output",
@@ -308,8 +374,14 @@
// If a clobber_abi is specified, add the necessary clobbers to the
// operands list.
- if let Some((abi, abi_span)) = clobber_abi {
+ let mut clobbered = FxHashSet::default();
+ for (abi, (_, abi_span)) in clobber_abis {
for &clobber in abi.clobbered_regs() {
+ // Don't emit a clobber for a register already clobbered
+ if clobbered.contains(&clobber) {
+ continue;
+ }
+
let mut output_used = false;
clobber.overlapping_regs(|reg| {
if used_output_regs.contains_key(®) {
@@ -326,6 +398,7 @@
},
self.lower_span(abi_span),
));
+ clobbered.insert(clobber);
}
}
}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 6027027..9c57920 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -13,7 +13,7 @@
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
+use rustc_span::DUMMY_SP;
impl<'hir> LoweringContext<'_, 'hir> {
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -252,9 +252,10 @@
}
// Merge attributes into the inner expression.
if !e.attrs.is_empty() {
- let old_attrs = self.attrs.get(&ex.hir_id).map(|la| *la).unwrap_or(&[]);
+ let old_attrs =
+ self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
self.attrs.insert(
- ex.hir_id,
+ ex.hir_id.local_id,
&*self.arena.alloc_from_iter(
e.attrs
.iter()
@@ -914,14 +915,22 @@
);
}
if !self.sess.features_untracked().destructuring_assignment {
- feature_err(
+ let mut err = feature_err(
&self.sess.parse_sess,
sym::destructuring_assignment,
eq_sign_span,
"destructuring assignments are unstable",
- )
- .span_label(lhs.span, "cannot assign to this expression")
- .emit();
+ );
+ err.span_label(lhs.span, "cannot assign to this expression");
+ if self.is_in_loop_condition {
+ err.span_suggestion_verbose(
+ lhs.span.shrink_to_lo(),
+ "you might have meant to use pattern destructuring",
+ "let ".to_string(),
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ }
+ err.emit();
}
let mut assignments = vec![];
@@ -1307,16 +1316,13 @@
/// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
/// ```rust
/// {
- /// let result = match ::std::iter::IntoIterator::into_iter(<head>) {
+ /// let result = match IntoIterator::into_iter(<head>) {
/// mut iter => {
/// [opt_ident]: loop {
- /// let mut __next;
- /// match ::std::iter::Iterator::next(&mut iter) {
- /// ::std::option::Option::Some(val) => __next = val,
- /// ::std::option::Option::None => break
+ /// match Iterator::next(&mut iter) {
+ /// None => break,
+ /// Some(<pat>) => <body>,
/// };
- /// let <pat> = __next;
- /// StmtKind::Expr(<body>);
/// }
/// }
/// };
@@ -1331,136 +1337,75 @@
body: &Block,
opt_label: Option<Label>,
) -> hir::Expr<'hir> {
- let orig_head_span = head.span;
- // expand <head>
- let mut head = self.lower_expr_mut(head);
- let desugared_span = self.mark_span_with_reason(
- DesugaringKind::ForLoop(ForLoopLoc::Head),
- orig_head_span,
- None,
- );
- head.span = self.lower_span(desugared_span);
+ let head = self.lower_expr_mut(head);
+ let pat = self.lower_pat(pat);
+ let for_span =
+ self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
+ let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
+ let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
- let iter = Ident::with_dummy_span(sym::iter);
-
- let next_ident = Ident::with_dummy_span(sym::__next);
- let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
- desugared_span,
- next_ident,
- hir::BindingAnnotation::Mutable,
- );
-
- // `::std::option::Option::Some(val) => __next = val`
- let pat_arm = {
- let val_ident = Ident::with_dummy_span(sym::val);
- let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
- let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid);
- let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
- let assign = self.arena.alloc(self.expr(
- pat.span,
- hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
- ThinVec::new(),
- ));
- let some_pat = self.pat_some(pat.span, val_pat);
- self.arm(some_pat, assign)
- };
-
- // `::std::option::Option::None => break`
- let break_arm = {
+ // `None => break`
+ let none_arm = {
let break_expr =
- self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
- let pat = self.pat_none(e.span);
+ self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
+ let pat = self.pat_none(for_span);
self.arm(pat, break_expr)
};
- // `mut iter`
- let (iter_pat, iter_pat_nid) =
- self.pat_ident_binding_mode(desugared_span, iter, hir::BindingAnnotation::Mutable);
+ // Some(<pat>) => <body>,
+ let some_arm = {
+ let some_pat = self.pat_some(pat_span, pat);
+ let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
+ let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
+ self.arm(some_pat, body_expr)
+ };
- // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+ // `mut iter`
+ let iter = Ident::with_dummy_span(sym::iter);
+ let (iter_pat, iter_pat_nid) =
+ self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
+
+ // `match Iterator::next(&mut iter) { ... }`
let match_expr = {
- let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
- let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
+ let iter = self.expr_ident(head_span, iter, iter_pat_nid);
+ let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
let next_expr = self.expr_call_lang_item_fn(
- desugared_span,
+ head_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
);
- let arms = arena_vec![self; pat_arm, break_arm];
+ let arms = arena_vec![self; none_arm, some_arm];
- self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
+ self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
};
- let match_stmt = self.stmt_expr(desugared_span, match_expr);
+ let match_stmt = self.stmt_expr(for_span, match_expr);
- let next_expr = self.expr_ident(desugared_span, next_ident, next_pat_hid);
-
- // `let mut __next`
- let next_let = self.stmt_let_pat(
- None,
- desugared_span,
- None,
- next_pat,
- hir::LocalSource::ForLoopDesugar,
- );
-
- // `let <pat> = __next`
- let pat = self.lower_pat(pat);
- let pat_let = self.stmt_let_pat(
- None,
- desugared_span,
- Some(next_expr),
- pat,
- hir::LocalSource::ForLoopDesugar,
- );
-
- let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
- let body_expr = self.expr_block(body_block, ThinVec::new());
- let body_stmt = self.stmt_expr(body.span, body_expr);
-
- let loop_block = self.block_all(
- e.span,
- arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
- None,
- );
+ let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);
// `[opt_ident]: loop { ... }`
let kind = hir::ExprKind::Loop(
loop_block,
self.lower_label(opt_label),
hir::LoopSource::ForLoop,
- self.lower_span(e.span.with_hi(orig_head_span.hi())),
+ self.lower_span(for_span.with_hi(head.span.hi())),
);
- let loop_expr = self.arena.alloc(hir::Expr {
- hir_id: self.lower_node_id(e.id),
- kind,
- span: self.lower_span(e.span),
- });
+ let loop_expr =
+ self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
// `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr);
- let into_iter_span = self.mark_span_with_reason(
- DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
- orig_head_span,
- None,
- );
-
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
self.expr_call_lang_item_fn(
- into_iter_span,
+ head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
)
};
- // #82462: to correctly diagnose borrow errors, the block that contains
- // the iter expr needs to have a span that covers the loop body.
- let desugared_full_span =
- self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
-
let match_expr = self.arena.alloc(self.expr_match(
- desugared_full_span,
+ for_span,
into_iter_expr,
arena_vec![self; iter_arm],
hir::MatchSource::ForLoopDesugar,
@@ -1474,7 +1419,7 @@
// surrounding scope of the `match` since the `match` is not a terminating scope.
//
// Also, add the attributes to the outer returned expr node.
- self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into())
+ self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
}
/// Desugar `ExprKind::Try` from: `<expr>?` into:
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_ast_lowering/src/index.rs
similarity index 61%
rename from compiler/rustc_middle/src/hir/map/collector.rs
rename to compiler/rustc_ast_lowering/src/index.rs
index efebf73..8a9dad2 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -1,187 +1,107 @@
-use crate::arena::Arena;
-use crate::hir::map::Map;
-use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::definitions;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::*;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_query_system::ich::StableHashingContext;
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
use rustc_span::{Span, DUMMY_SP};
-use std::iter::repeat;
+use tracing::debug;
/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
pub(super) struct NodeCollector<'a, 'hir> {
- arena: &'hir Arena<'hir>,
-
- /// The crate
- krate: &'hir Crate<'hir>,
-
/// Source map
source_map: &'a SourceMap,
+ bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
- map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
- parenting: FxHashMap<LocalDefId, HirId>,
+ /// Outputs
+ nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
+ parenting: FxHashMap<LocalDefId, ItemLocalId>,
/// The parent of this node
- parent_node: hir::HirId,
+ parent_node: hir::ItemLocalId,
- current_dep_node_owner: LocalDefId,
+ owner: LocalDefId,
definitions: &'a definitions::Definitions,
-
- hcx: StableHashingContext<'a>,
}
-fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
- let i = k.index();
- let len = map.len();
- if i >= len {
- map.extend(repeat(None).take(i - len + 1));
- }
- debug_assert!(map[k].is_none());
- map[k] = Some(v);
-}
+pub(super) fn index_hir<'hir>(
+ sess: &Session,
+ definitions: &definitions::Definitions,
+ item: hir::OwnerNode<'hir>,
+ bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
+) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
+ let mut nodes = IndexVec::new();
+ // This node's parent should never be accessed: the owner's parent is computed by the
+ // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
+ // used.
+ nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
+ let mut collector = NodeCollector {
+ source_map: sess.source_map(),
+ definitions,
+ owner: item.def_id(),
+ parent_node: ItemLocalId::new(0),
+ nodes,
+ bodies,
+ parenting: FxHashMap::default(),
+ };
-fn hash_body(
- hcx: &mut StableHashingContext<'_>,
- item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
-) -> Fingerprint {
- let mut stable_hasher = StableHasher::new();
- hcx.while_hashing_hir_bodies(true, |hcx| {
- item_like.hash_stable(hcx, &mut stable_hasher);
- });
- stable_hasher.finish()
+ match item {
+ OwnerNode::Crate(citem) => collector.visit_mod(&citem, citem.inner, hir::CRATE_HIR_ID),
+ OwnerNode::Item(item) => collector.visit_item(item),
+ OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
+ OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
+ OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
+ };
+
+ (collector.nodes, collector.parenting)
}
impl<'a, 'hir> NodeCollector<'a, 'hir> {
- pub(super) fn root(
- sess: &'a Session,
- arena: &'hir Arena<'hir>,
- krate: &'hir Crate<'hir>,
- definitions: &'a definitions::Definitions,
- hcx: StableHashingContext<'a>,
- ) -> NodeCollector<'a, 'hir> {
- let mut collector = NodeCollector {
- arena,
- krate,
- source_map: sess.source_map(),
- parent_node: hir::CRATE_HIR_ID,
- current_dep_node_owner: CRATE_DEF_ID,
- definitions,
- hcx,
- map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
- parenting: FxHashMap::default(),
- };
- collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
-
- collector
- }
-
- pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
- // Insert bodies into the map
- for (id, body) in self.krate.bodies.iter() {
- let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
- assert!(bodies.insert(id.hir_id.local_id, body).is_none());
- }
- IndexedHir { map: self.map, parenting: self.parenting }
- }
-
- fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
- let hash = hash_body(&mut self.hcx, node);
-
- let mut nodes = IndexVec::new();
- nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
-
- debug_assert!(self.map[owner].is_none());
- self.map[owner] =
- Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() }));
- }
-
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
- debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
+ debug_assert_eq!(self.owner, hir_id.owner);
debug_assert_ne!(hir_id.local_id.as_u32(), 0);
// Make sure that the DepNode of some node coincides with the HirId
// owner of that node.
if cfg!(debug_assertions) {
- if hir_id.owner != self.current_dep_node_owner {
- let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
- Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(),
- None => format!("{:?}", node),
- };
-
- span_bug!(
- span,
- "inconsistent DepNode at `{:?}` for `{}`: \
+ if hir_id.owner != self.owner {
+ panic!(
+ "inconsistent DepNode at `{:?}` for `{:?}`: \
current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
self.source_map.span_to_diagnostic_string(span),
- node_str,
- self.definitions
- .def_path(self.current_dep_node_owner)
- .to_string_no_crate_verbose(),
- self.current_dep_node_owner,
+ node,
+ self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
+ self.owner,
self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
hir_id.owner,
)
}
}
- let nodes = self.map[hir_id.owner].as_mut().unwrap();
-
- debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
- insert_vec_map(
- &mut nodes.nodes,
- hir_id.local_id,
- ParentedNode { parent: self.parent_node.local_id, node: node },
- );
+ self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node });
}
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
+ debug_assert_eq!(parent_node_id.owner, self.owner);
let parent_node = self.parent_node;
- self.parent_node = parent_node_id;
+ self.parent_node = parent_node_id.local_id;
f(self);
self.parent_node = parent_node;
}
- fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
- let prev_owner = self.current_dep_node_owner;
- let prev_parent = self.parent_node;
-
- self.current_dep_node_owner = dep_node_owner;
- self.parent_node = HirId::make_owner(dep_node_owner);
- f(self);
- self.current_dep_node_owner = prev_owner;
- self.parent_node = prev_parent;
- }
-
fn insert_nested(&mut self, item: LocalDefId) {
- #[cfg(debug_assertions)]
- {
- let dk_parent = self.definitions.def_key(item).parent.unwrap();
- let dk_parent = LocalDefId { local_def_index: dk_parent };
- let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
- debug_assert_eq!(
- dk_parent.owner, self.parent_node.owner,
- "Different parents for {:?}",
- item
- )
- }
-
- assert_eq!(self.parenting.insert(item, self.parent_node), None);
+ self.parenting.insert(item, self.parent_node);
}
}
impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
- type Map = Map<'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
@@ -194,26 +114,24 @@
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
self.insert_nested(item.def_id);
- self.visit_item(self.krate.item(item));
}
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
self.insert_nested(item_id.def_id);
- self.visit_trait_item(self.krate.trait_item(item_id));
}
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
self.insert_nested(item_id.def_id);
- self.visit_impl_item(self.krate.impl_item(item_id));
}
fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
self.insert_nested(foreign_id.def_id);
- self.visit_foreign_item(self.krate.foreign_item(foreign_id));
}
fn visit_nested_body(&mut self, id: BodyId) {
- self.visit_body(self.krate.body(id));
+ debug_assert_eq!(id.hir_id.owner, self.owner);
+ let body = self.bodies[&id.hir_id.local_id];
+ self.visit_body(body);
}
fn visit_param(&mut self, param: &'hir Param<'hir>) {
@@ -226,8 +144,8 @@
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug!("visit_item: {:?}", i);
- self.insert_owner(i.def_id, OwnerNode::Item(i));
- self.with_dep_node_owner(i.def_id, |this| {
+ debug_assert_eq!(i.def_id, self.owner);
+ self.with_parent(i.hir_id(), |this| {
if let ItemKind::Struct(ref struct_def, _) = i.kind {
// If this is a tuple or unit-like struct, register the constructor.
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
@@ -239,8 +157,8 @@
}
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
- self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
- self.with_dep_node_owner(fi.def_id, |this| {
+ debug_assert_eq!(fi.def_id, self.owner);
+ self.with_parent(fi.hir_id(), |this| {
intravisit::walk_foreign_item(this, fi);
});
}
@@ -257,15 +175,15 @@
}
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
- self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
- self.with_dep_node_owner(ti.def_id, |this| {
+ debug_assert_eq!(ti.def_id, self.owner);
+ self.with_parent(ti.hir_id(), |this| {
intravisit::walk_trait_item(this, ti);
});
}
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
- self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
- self.with_dep_node_owner(ii.def_id, |this| {
+ debug_assert_eq!(ii.def_id, self.owner);
+ self.with_parent(ii.hir_id(), |this| {
intravisit::walk_impl_item(this, ii);
});
}
@@ -353,7 +271,8 @@
s: Span,
id: HirId,
) {
- assert_eq!(self.parent_node, id);
+ assert_eq!(self.owner, id.owner);
+ assert_eq!(self.parent_node, id.local_id);
intravisit::walk_fn(self, fk, fd, b, s, id);
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a5a4de8..692f393 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -10,6 +10,7 @@
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
+use rustc_index::vec::Idx;
use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
@@ -39,6 +40,11 @@
}
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
+ fn visit_attribute(&mut self, _: &'a Attribute) {
+ // We do not want to lower expressions that appear in attributes,
+ // as they are not accessible to the rest of the HIR.
+ }
+
fn visit_item(&mut self, item: &'a Item) {
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
@@ -48,7 +54,7 @@
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
let this = &mut ItemLowerer { lctx: this };
match item.kind {
- ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+ ItemKind::Impl(box Impl { ref of_trait, .. }) => {
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
}
_ => visit::walk_item(this, item),
@@ -99,11 +105,12 @@
) -> T {
let old_len = self.in_scope_lifetimes.len();
- let parent_generics = match self.owners[parent_hir_id].unwrap().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].as_ref().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,
@@ -216,12 +223,12 @@
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Const(ty, body_id)
}
- ItemKind::Fn(box FnKind(
- _,
- FnSig { ref decl, header, span: fn_sig_span },
+ ItemKind::Fn(box Fn {
+ sig: FnSig { ref decl, header, span: fn_sig_span },
ref generics,
ref body,
- )) => {
+ ..
+ }) => {
let fn_def_id = self.resolver.local_def_id(id);
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);
@@ -271,7 +278,7 @@
ItemKind::GlobalAsm(ref asm) => {
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
}
- ItemKind::TyAlias(box TyAliasKind(_, ref gen, _, Some(ref ty))) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
// We lower
//
// type Foo = impl Trait
@@ -286,10 +293,10 @@
capturable_lifetimes: &mut FxHashSet::default(),
},
);
- let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
+ let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
}
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, None)) => {
+ 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());
hir::ItemKind::TyAlias(ty, generics)
@@ -316,7 +323,7 @@
self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness,
@@ -382,13 +389,13 @@
items: new_impl_items,
})
}
- ItemKind::Trait(box TraitKind(
+ ItemKind::Trait(box Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
ref items,
- )) => {
+ }) => {
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
let items = self
.arena
@@ -493,7 +500,7 @@
let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
let vis = this.rebuild_vis(&vis);
if let Some(attrs) = attrs {
- this.attrs.insert(hir::HirId::make_owner(new_id), attrs);
+ this.attrs.insert(hir::ItemLocalId::new(0), attrs);
}
let item = hir::Item {
@@ -568,7 +575,7 @@
let kind =
this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
if let Some(attrs) = attrs {
- this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs);
+ this.attrs.insert(hir::ItemLocalId::new(0), attrs);
}
let item = hir::Item {
@@ -653,7 +660,7 @@
def_id,
ident: self.lower_ident(i.ident),
kind: match i.kind {
- ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => {
+ ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
@@ -770,13 +777,13 @@
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 FnKind(_, ref sig, ref generics, None)) => {
+ 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);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, Some(ref body))) => {
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
let asyncness = sig.header.asyncness;
let body_id =
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
@@ -789,8 +796,8 @@
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
- AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref default)) => {
- let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
+ 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 kind = hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
@@ -816,11 +823,11 @@
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
let (kind, has_default) = match &i.kind {
AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
- AssocItemKind::TyAlias(box TyAliasKind(_, _, _, default)) => {
- (hir::AssocItemKind::Type, default.is_some())
+ AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
+ (hir::AssocItemKind::Type, ty.is_some())
}
- AssocItemKind::Fn(box FnKind(_, sig, _, default)) => {
- (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, default.is_some())
+ AssocItemKind::Fn(box Fn { sig, body, .. }) => {
+ (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
}
AssocItemKind::MacCall(..) => unimplemented!(),
};
@@ -851,7 +858,7 @@
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
)
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
let body_id =
@@ -867,7 +874,7 @@
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = match ty {
None => {
@@ -918,7 +925,7 @@
kind: match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
- AssocItemKind::Fn(box FnKind(_, sig, ..)) => {
+ AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
@@ -971,7 +978,8 @@
) -> hir::BodyId {
let body = hir::Body { generator_kind: self.generator_kind, params, value };
let id = body.id();
- self.bodies.insert(id, body);
+ debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
+ self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
id
}
@@ -1124,7 +1132,7 @@
//
// If this is the simple case, this parameter will end up being the same as the
// original parameter, but with a different pattern id.
- let stmt_attrs = this.attrs.get(¶meter.hir_id).copied();
+ let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied();
let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
let new_parameter = hir::Param {
hir_id: parameter.hir_id,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 245199e..2b3a538 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -33,16 +33,19 @@
#![feature(crate_visibility_modifier)]
#![feature(box_patterns)]
#![feature(iter_zip)]
+#![feature(never_type)]
#![recursion_limit = "256"]
-use rustc_ast::node_id::NodeMap;
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
use rustc_ast::visit;
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fingerprint::Fingerprint;
+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::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
@@ -52,18 +55,18 @@
use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName};
use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
-use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
+use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
-use std::collections::BTreeMap;
use tracing::{debug, trace};
macro_rules! arena_vec {
@@ -76,11 +79,12 @@
mod asm;
mod block;
mod expr;
+mod index;
mod item;
mod pat;
mod path;
-rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx);
+rustc_hir::arena_types!(rustc_arena::declare_arena);
struct LoweringContext<'a, 'hir: 'a> {
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
@@ -97,13 +101,14 @@
arena: &'hir Arena<'hir>,
/// The items being lowered are collected here.
- owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
- bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
+ owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
+ /// Bodies inside the owner being lowered.
+ bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
+ /// Attributes inside the owner being lowered.
+ attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
generator_kind: Option<hir::GeneratorKind>,
- attrs: BTreeMap<hir::HirId, &'hir [Attribute]>,
-
/// When inside an `async` context, this is the `HirId` of the
/// `task_context` local bound to the resume argument of the generator.
task_context: Option<hir::HirId>,
@@ -152,6 +157,9 @@
item_local_id_counter: hir::ItemLocalId,
node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
+ /// NodeIds that are lowered inside the current HIR owner.
+ local_node_ids: Vec<NodeId>,
+
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
}
@@ -178,11 +186,13 @@
/// This should only return `None` during testing.
fn definitions(&mut self) -> &mut Definitions;
+ fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
+
fn lint_buffer(&mut self) -> &mut LintBuffer;
fn next_node_id(&mut self) -> NodeId;
- fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
+ fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<hir::TraitCandidate>>;
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
@@ -200,37 +210,6 @@
) -> LocalDefId;
}
-struct LoweringHasher<'a> {
- source_map: CachingSourceMapView<'a>,
- resolver: &'a dyn ResolverAstLowering,
-}
-
-impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
- #[inline]
- fn hash_spans(&self) -> bool {
- true
- }
-
- #[inline]
- fn def_span(&self, id: LocalDefId) -> Span {
- self.resolver.def_span(id)
- }
-
- #[inline]
- fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
- self.resolver.def_path_hash(def_id)
- }
-
- #[inline]
- fn span_data_to_lines_and_cols(
- &mut self,
- span: &rustc_span::SpanData,
- ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
- {
- self.source_map.span_data_to_lines_and_cols(span)
- }
-}
-
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
#[derive(Debug)]
@@ -314,14 +293,15 @@
) -> &'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());
LoweringContext {
sess,
resolver,
nt_to_tokenstream,
arena,
- owners: IndexVec::default(),
- bodies: BTreeMap::new(),
- attrs: BTreeMap::default(),
+ owners,
+ bodies: Vec::new(),
+ attrs: SortedMap::new(),
catch_scope: None,
loop_scope: None,
is_in_loop_condition: false,
@@ -331,6 +311,7 @@
current_hir_id_owner: CRATE_DEF_ID,
item_local_id_counter: hir::ItemLocalId::new(0),
node_id_to_hir_id: IndexVec::new(),
+ local_node_ids: Vec::new(),
generator_kind: None,
task_context: None,
current_item: None,
@@ -420,13 +401,7 @@
hir::OwnerNode::Crate(lctx.arena.alloc(module))
});
- let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
- for (k, v) in self.resolver.take_trait_map().into_iter() {
- if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
- let map = trait_map.entry(hir_id.owner).or_default();
- map.insert(hir_id.local_id, v.into_boxed_slice());
- }
- }
+ let hir_hash = self.compute_hir_hash();
let mut def_id_to_hir_id = IndexVec::default();
@@ -441,24 +416,29 @@
self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
- #[cfg(debug_assertions)]
- for (&id, attrs) in self.attrs.iter() {
- // Verify that we do not store empty slices in the map.
- if attrs.is_empty() {
- panic!("Stored empty attributes for {:?}", id);
- }
- }
-
- let krate =
- hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs };
+ let krate = hir::Crate { owners: self.owners, hir_hash };
self.arena.alloc(krate)
}
- fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
- LoweringHasher {
- source_map: CachingSourceMapView::new(self.sess.source_map()),
- resolver: self.resolver,
- }
+ /// Compute the hash for the HIR of the full crate.
+ /// This hash will then be part of the crate_hash which is stored in the metadata.
+ fn compute_hir_hash(&mut self) -> Fingerprint {
+ let definitions = self.resolver.definitions();
+ let mut hir_body_nodes: Vec<_> = self
+ .owners
+ .iter_enumerated()
+ .filter_map(|(def_id, info)| {
+ let info = info.as_ref()?;
+ let def_path_hash = definitions.def_path_hash(def_id);
+ Some((def_path_hash, info))
+ })
+ .collect();
+ hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+
+ let mut stable_hasher = StableHasher::new();
+ let mut hcx = self.resolver.create_stable_hashing_context();
+ hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
+ stable_hasher.finish()
}
fn with_hir_id_owner(
@@ -468,25 +448,93 @@
) -> LocalDefId {
let def_id = self.resolver.local_def_id(owner);
- // Always allocate the first `HirId` for the owner itself.
- let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
- debug_assert_eq!(_old, None);
-
+ let current_attrs = std::mem::take(&mut self.attrs);
+ let current_bodies = std::mem::take(&mut self.bodies);
+ let current_node_ids = std::mem::take(&mut self.local_node_ids);
let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
let current_local_counter =
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
- let item = f(self);
+ // Always allocate the first `HirId` for the owner itself.
+ let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
+ debug_assert_eq!(_old, None);
+ self.local_node_ids.push(owner);
+ let item = f(self);
+ debug_assert_eq!(def_id, item.def_id());
+ let info = self.make_owner_info(item);
+
+ self.attrs = current_attrs;
+ self.bodies = current_bodies;
+ self.local_node_ids = current_node_ids;
self.current_hir_id_owner = current_owner;
self.item_local_id_counter = current_local_counter;
- let _old = self.owners.insert(def_id, item);
+ let _old = self.owners.insert(def_id, info);
debug_assert!(_old.is_none());
def_id
}
+ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
+ 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 trait_map = local_node_ids
+ .into_iter()
+ .filter_map(|node_id| {
+ let hir_id = self.node_id_to_hir_id[node_id]?;
+ let traits = self.resolver.take_trait_map(node_id)?;
+ Some((hir_id.local_id, traits.into_boxed_slice()))
+ })
+ .collect();
+
+ #[cfg(debug_assertions)]
+ for (id, attrs) in attrs.iter() {
+ // Verify that we do not store empty slices in the map.
+ if attrs.is_empty() {
+ panic!("Stored empty attributes for {:?}", id);
+ }
+ }
+
+ bodies.sort_by_key(|(k, _)| *k);
+ let bodies = SortedMap::from_presorted_elements(bodies);
+ 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 attrs = {
+ let mut hcx = self.resolver.create_stable_hashing_context();
+ let mut stable_hasher = StableHasher::new();
+ attrs.hash_stable(&mut hcx, &mut stable_hasher);
+ let hash = stable_hasher.finish();
+ hir::AttributeMap { map: attrs, hash }
+ };
+
+ hir::OwnerInfo { nodes, parenting, attrs, trait_map }
+ }
+
+ /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
+ /// queries which depend on the full HIR tree and those which only depend on the item signature.
+ fn hash_owner(
+ &mut self,
+ node: hir::OwnerNode<'hir>,
+ bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
+ ) -> (Fingerprint, Fingerprint) {
+ let mut hcx = self.resolver.create_stable_hashing_context();
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let hash_including_bodies = stable_hasher.finish();
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let hash_without_bodies = stable_hasher.finish();
+ (hash_including_bodies, hash_without_bodies)
+ }
+
/// This method allocates a new `HirId` for the given `NodeId` and stores it in
/// the `LoweringContext`'s `NodeId => HirId` map.
/// Take care not to call this method if the resulting `HirId` is then not
@@ -501,6 +549,7 @@
let owner = self.current_hir_id_owner;
let local_id = self.item_local_id_counter;
self.item_local_id_counter.increment_by(1);
+ self.local_node_ids.push(ast_node_id);
hir::HirId { owner, local_id }
})
}
@@ -547,7 +596,7 @@
allow_internal_unstable,
reason,
self.sess.edition(),
- self.create_stable_hashing_context(),
+ self.resolver.create_stable_hashing_context(),
)
}
@@ -791,9 +840,10 @@
if attrs.is_empty() {
None
} else {
+ debug_assert_eq!(id.owner, self.current_hir_id_owner);
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
debug_assert!(!ret.is_empty());
- self.attrs.insert(id, ret);
+ self.attrs.insert(id.local_id, ret);
Some(ret)
}
}
@@ -819,9 +869,11 @@
}
fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
- if let Some(&a) = self.attrs.get(&target_id) {
+ debug_assert_eq!(id.owner, self.current_hir_id_owner);
+ debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
+ if let Some(&a) = self.attrs.get(&target_id.local_id) {
debug_assert!(!a.is_empty());
- self.attrs.insert(id, a);
+ self.attrs.insert(id.local_id, a);
}
}
@@ -1286,10 +1338,7 @@
pure_wrt_drop: false,
bounds: hir_bounds,
span: self.lower_span(span),
- kind: hir::GenericParamKind::Type {
- default: None,
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- },
+ kind: hir::GenericParamKind::Type { default: None, synthetic: true },
});
hir::TyKind::Path(hir::QPath::Resolved(
@@ -1435,7 +1484,7 @@
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
def_id: opaque_ty_id,
- ident: Ident::invalid(),
+ ident: Ident::empty(),
kind: opaque_ty_item_kind,
vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
span: self.lower_span(opaque_ty_span),
@@ -1902,12 +1951,7 @@
default: default.as_ref().map(|x| {
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other))
}),
- synthetic: param
- .attrs
- .iter()
- .filter(|attr| attr.has_name(sym::rustc_synthetic))
- .map(|_| hir::SyntheticTyParamKind::FromAttr)
- .next(),
+ synthetic: false,
};
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
@@ -2066,7 +2110,7 @@
let hir_id = self.next_id();
if let Some(a) = attrs {
debug_assert!(!a.is_empty());
- self.attrs.insert(hir_id, a);
+ self.attrs.insert(hir_id.local_id, a);
}
let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 968e9fa..1822ba6 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -113,7 +113,7 @@
if sess.opts.unstable_features.is_nightly_build() {
sess.struct_span_err(expr.span, "`let` expressions are not supported here")
.note("only supported directly in conditions of `if`- and `while`-expressions")
- .note("as well as when nested within `&&` and parenthesis in those conditions")
+ .note("as well as when nested within `&&` and parentheses in those conditions")
.emit();
} else {
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
@@ -1064,7 +1064,7 @@
}
match item.kind {
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness: _,
@@ -1111,7 +1111,7 @@
});
return; // Avoid visiting again.
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness,
@@ -1152,8 +1152,8 @@
.emit();
}
}
- ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
- self.check_defaultness(item.span, def);
+ ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
+ self.check_defaultness(item.span, defaultness);
if body.is_none() {
let msg = "free function without a body";
@@ -1195,19 +1195,13 @@
}
}
}
- ItemKind::Trait(box TraitKind(
- is_auto,
- _,
- ref generics,
- ref bounds,
- ref trait_items,
- )) => {
+ ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
if is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
self.deny_generic_params(generics, item.ident.span);
self.deny_super_traits(bounds, item.ident.span);
self.deny_where_clause(&generics.where_clause, item.ident.span);
- self.deny_items(trait_items, item.ident.span);
+ self.deny_items(items, item.ident.span);
}
self.no_questions_in_bounds(bounds, "supertraits", true);
@@ -1217,7 +1211,7 @@
self.visit_ident(item.ident);
self.visit_generics(generics);
self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
- walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
+ walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs);
return;
}
@@ -1278,9 +1272,9 @@
let msg = "free static item without body";
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
}
- ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => {
- self.check_defaultness(item.span, def);
- if body.is_none() {
+ ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
+ self.check_defaultness(item.span, defaultness);
+ if ty.is_none() {
let msg = "free type alias without body";
self.error_item_without_body(item.span, "type", msg, " = <type>;");
}
@@ -1294,15 +1288,15 @@
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match &fi.kind {
- ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => {
- self.check_defaultness(fi.span, *def);
+ ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
+ self.check_defaultness(fi.span, *defaultness);
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
self.check_foreign_item_ascii_only(fi.ident);
}
- ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => {
- self.check_defaultness(fi.span, *def);
- self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
+ ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
+ self.check_defaultness(fi.span, *defaultness);
+ self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
self.check_type_no_bounds(bounds, "`extern` blocks");
self.check_foreign_ty_genericless(generics);
self.check_foreign_item_ascii_only(fi.ident);
@@ -1587,11 +1581,11 @@
AssocItemKind::Const(_, _, body) => {
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
}
- AssocItemKind::Fn(box FnKind(_, _, _, body)) => {
+ AssocItemKind::Fn(box Fn { body, .. }) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
- AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => {
- self.check_impl_item_provided(item.span, body, "type", " = <type>;");
+ AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
+ self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
self.check_type_no_bounds(bounds, "`impl`s");
}
_ => {}
@@ -1600,7 +1594,7 @@
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.invalid_visibility(&item.vis, None);
- if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind {
+ if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
}
@@ -1611,7 +1605,7 @@
}
match item.kind {
- AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
+ AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
if ctxt == AssocCtxt::Trait =>
{
self.visit_vis(&item.vis);
@@ -1623,7 +1617,7 @@
});
walk_list!(self, visit_ty, ty);
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
if self.in_const_trait_impl
|| ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) =>
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 91b4597..ad539f2 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -3,7 +3,7 @@
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
-use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
use rustc_session::parse::{feature_err, feature_err_issue};
use rustc_session::Session;
@@ -301,11 +301,14 @@
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
- let attr_info =
- attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+ let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check feature gates for built-in attributes.
- if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
- gate_feature_fn!(self, has_feature, attr.span, name, descr);
+ if let Some(BuiltinAttribute {
+ gate: AttributeGate::Gated(_, name, descr, has_feature),
+ ..
+ }) = attr_info
+ {
+ gate_feature_fn!(self, has_feature, attr.span, *name, descr);
}
// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {
@@ -322,8 +325,12 @@
cfg_hide => doc_cfg_hide
masked => doc_masked
notable_trait => doc_notable_trait
- keyword => doc_keyword
);
+
+ if nested_meta.has_name(sym::keyword) {
+ let msg = "`#[doc(keyword)]` is meant for internal use only";
+ gate_feature_post!(self, rustdoc_internals, attr.span, msg);
+ }
}
}
@@ -423,9 +430,7 @@
}
}
- ast::ItemKind::Impl(box ast::ImplKind {
- polarity, defaultness, ref of_trait, ..
- }) => {
+ ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
&self,
@@ -441,7 +446,7 @@
}
}
- ast::ItemKind::Trait(box ast::TraitKind(ast::IsAuto::Yes, ..)) => {
+ ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => {
gate_feature_post!(
&self,
auto_traits,
@@ -459,7 +464,7 @@
gate_feature_post!(&self, decl_macro, i.span, msg);
}
- ast::ItemKind::TyAlias(box ast::TyAliasKind(_, _, _, Some(ref ty))) => {
+ ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ref ty), .. }) => {
self.check_impl_trait(&ty)
}
@@ -541,15 +546,13 @@
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
- ast::ExprKind::Block(_, opt_label) => {
- if let Some(label) = opt_label {
- gate_feature_post!(
- &self,
- label_break_value,
- label.ident.span,
- "labels on blocks are unstable"
- );
- }
+ ast::ExprKind::Block(_, Some(label)) => {
+ gate_feature_post!(
+ &self,
+ label_break_value,
+ label.ident.span,
+ "labels on blocks are unstable"
+ );
}
_ => {}
}
@@ -634,7 +637,7 @@
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
let is_fn = match i.kind {
ast::AssocItemKind::Fn(_) => true,
- ast::AssocItemKind::TyAlias(box ast::TyAliasKind(_, ref generics, _, ref ty)) => {
+ ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
@@ -720,6 +723,7 @@
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
+ gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
gate_all!(
const_generics_defaults,
"default values for const generic parameters are experimental"
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index c248820..f1f2387 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1044,15 +1044,27 @@
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::ForeignItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
- self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+ ast::ForeignItemKind::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::TyAliasKind(def, generics, bounds, ty)) => {
- self.print_associated_type(ident, generics, bounds, ty.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);
@@ -1156,9 +1168,17 @@
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::FnKind(def, ref sig, ref gen, ref body)) => {
+ 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, gen, &item.vis, def, body, &item.attrs);
+ 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| {
@@ -1203,9 +1223,21 @@
self.print_inline_asm(asm);
self.end();
}
- ast::ItemKind::TyAlias(box ast::TyAliasKind(def, ref generics, ref bounds, ref ty)) => {
+ 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, def);
+ 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);
@@ -1218,7 +1250,7 @@
self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, item.ident, item.span, true);
}
- ast::ItemKind::Impl(box ast::ImplKind {
+ ast::ItemKind::Impl(box ast::Impl {
unsafety,
polarity,
defaultness,
@@ -1261,13 +1293,14 @@
}
self.bclose(item.span);
}
- ast::ItemKind::Trait(box ast::TraitKind(
+ ast::ItemKind::Trait(box ast::Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
- ref trait_items,
- )) => {
+ ref items,
+ ..
+ }) => {
self.head("");
self.print_visibility(&item.vis);
self.print_unsafety(unsafety);
@@ -1290,7 +1323,7 @@
self.s.word(" ");
self.bopen();
self.print_inner_attributes(&item.attrs);
- for trait_item in trait_items {
+ for trait_item in items {
self.print_assoc_item(trait_item);
}
self.bclose(item.span);
@@ -1405,11 +1438,7 @@
}
}
- crate fn print_record_struct_body(
- &mut self,
- fields: &Vec<ast::FieldDef>,
- span: rustc_span::Span,
- ) {
+ crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();
@@ -1483,14 +1512,21 @@
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::AssocItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
- self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+ ast::AssocItemKind::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::TyAliasKind(def, generics, bounds, ty)) => {
- self.print_associated_type(ident, generics, bounds, ty.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);
@@ -1675,7 +1711,7 @@
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
}
- // Does `expr` need parenthesis when printed in a condition position?
+ // 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) {}`.
@@ -2199,8 +2235,8 @@
let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
- if let Some((abi, _)) = asm.clobber_abi {
- args.push(AsmArg::ClobberAbi(abi));
+ for (abi, _) in &asm.clobber_abis {
+ args.push(AsmArg::ClobberAbi(*abi));
}
if !asm.options.is_empty() {
args.push(AsmArg::Options(asm.options));
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index ee2ce1d..952e18c 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -12,22 +12,22 @@
use std::fmt;
use std::ops::Index;
-crate struct BorrowSet<'tcx> {
+pub struct BorrowSet<'tcx> {
/// The fundamental map relating bitvector indexes to the borrows
/// in the MIR. Each borrow is also uniquely identified in the MIR
/// by the `Location` of the assignment statement in which it
/// appears on the right hand side. Thus the location is the map
/// key, and its position in the map corresponds to `BorrowIndex`.
- crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
+ pub location_map: FxIndexMap<Location, BorrowData<'tcx>>,
/// Locations which activate borrows.
/// NOTE: a given location may activate more than one borrow in the future
/// when more general two-phase borrow support is introduced, but for now we
/// only need to store one borrow index.
- crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+ pub activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
/// Map from local to all the borrows on that local.
- crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+ pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
crate locals_state_at_exit: LocalsStateAtExit,
}
@@ -43,27 +43,27 @@
/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-crate enum TwoPhaseActivation {
+pub enum TwoPhaseActivation {
NotTwoPhase,
NotActivated,
ActivatedAt(Location),
}
#[derive(Debug, Clone)]
-crate struct BorrowData<'tcx> {
+pub struct BorrowData<'tcx> {
/// Location where the borrow reservation starts.
/// In many cases, this will be equal to the activation location but not always.
- crate reserve_location: Location,
+ pub reserve_location: Location,
/// Location where the borrow is activated.
- crate activation_location: TwoPhaseActivation,
+ pub activation_location: TwoPhaseActivation,
/// What kind of borrow this is
- crate kind: mir::BorrowKind,
+ pub kind: mir::BorrowKind,
/// The region for which this borrow is live
- crate region: RegionVid,
+ pub region: RegionVid,
/// Place from which we are borrowing
- crate borrowed_place: mir::Place<'tcx>,
+ pub borrowed_place: mir::Place<'tcx>,
/// Place to which the borrow was stored
- crate assigned_place: mir::Place<'tcx>,
+ pub assigned_place: mir::Place<'tcx>,
}
impl<'tcx> fmt::Display for BorrowData<'tcx> {
@@ -78,7 +78,7 @@
}
}
-crate enum LocalsStateAtExit {
+pub enum LocalsStateAtExit {
AllAreInvalidated,
SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> },
}
@@ -315,9 +315,7 @@
// TEMP = &foo
//
// so extract `temp`.
- let temp = if let Some(temp) = assigned_place.as_local() {
- temp
- } else {
+ let Some(temp) = assigned_place.as_local() else {
span_bug!(
self.body.source_info(start_location).span,
"expected 2-phase borrow to assign to a local, not `{:?}`",
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 15309cc..1bc9f8c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -339,7 +339,7 @@
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
- let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+ let _errors = fulfill_cx.select_all_or_error(infcx);
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints);
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 3739889..46a3c0f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -11,7 +11,6 @@
};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
@@ -247,6 +246,36 @@
place_name, partially_str, loop_message
),
);
+ let sess = self.infcx.tcx.sess;
+ let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+ // If we have a `&mut` ref, we need to reborrow.
+ if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+ // If we are in a loop this will be suggested later.
+ if !is_loop_move {
+ err.span_suggestion_verbose(
+ move_span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(
+ || "the mutable reference".to_string()
+ ),
+ ),
+ "&mut *".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ } else if let Ok(snippet) =
+ sess.source_map().span_to_snippet(move_span)
+ {
+ err.span_suggestion(
+ move_span,
+ "consider borrowing to avoid moving into the for loop",
+ format!("&{}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
} else {
err.span_label(
fn_call_span,
@@ -315,35 +344,6 @@
in_pattern = true;
}
}
-
- if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
- let sess = self.infcx.tcx.sess;
- let ty = used_place.ty(self.body, self.infcx.tcx).ty;
- // If we have a `&mut` ref, we need to reborrow.
- if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
- // If we are in a loop this will be suggested later.
- if !is_loop_move {
- err.span_suggestion_verbose(
- move_span.shrink_to_lo(),
- &format!(
- "consider creating a fresh reborrow of {} here",
- self.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
- .unwrap_or_else(|| "the mutable reference".to_string()),
- ),
- "&mut *".to_string(),
- Applicability::MachineApplicable,
- );
- }
- } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
- err.span_suggestion(
- move_span,
- "consider borrowing to avoid moving into the for loop",
- format!("&{}", snippet),
- Applicability::MaybeIncorrect,
- );
- }
- }
}
use_spans.var_span_label_path_only(
@@ -408,7 +408,7 @@
let param = generics.type_param(¶m_ty, tcx);
if let Some(generics) = tcx
.hir()
- .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+ .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
{
suggest_constraining_type_param(
tcx,
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index d5de080..db8268c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -13,7 +13,7 @@
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{sym, DesugaringKind, Span};
use crate::region_infer::BlameConstraint;
use crate::{
@@ -53,10 +53,7 @@
impl BorrowExplanation {
pub(crate) fn is_explained(&self) -> bool {
- match self {
- BorrowExplanation::Unexplained => false,
- _ => true,
- }
+ !matches!(self, BorrowExplanation::Unexplained)
}
pub(crate) fn add_explanation_to_diagnostic<'tcx>(
&self,
@@ -138,7 +135,16 @@
should_note_order,
} => {
let local_decl = &body.local_decls[dropped_local];
- let (dtor_desc, type_desc) = match local_decl.ty.kind() {
+ let mut ty = local_decl.ty;
+ if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+ if let ty::Adt(adt, substs) = local_decl.ty.kind() {
+ if tcx.is_diagnostic_item(sym::Option, adt.did) {
+ // in for loop desugaring, only look at the `Some(..)` inner type
+ ty = substs.type_at(0);
+ }
+ }
+ }
+ let (dtor_desc, type_desc) = match ty.kind() {
// If type is an ADT that implements Drop, then
// simplify output by reporting just the ADT name.
ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index a4df277..79623e2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,11 +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, ForLoopLoc},
- symbol::sym,
- Span,
-};
+use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
use rustc_target::abi::VariantIdx;
use super::borrow_set::BorrowData;
@@ -955,10 +951,8 @@
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 = matches!(
- fn_call_span.desugaring_kind(),
- Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
- );
+ 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() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 855e685..692c20d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -5,11 +5,10 @@
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{FnSelfUseKind, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
@@ -400,19 +399,21 @@
| ty::Opaque(def_id, _) => def_id,
_ => return err,
};
- let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
- let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
- if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
+ let diag_name = self.infcx.tcx.get_diagnostic_name(def_id);
+ if matches!(diag_name, Some(sym::Option | sym::Result))
+ && use_spans.map_or(true, |v| !v.for_closure())
+ {
err.span_suggestion_verbose(
span.shrink_to_hi(),
- &format!(
- "consider borrowing the `{}`'s content",
- if is_option { "Option" } else { "Result" }
- ),
+ &format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
".as_ref()".to_string(),
Applicability::MaybeIncorrect,
);
- } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
+ } else if let Some(UseSpans::FnSelfUse {
+ kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+ ..
+ }) = use_spans
+ {
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
type_known_to_meet_bound_modulo_regions(
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 246d2e3..a0f8aab 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -45,12 +45,12 @@
let item_msg;
let reason;
let mut opt_source = None;
- let access_place_desc = self.describe_place(access_place.as_ref());
+ let access_place_desc = self.describe_any_place(access_place.as_ref());
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
match the_place_err {
PlaceRef { local, projection: [] } => {
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
if access_place.as_local().is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
@@ -83,7 +83,7 @@
// If we deref an immutable ref then the suggestion here doesn't help.
return;
} else {
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
@@ -96,17 +96,17 @@
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_for_guard() =>
{
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
reason = ", as it is immutable for the pattern guard".to_string();
}
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_to_static() =>
{
if access_place.projection.len() == 1 {
- item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+ item_msg = format!("immutable static item {}", access_place_desc);
reason = String::new();
} else {
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
let local_info = &self.body.local_decls[local].local_info;
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
let static_name = &self.infcx.tcx.item_name(def_id);
@@ -121,7 +121,7 @@
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
debug_assert!(
self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
);
@@ -147,7 +147,7 @@
});
let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
opt_source = Some(source);
- if let Some(desc) = access_place_desc {
+ if let Some(desc) = self.describe_place(access_place.as_ref()) {
item_msg = format!("`{}`", desc);
reason = match error_access {
AccessKind::Mutate => format!(", which is behind {}", pointer_type),
@@ -445,15 +445,27 @@
},
))) => {
// check if the RHS is from desugaring
- let locations = self.body.find_assignments(local);
- let opt_assignment_rhs_span = locations
- .first()
- .map(|&location| self.body.source_info(location).span);
- let opt_desugaring_kind =
- opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
- match opt_desugaring_kind {
+ let opt_assignment_rhs_span =
+ self.body.find_assignments(local).first().map(|&location| {
+ if let Some(mir::Statement {
+ source_info: _,
+ kind:
+ mir::StatementKind::Assign(box (
+ _,
+ mir::Rvalue::Use(mir::Operand::Copy(place)),
+ )),
+ }) = self.body[location.block]
+ .statements
+ .get(location.statement_index)
+ {
+ self.body.local_decls[place.local].source_info.span
+ } else {
+ self.body.source_info(location).span
+ }
+ });
+ match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
// on for loops, RHS points to the iterator part
- Some(DesugaringKind::ForLoop(_)) => {
+ Some(DesugaringKind::ForLoop) => {
self.suggest_similar_mut_method_for_for_loop(&mut err);
Some((
false,
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index b15e55c..723b57e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -90,9 +90,7 @@
let mut unified_already = FxHashSet::default();
for (fr, outlived) in &self.constraints_to_add {
- let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) {
- fr_name
- } else {
+ let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else {
continue;
};
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index e626015..76d3a83 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2,11 +2,11 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
@@ -63,7 +63,7 @@
use self::path_utils::*;
-mod borrow_set;
+pub mod borrow_set;
mod borrowck_errors;
mod constraint_generation;
mod constraints;
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index e5924f9..6ffab16 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -376,7 +376,7 @@
errors_buffer: &mut Vec<Diagnostic>,
) {
let tcx = infcx.tcx;
- let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+ let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
return;
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 21c26af..b39a28f 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -569,7 +569,7 @@
// to store those. Otherwise, we'll pass in `None` to the
// functions below, which will trigger them to report errors
// eagerly.
- let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+ let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
@@ -689,6 +689,16 @@
// them down.
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
+ // Convert to the SCC representative: sometimes we have inference
+ // variables in the member constraint that wind up equated with
+ // universal regions. The scc representative is the minimal numbered
+ // one from the corresponding scc so it will be the universal region
+ // if one exists.
+ for c_r in &mut choice_regions {
+ let scc = self.constraint_sccs.scc(*c_r);
+ *c_r = self.scc_representatives[scc];
+ }
+
// The 'member region' in a member constraint is part of the
// hidden type, which must be in the root universe. Therefore,
// it cannot have any placeholders in its value.
@@ -2100,14 +2110,14 @@
_ => constraint_sup_scc != target_scc,
}
} else {
- match categorized_path[*i].category {
+ !matches!(
+ categorized_path[*i].category,
ConstraintCategory::OpaqueType
- | ConstraintCategory::Boring
- | ConstraintCategory::BoringNoLocation
- | ConstraintCategory::Internal
- | ConstraintCategory::Predicate(_) => false,
- _ => true,
- }
+ | ConstraintCategory::Boring
+ | ConstraintCategory::BoringNoLocation
+ | ConstraintCategory::Internal
+ | ConstraintCategory::Predicate(_)
+ )
}
};
@@ -2219,7 +2229,7 @@
tcx,
closure_substs,
self.num_external_vids,
- tcx.closure_base_def_id(closure_def_id),
+ tcx.typeck_root_def_id(closure_def_id),
);
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 8819039..100ac57 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -60,6 +60,11 @@
PointIndex::new(start_index)
}
+ /// Return the PointIndex for the block start of this index.
+ crate fn to_block_start(&self, index: PointIndex) -> PointIndex {
+ PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
+ }
+
/// Converts a `PointIndex` back to a location. O(1).
crate fn to_location(&self, index: PointIndex) -> Location {
assert!(index.index() < self.num_points);
@@ -76,29 +81,6 @@
crate fn point_in_range(&self, index: PointIndex) -> bool {
index.index() < self.num_points
}
-
- /// Pushes all predecessors of `index` onto `stack`.
- crate fn push_predecessors(
- &self,
- body: &Body<'_>,
- index: PointIndex,
- stack: &mut Vec<PointIndex>,
- ) {
- let Location { block, statement_index } = self.to_location(index);
- if statement_index == 0 {
- // If this is a basic block head, then the predecessors are
- // the terminators of other basic blocks
- stack.extend(
- body.predecessors()[block]
- .iter()
- .map(|&pred_bb| body.terminator_loc(pred_bb))
- .map(|pred_loc| self.point_from_location(pred_loc)),
- );
- } else {
- // Otherwise, the pred is just the previous statement
- stack.push(PointIndex::new(index.index() - 1));
- }
- }
}
rustc_index::newtype_index! {
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 7d4df59..0fa72ed 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -94,6 +94,7 @@
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}))),
locations,
category,
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 84fa9bb..8d97c3c 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -1,20 +1,18 @@
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::free_regions::FreeRegionRelations;
use rustc_infer::infer::outlives;
use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
use crate::{
- nll::ToRegionVid,
type_check::constraint_conversion,
type_check::{Locations, MirTypeckRegionConstraints},
universal_regions::UniversalRegions,
@@ -381,21 +379,3 @@
}
}
}
-
-/// This trait is used by the `impl-trait` constraint code to abstract
-/// over the `FreeRegionMap` from lexical regions and
-/// `UniversalRegions` (from NLL)`.
-impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
- fn sub_free_regions(
- &self,
- _tcx: TyCtxt<'tcx>,
- shorter: ty::Region<'tcx>,
- longer: ty::Region<'tcx>,
- ) -> bool {
- let shorter = shorter.to_region_vid();
- assert!(self.universal_regions.is_universal_region(shorter));
- let longer = longer.to_region_vid();
- assert!(self.universal_regions.is_universal_region(longer));
- self.outlives(longer, shorter)
- }
-}
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 2433269..92d2d04 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,13 +7,16 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
+use crate::type_check::constraint_conversion::ConstraintConversion;
use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
use rustc_span::Span;
-use rustc_trait_selection::traits::query::normalize::AtExt;
+use rustc_span::DUMMY_SP;
+use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
+use rustc_trait_selection::traits::query::Fallible;
+use type_op::TypeOpOutput;
use crate::universal_regions::UniversalRegions;
@@ -30,6 +33,9 @@
let (&normalized_output_ty, normalized_input_tys) =
normalized_inputs_and_output.split_last().unwrap();
+ debug!(?normalized_output_ty);
+ debug!(?normalized_input_tys);
+
let mir_def_id = body.source.def_id().expect_local();
// If the user explicitly annotated the input types, extract
@@ -75,10 +81,12 @@
.delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
break;
}
+
// In MIR, argument N is stored in local N+1.
let local = Local::new(argument_index + 1);
let mir_input_ty = body.local_decls[local].ty;
+
let mir_input_span = body.local_decls[local].source_info.span;
self.equate_normalized_input_or_output(
normalized_input_ty,
@@ -100,6 +108,7 @@
// If the user explicitly annotated the input types, enforce those.
let user_provided_input_ty =
self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
+
self.equate_normalized_input_or_output(
user_provided_input_ty,
mir_input_ty,
@@ -167,30 +176,14 @@
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
// like to normalize *before* inserting into `local_decls`, but
// doing so ends up causing some other trouble.
- let b = match self
- .infcx
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .normalize(b)
- {
- Ok(n) => {
- debug!("equate_inputs_and_outputs: {:?}", n);
- if n.obligations.iter().all(|o| {
- matches!(
- o.predicate.kind().skip_binder(),
- ty::PredicateKind::RegionOutlives(_)
- | ty::PredicateKind::TypeOutlives(_)
- )
- }) {
- n.value
- } else {
- b
- }
- }
+ let b = match self.normalize_and_add_constraints(b) {
+ Ok(n) => n,
Err(_) => {
debug!("equate_inputs_and_outputs: NoSolution");
b
}
};
+
// Note: if we have to introduce new placeholders during normalization above, then we won't have
// added those universes to the universe info, which we would want in `relate_tys`.
if let Err(terr) =
@@ -207,4 +200,27 @@
}
}
}
+
+ pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
+ let TypeOpOutput { output: norm_ty, constraints, .. } =
+ self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
+
+ debug!("{:?} normalized to {:?}", t, norm_ty);
+
+ for data in constraints.into_iter().collect::<Vec<_>>() {
+ ConstraintConversion::new(
+ self.infcx,
+ &self.borrowck_context.universal_regions,
+ &self.region_bound_pairs,
+ Some(self.implicit_region_bound),
+ self.param_env,
+ Locations::All(DUMMY_SP),
+ ConstraintCategory::Internal,
+ &mut self.borrowck_context.constraints,
+ )
+ .convert_all(&*data);
+ }
+
+ Ok(norm_ty)
+ }
}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 1671c7c..73c2840 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -205,12 +205,42 @@
self.stack.extend(self.cx.local_use_map.uses(local));
while let Some(p) = self.stack.pop() {
- if self.defs.contains(p) {
- continue;
- }
+ // We are live in this block from the closest to us of:
+ //
+ // * Inclusively, the block start
+ // * Exclusively, the previous definition (if it's in this block)
+ // * Exclusively, the previous live_at setting (an optimization)
+ let block_start = self.cx.elements.to_block_start(p);
+ let previous_defs = self.defs.last_set_in(block_start..=p);
+ let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
- if self.use_live_at.insert(p) {
- self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack)
+ let exclusive_start = match (previous_defs, previous_live_at) {
+ (Some(a), Some(b)) => Some(std::cmp::max(a, b)),
+ (Some(a), None) | (None, Some(a)) => Some(a),
+ (None, None) => None,
+ };
+
+ if let Some(exclusive) = exclusive_start {
+ self.use_live_at.insert_range(exclusive + 1..=p);
+
+ // If we have a bound after the start of the block, we should
+ // not add the predecessors for this block.
+ continue;
+ } else {
+ // Add all the elements of this block.
+ self.use_live_at.insert_range(block_start..=p);
+
+ // Then add the predecessors for this block, which are the
+ // terminators of predecessor basic blocks. Push those onto the
+ // stack so that the next iteration(s) will process them.
+
+ let block = self.cx.elements.to_location(block_start).block;
+ self.stack.extend(
+ self.cx.body.predecessors()[block]
+ .iter()
+ .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
+ .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
+ );
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 7bf1198..da26d9c7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -10,6 +10,7 @@
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
@@ -36,7 +37,6 @@
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -185,7 +185,6 @@
®ion_bound_pairs,
implicit_region_bound,
&mut borrowck_context,
- &universal_region_relations,
|mut cx| {
cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
@@ -253,15 +252,7 @@
}
#[instrument(
- skip(
- infcx,
- body,
- promoted,
- region_bound_pairs,
- borrowck_context,
- universal_region_relations,
- extra
- ),
+ skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
level = "debug"
)]
fn type_check_internal<'a, 'tcx, R>(
@@ -272,7 +263,6 @@
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- universal_region_relations: &'a UniversalRegionRelations<'tcx>,
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
) -> R {
let mut checker = TypeChecker::new(
@@ -282,7 +272,6 @@
region_bound_pairs,
implicit_region_bound,
borrowck_context,
- universal_region_relations,
);
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
@@ -667,7 +656,7 @@
// If the region is live at at least one location in the promoted MIR,
// then add a liveness constraint to the main MIR for this region
// at the location provided as an argument to this method
- if let Some(_) = liveness_constraints.get_elements(region).next() {
+ if liveness_constraints.get_elements(region).next().is_some() {
self.cx
.borrowck_context
.constraints
@@ -901,15 +890,14 @@
implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- universal_region_relations: &'a UniversalRegionRelations<'tcx>,
}
struct BorrowCheckContext<'a, 'tcx> {
- universal_regions: &'a UniversalRegions<'tcx>,
+ pub(crate) universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a LocationTable,
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
- constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
+ pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
upvars: &'a [Upvar<'tcx>],
}
@@ -1050,7 +1038,6 @@
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- universal_region_relations: &'a UniversalRegionRelations<'tcx>,
) -> Self {
let mut checker = Self {
infcx,
@@ -1062,7 +1049,6 @@
implicit_region_bound,
borrowck_context,
reported_errors: Default::default(),
- universal_region_relations,
};
checker.check_user_type_annotations();
checker
@@ -1171,6 +1157,7 @@
self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
}
+ #[instrument(skip(self, category), level = "debug")]
fn eq_types(
&mut self,
expected: Ty<'tcx>,
@@ -1322,8 +1309,6 @@
),
)?;
- let universal_region_relations = self.universal_region_relations;
-
// Finally, if we instantiated the anon types successfully, we
// have to solve any bounds (e.g., `-> impl Iterator` needs to
// prove that `T: Iterator` where `T` is the type we
@@ -1335,12 +1320,7 @@
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|infcx| {
- infcx.constrain_opaque_type(
- opaque_type_key,
- &opaque_decl,
- GenerateMemberConstraints::IfNoStaticBound,
- universal_region_relations,
- );
+ infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
Ok(InferOk { value: (), obligations: vec![] })
},
|| "opaque_type_map".to_string(),
@@ -1365,13 +1345,9 @@
// though.
let category = match place.as_local() {
Some(RETURN_PLACE) => {
- if let BorrowCheckContext {
- universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
- ..
- } = self.borrowck_context
- {
- if tcx.is_static(*def_id) {
+ let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+ if defining_ty.is_const() {
+ if tcx.is_static(defining_ty.def_id()) {
ConstraintCategory::UseAsStatic
} else {
ConstraintCategory::UseAsConst
@@ -1549,6 +1525,8 @@
}
}
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+ self.check_operand(discr, term_location);
+
let discr_ty = discr.ty(body, tcx);
if let Err(terr) = self.sub_types(
discr_ty,
@@ -1571,6 +1549,11 @@
// FIXME: check the values
}
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+ self.check_operand(func, term_location);
+ for arg in args {
+ self.check_operand(arg, term_location);
+ }
+
let func_ty = func.ty(body, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.kind() {
@@ -1615,6 +1598,8 @@
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
}
TerminatorKind::Assert { ref cond, ref msg, .. } => {
+ self.check_operand(cond, term_location);
+
let cond_ty = cond.ty(body, tcx);
if cond_ty != tcx.types.bool {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
@@ -1630,6 +1615,8 @@
}
}
TerminatorKind::Yield { ref value, .. } => {
+ self.check_operand(value, term_location);
+
let value_ty = value.ty(body, tcx);
match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-generator"),
@@ -1672,7 +1659,12 @@
Some(RETURN_PLACE) => {
if let BorrowCheckContext {
universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+ UniversalRegions {
+ defining_ty:
+ DefiningTy::Const(def_id, _)
+ | DefiningTy::InlineConst(def_id, _),
+ ..
+ },
..
} = self.borrowck_context
{
@@ -1953,15 +1945,51 @@
}
}
+ 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 {
+ ty::ConstKind::Unevaluated(uv) => Some(uv),
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(uv) = maybe_uneval {
+ if uv.promoted.is_none() {
+ let tcx = self.tcx();
+ let def_id = uv.def.def_id_for_type_of();
+ if tcx.def_kind(def_id) == DefKind::InlineConst {
+ let predicates = self.prove_closure_bounds(
+ tcx,
+ def_id.expect_local(),
+ uv.substs(tcx),
+ location,
+ );
+ self.normalize_and_prove_instantiated_predicates(
+ def_id,
+ predicates,
+ location.to_locations(),
+ );
+ }
+ }
+ }
+ }
+ }
+
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
let tcx = self.tcx();
match rvalue {
Rvalue::Aggregate(ak, ops) => {
+ for op in ops {
+ self.check_operand(op, location);
+ }
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
}
Rvalue::Repeat(operand, len) => {
+ self.check_operand(operand, location);
+
// If the length cannot be evaluated we must assume that the length can be larger
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
@@ -2012,7 +2040,22 @@
}
}
- Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, 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, &[]),
+ };
+
+ self.prove_trait_ref(
+ trait_ref,
+ location.to_locations(),
+ ConstraintCategory::SizedBound,
+ );
+ }
+
+ Rvalue::ShallowInitBox(operand, ty) => {
+ self.check_operand(operand, location);
+
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
@@ -2026,6 +2069,8 @@
}
Rvalue::Cast(cast_kind, op, ty) => {
+ self.check_operand(op, location);
+
match cast_kind {
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
@@ -2272,6 +2317,9 @@
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
box (left, right),
) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+
let ty_left = left.ty(body, tcx);
match ty_left.kind() {
// Types with regions are comparable if they have a common super-type.
@@ -2322,13 +2370,19 @@
}
}
+ Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+ self.check_operand(operand, location);
+ }
+
+ Rvalue::BinaryOp(_, box (left, right))
+ | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+ }
+
Rvalue::AddressOf(..)
| Rvalue::ThreadLocalRef(..)
- | Rvalue::Use(..)
| Rvalue::Len(..)
- | Rvalue::BinaryOp(..)
- | Rvalue::CheckedBinaryOp(..)
- | Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => {}
}
}
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index bebd193..b986df4 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -23,7 +23,7 @@
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
use std::iter;
use crate::nll::ToRegionVid;
@@ -108,6 +108,10 @@
/// is that it has no inputs and a single return value, which is
/// the value of the constant.
Const(DefId, SubstsRef<'tcx>),
+
+ /// The MIR represents an inline const. The signature has no inputs and a
+ /// single return value found via `InlineConstSubsts::ty`.
+ InlineConst(DefId, SubstsRef<'tcx>),
}
impl<'tcx> DefiningTy<'tcx> {
@@ -121,7 +125,7 @@
DefiningTy::Generator(_, substs, _) => {
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
}
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
Either::Right(Either::Right(iter::empty()))
}
}
@@ -133,22 +137,16 @@
pub fn implicit_inputs(self) -> usize {
match self {
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
}
}
pub fn is_fn_def(&self) -> bool {
- match *self {
- DefiningTy::FnDef(..) => true,
- _ => false,
- }
+ matches!(*self, DefiningTy::FnDef(..))
}
pub fn is_const(&self) -> bool {
- match *self {
- DefiningTy::Const(..) => true,
- _ => false,
- }
+ matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
}
pub fn def_id(&self) -> DefId {
@@ -156,7 +154,8 @@
DefiningTy::Closure(def_id, ..)
| DefiningTy::Generator(def_id, ..)
| DefiningTy::FnDef(def_id, ..)
- | DefiningTy::Const(def_id, ..) => def_id,
+ | DefiningTy::Const(def_id, ..)
+ | DefiningTy::InlineConst(def_id, ..) => def_id,
}
}
}
@@ -248,7 +247,7 @@
tcx: TyCtxt<'tcx>,
closure_substs: SubstsRef<'tcx>,
expected_num_vars: usize,
- closure_base_def_id: DefId,
+ typeck_root_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.lifetimes.re_static);
@@ -256,7 +255,7 @@
region_mapping.push(fr);
});
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
region_mapping.push(r);
});
@@ -350,8 +349,8 @@
// tests, and the resulting print-outs include def-ids
// and other things that are not stable across tests!
// So we just include the region-vid. Annoying.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
@@ -365,8 +364,8 @@
// FIXME: As above, we'd like to print out the region
// `r` but doing so is not stable across architectures
// and so forth.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
@@ -382,6 +381,12 @@
tcx.def_path_str_with_substs(def_id, substs),
));
}
+ DefiningTy::InlineConst(def_id, substs) => {
+ err.note(&format!(
+ "defining inline constant type: {}",
+ tcx.def_path_str_with_substs(def_id, substs),
+ ));
+ }
}
}
}
@@ -417,7 +422,7 @@
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ 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
@@ -425,7 +430,7 @@
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- if self.mir_def.did.to_def_id() != closure_base_def_id {
+ if self.mir_def.did.to_def_id() != typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
}
@@ -443,7 +448,7 @@
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
- if self.mir_def.did.to_def_id() == closure_base_def_id {
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
}
@@ -508,12 +513,12 @@
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
- tcx.type_of(closure_base_def_id)
+ let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ tcx.type_of(typeck_root_def_id)
} else {
let tables = tcx.typeck(self.mir_def.did);
tables.node_type(self.mir_hir_id)
@@ -540,11 +545,21 @@
}
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
- assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
- let substs =
- self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
- DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ let substs =
+ self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+ DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ } else {
+ let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+ let substs = InlineConstSubsts::new(
+ tcx,
+ InlineConstSubstsParts { parent_substs: identity_substs, ty },
+ )
+ .substs;
+ let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+ DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+ }
}
}
}
@@ -559,17 +574,19 @@
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let fr_substs = match defining_ty {
- DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+ DefiningTy::Closure(_, ref substs)
+ | DefiningTy::Generator(_, ref substs, _)
+ | DefiningTy::InlineConst(_, ref substs) => {
// In the case of closures, we rely on the fact that
// the first N elements in the ClosureSubsts are
- // inherited from the `closure_base_def_id`.
+ // inherited from the `typeck_root_def_id`.
// Therefore, when we zip together (below) with
// `identity_substs`, we will get only those regions
// that correspond to early-bound regions declared on
- // the `closure_base_def_id`.
+ // the `typeck_root_def_id`.
assert!(substs.len() >= identity_substs.len());
assert_eq!(substs.regions().count(), identity_substs.regions().count());
substs
@@ -654,6 +671,12 @@
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
}
+
+ DefiningTy::InlineConst(def_id, substs) => {
+ assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ let ty = substs.as_inline_const().ty();
+ ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+ }
}
}
}
@@ -742,8 +765,8 @@
indices: &mut UniversalRegionIndices<'tcx>,
) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
- let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
- for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+ for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index c032364c..41662f4 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -19,7 +19,7 @@
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
- clobber_abi: Option<(Symbol, Span)>,
+ clobber_abis: Vec<(Symbol, Span)>,
options: ast::InlineAsmOptions,
options_spans: Vec<Span>,
}
@@ -64,7 +64,7 @@
operands: vec![],
named_args: FxHashMap::default(),
reg_args: FxHashSet::default(),
- clobber_abi: None,
+ clobber_abis: Vec::new(),
options: ast::InlineAsmOptions::empty(),
options_spans: vec![],
};
@@ -210,9 +210,9 @@
.span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
- } else if let Some((_, abi_span)) = args.clobber_abi {
+ } else if let Some((_, abi_span)) = args.clobber_abis.last() {
ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
- .span_label(abi_span, "clobber_abi")
+ .span_label(*abi_span, "clobber_abi")
.span_label(span, "argument")
.emit();
}
@@ -322,10 +322,13 @@
// Bail out now since this is likely to confuse MIR
return Err(err);
}
- if let Some((_, abi_span)) = args.clobber_abi {
+
+ if args.clobber_abis.len() > 0 {
if is_global_asm {
- let err =
- ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
+ let err = ecx.struct_span_err(
+ args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+ "`clobber_abi` cannot be used with `global_asm!`",
+ );
// Bail out now since this is likely to confuse later stages
return Err(err);
@@ -335,7 +338,10 @@
regclass_outputs.clone(),
"asm with `clobber_abi` must specify explicit registers for outputs",
)
- .span_label(abi_span, "clobber_abi")
+ .span_labels(
+ args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+ "clobber_abi",
+ )
.span_labels(regclass_outputs, "generic outputs")
.emit();
}
@@ -439,37 +445,61 @@
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
- let clobber_abi = match p.parse_str_lit() {
- Ok(str_lit) => str_lit.symbol_unescaped,
- Err(opt_lit) => {
- let span = opt_lit.map_or(p.token.span, |lit| lit.span);
- let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
- err.span_label(span, "not a string literal");
- return Err(err);
- }
- };
-
- p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
-
- let new_span = span_start.to(p.prev_token.span);
-
- if let Some((_, prev_span)) = args.clobber_abi {
- let mut err = p
- .sess
- .span_diagnostic
- .struct_span_err(new_span, "clobber_abi specified multiple times");
- err.span_label(prev_span, "clobber_abi previously specified here");
+ if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+ let err = p.sess.span_diagnostic.struct_span_err(
+ p.token.span,
+ "at least one abi must be provided as an argument to `clobber_abi`",
+ );
return Err(err);
- } else if !args.options_spans.is_empty() {
+ }
+
+ let mut new_abis = Vec::new();
+ loop {
+ match p.parse_str_lit() {
+ Ok(str_lit) => {
+ new_abis.push((str_lit.symbol_unescaped, str_lit.span));
+ }
+ Err(opt_lit) => {
+ // If the non-string literal is a closing paren then it's the end of the list and is fine
+ if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+ break;
+ }
+ let span = opt_lit.map_or(p.token.span, |lit| lit.span);
+ let mut err =
+ p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
+ err.span_label(span, "not a string literal");
+ return Err(err);
+ }
+ };
+
+ // Allow trailing commas
+ if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+ break;
+ }
+ p.expect(&token::Comma)?;
+ }
+
+ let full_span = span_start.to(p.prev_token.span);
+
+ if !args.options_spans.is_empty() {
let mut err = p
.sess
.span_diagnostic
- .struct_span_err(new_span, "clobber_abi is not allowed after options");
+ .struct_span_err(full_span, "clobber_abi is not allowed after options");
err.span_labels(args.options_spans.clone(), "options");
return Err(err);
}
- args.clobber_abi = Some((clobber_abi, new_span));
+ match &new_abis[..] {
+ // should have errored above during parsing
+ [] => unreachable!(),
+ [(abi, _span)] => args.clobber_abis.push((*abi, full_span)),
+ [abis @ ..] => {
+ for (abi, span) in abis {
+ args.clobber_abis.push((*abi, *span));
+ }
+ }
+ }
Ok(())
}
@@ -547,7 +577,7 @@
if let Some(snippet) = &template_snippet {
if let Some(pos) = snippet.find(needle) {
let end = pos
- + &snippet[pos..]
+ + snippet[pos..]
.find(|c| matches!(c, '\n' | ';' | '\\' | '"'))
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
@@ -770,7 +800,7 @@
template,
template_strs: template_strs.into_boxed_slice(),
operands: args.operands,
- clobber_abi: args.clobber_abi,
+ clobber_abis: args.clobber_abis,
options: args.options,
line_spans,
})
@@ -812,10 +842,10 @@
Ok(args) => {
if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
MacEager::items(smallvec![P(ast::Item {
- ident: Ident::invalid(),
+ ident: Ident::empty(),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
- kind: ast::ItemKind::GlobalAsm(inline_asm),
+ kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 241c90c..31a35b9 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -85,7 +85,7 @@
fn dummy_annotatable() -> Annotatable {
Annotatable::GenericParam(ast::GenericParam {
id: ast::DUMMY_NODE_ID,
- ident: Ident::invalid(),
+ ident: Ident::empty(),
attrs: Default::default(),
bounds: Default::default(),
is_placeholder: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index cd78c01..994a74a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -557,12 +557,12 @@
tokens: None,
},
attrs: Vec::new(),
- kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAliasKind(
- ast::Defaultness::Final,
- Generics::default(),
- Vec::new(),
- Some(type_def.to_ty(cx, self.span, type_ident, generics)),
- ))),
+ kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
+ defaultness: ast::Defaultness::Final,
+ generics: Generics::default(),
+ bounds: Vec::new(),
+ ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
+ })),
tokens: None,
})
});
@@ -724,9 +724,9 @@
cx.item(
self.span,
- Ident::invalid(),
+ Ident::empty(),
a,
- ast::ItemKind::Impl(Box::new(ast::ImplKind {
+ ast::ItemKind::Impl(Box::new(ast::Impl {
unsafety,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
@@ -955,7 +955,7 @@
decl: fn_decl,
span: trait_.span,
};
- let def = ast::Defaultness::Final;
+ let defaultness = ast::Defaultness::Final;
// Create the method.
P(ast::AssocItem {
@@ -968,12 +968,12 @@
tokens: None,
},
ident: method_ident,
- kind: ast::AssocItemKind::Fn(Box::new(ast::FnKind(
- def,
+ kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
+ defaultness,
sig,
- fn_generics,
- Some(body_block),
- ))),
+ generics: fn_generics,
+ body: Some(body_block),
+ })),
tokens: None,
})
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index bcf9571..367a5aa 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -2,7 +2,7 @@
use rustc_ast as ast;
use rustc_ast::ptr::P;
-use rustc_ast::{ImplKind, ItemKind, MetaItem};
+use rustc_ast::{Impl, ItemKind, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
@@ -178,9 +178,9 @@
let newitem = cx.item(
span,
- Ident::invalid(),
+ Ident::empty(),
attrs,
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index f0056cb..097eadd 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -527,17 +527,9 @@
self.verify_arg_type(Exact(idx), ty)
}
None => {
- let capture_feature_enabled = self
- .ecx
- .ecfg
- .features
- .map_or(false, |features| features.format_args_capture);
-
// For the moment capturing variables from format strings expanded from macros is
// disabled (see RFC #2795)
- let can_capture = capture_feature_enabled && self.is_literal;
-
- if can_capture {
+ if self.is_literal {
// Treat this name as a variable to capture from the surrounding scope
let idx = self.args.len();
self.arg_types.push(Vec::new());
@@ -559,23 +551,15 @@
};
let mut err = self.ecx.struct_span_err(sp, &msg[..]);
- if capture_feature_enabled && !self.is_literal {
- err.note(&format!(
- "did you intend to capture a variable `{}` from \
- the surrounding scope?",
- name
- ));
- err.note(
- "to avoid ambiguity, `format_args!` cannot capture variables \
- when the format string is expanded from a macro",
- );
- } else if self.ecx.parse_sess().unstable_features.is_nightly_build() {
- err.help(&format!(
- "if you intended to capture `{}` from the surrounding scope, add \
- `#![feature(format_args_capture)]` to the crate attributes",
- name
- ));
- }
+ err.note(&format!(
+ "did you intend to capture a variable `{}` from \
+ the surrounding scope?",
+ name
+ ));
+ err.note(
+ "to avoid ambiguity, `format_args!` cannot capture variables \
+ when the format string is expanded from a macro",
+ );
err.emit();
}
@@ -760,16 +744,11 @@
/// Actually builds the expression which the format_args! block will be
/// expanded to.
fn into_expr(self) -> P<ast::Expr> {
- let mut locals =
- Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum());
- let mut counts = Vec::with_capacity(self.count_args.len());
- let mut pats = Vec::with_capacity(self.args.len());
+ let mut 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());
- let names_pos: Vec<_> = (0..self.args.len())
- .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
- .collect();
-
// 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);
@@ -787,11 +766,8 @@
// 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() {
- let name = names_pos[i];
- let span = self.ecx.with_def_site_ctxt(e.span);
- pats.push(self.ecx.pat_ident(span, name));
for arg_ty in self.arg_unique_types[i].iter() {
- locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
heads.push(self.ecx.expr_addr_of(e.span, e));
}
@@ -800,15 +776,11 @@
Exact(i) => i,
_ => panic!("should never happen"),
};
- let name = names_pos[index];
let span = spans_pos[index];
- counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
- // Now create a vector containing all the arguments
- let args = locals.into_iter().chain(counts.into_iter());
-
- let args_array = self.ecx.expr_vec(self.macsp, args.collect());
+ let args_array = self.ecx.expr_vec(self.macsp, args);
// Constructs an AST equivalent to:
//
@@ -838,7 +810,7 @@
// 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_tuple(self.macsp, pats);
+ 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])
@@ -877,10 +849,11 @@
macsp: Span,
mut sp: Span,
ty: &ArgumentType,
- arg: Ident,
+ arg_index: usize,
) -> P<ast::Expr> {
sp = ecx.with_def_site_ctxt(sp);
- let arg = ecx.expr_ident(sp, arg);
+ 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_,
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 3f71ee6..a433876 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -5,7 +5,7 @@
};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{FnKind, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
@@ -84,13 +84,13 @@
let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
let sig = FnSig { decl, header, span: self.span };
- let block = Some(self.cx.block_expr(output_expr));
- let kind = ItemKind::Fn(Box::new(FnKind(
- ast::Defaultness::Final,
+ let body = Some(self.cx.block_expr(output_expr));
+ let kind = ItemKind::Fn(Box::new(Fn {
+ defaultness: ast::Defaultness::Final,
sig,
- Generics::default(),
- block,
- )));
+ generics: Generics::default(),
+ body,
+ }));
let item = self.cx.item(
self.span,
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index e0d5726..e106f60 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -77,7 +77,7 @@
let use_item = cx.item(
span,
- Ident::invalid(),
+ Ident::empty(),
vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
ast::ItemKind::Use(ast::UseTree {
prefix: cx.path(span, import_path),
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index bbca070..d262992 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -429,7 +429,7 @@
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
- if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, ref generics, _)) = i.kind {
+ if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
.span_label(span, "`unsafe` because of this")
@@ -478,7 +478,7 @@
}
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
- let has_sig = if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) = i.kind {
+ let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
sig.decl.inputs.len() == 1
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index d791677..64ccd43 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -313,13 +313,13 @@
let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty));
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
- let def = ast::Defaultness::Final;
- let main = ast::ItemKind::Fn(Box::new(ast::FnKind(
- def,
+ let defaultness = ast::Defaultness::Final;
+ let main = ast::ItemKind::Fn(Box::new(ast::Fn {
+ defaultness,
sig,
- ast::Generics::default(),
- Some(main_body),
- )));
+ generics: ast::Generics::default(),
+ body: Some(main_body),
+ }));
// Honor the reexport_test_harness_main attribute
let main_id = match cx.reexport_test_harness_main {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 32cc50ee..0a8d612 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -224,7 +224,7 @@
tcx,
(backend_config.clone(), cgu.name()),
module_codegen,
- rustc_middle::dep_graph::hash_result,
+ Some(rustc_middle::dep_graph::hash_result),
);
if let Some((id, product)) = work_product {
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index ce428c5..2bbb199 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -14,7 +14,7 @@
// TODO(antoyo)
}
- fn get_param(&self, index: usize) -> Self::Value {
+ fn get_param(&mut self, index: usize) -> Self::Value {
self.cx.current_func.borrow().expect("current func")
.get_param(index as i32)
.to_rvalue()
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 3b77097..7c3ed3c 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -118,7 +118,7 @@
true
}
- fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index 9f96096..a3b8d32 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -59,7 +59,13 @@
let start_time = Instant::now();
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
- let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+ let (module, _) = tcx.dep_graph.with_task(
+ dep_node,
+ tcx,
+ cgu_name,
+ module_codegen,
+ Some(dep_graph::hash_result),
+ );
let time_to_codegen = start_time.elapsed();
drop(prof_timer);
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index ac90841..fff2aa6 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -915,6 +915,16 @@
// TODO(antoyo)
}
+ fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
+ // Unsupported.
+ }
+
+ fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
+ // Unsupported.
+ self.context.new_rvalue_from_int(self.int_type, 0)
+ }
+
+
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 375d422..f3a2382 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -316,7 +316,7 @@
extended_asm.add_input_operand(None, "r", result.llval);
extended_asm.add_clobber("memory");
extended_asm.set_volatile_flag(true);
-
+
// We have copied the value to `result` already.
return;
}
@@ -363,8 +363,9 @@
cond
}
- fn sideeffect(&mut self) {
- // TODO(antoyo)
+ fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
+ // Unsupported.
+ self.context.new_rvalue_from_int(self.int_type, 0)
}
fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index a6a553b..5f3f533 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -11,7 +11,7 @@
bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
-measureme = "9.1.0"
+measureme = "10.0.0"
snap = "1"
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index dca9c1f..07adfff 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -1,7 +1,6 @@
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, AttributePlace};
-use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
@@ -53,15 +52,10 @@
}
fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
- // LLVM prior to version 12 has known miscompiles in the presence of
- // noalias attributes (see #54878). Only enable mutable noalias by
- // default for versions we believe to be safe.
- cx.tcx
- .sess
- .opts
- .debugging_opts
- .mutable_noalias
- .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0))
+ // LLVM prior to version 12 had known miscompiles in the presence of
+ // noalias attributes (see #54878), but we don't support earlier
+ // versions at all anymore. We now enable mutable noalias by default.
+ cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
}
impl ArgAttributesExt for ArgAttributes {
@@ -613,7 +607,7 @@
fn_abi.apply_attrs_callsite(self, callsite)
}
- fn get_param(&self, index: usize) -> Self::Value {
+ fn get_param(&mut self, index: usize) -> Self::Value {
llvm::get_param(self.llfn(), index as c_uint)
}
}
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 341a888..02096f4 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -13,7 +13,7 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty::Instance};
use rustc_span::{Pos, Span, Symbol};
use rustc_target::abi::*;
use rustc_target::asm::*;
@@ -120,6 +120,7 @@
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
line_spans: &[Span],
+ instance: Instance<'_>,
) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
@@ -135,7 +136,10 @@
let is_target_supported = |reg_class: InlineAsmRegClass| {
for &(_, feature) in reg_class.supported_types(asm_arch) {
if let Some(feature) = feature {
- if self.tcx.sess.target_features.contains(&Symbol::intern(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)
{
return true;
}
@@ -316,7 +320,7 @@
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::S390x => {}
InlineAsmArch::SpirV => {}
- InlineAsmArch::Wasm32 => {}
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
InlineAsmArch::Bpf => {}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 659cf9e..8e6329a 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -12,7 +12,7 @@
use rustc_session::config::OptLevel;
use rustc_session::Session;
use rustc_target::spec::abi::Abi;
-use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
+use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
use crate::attributes;
use crate::llvm::AttributePlace::Function;
@@ -161,6 +161,17 @@
}
}
+fn set_stackprotector(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+ let sspattr = match cx.sess().stack_protector() {
+ StackProtector::None => return,
+ StackProtector::All => Attribute::StackProtectReq,
+ StackProtector::Strong => Attribute::StackProtectStrong,
+ StackProtector::Basic => Attribute::StackProtect,
+ };
+
+ sspattr.apply_llfn(Function, llfn)
+}
+
pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess));
llvm::AddFunctionAttrStringValue(
@@ -271,6 +282,7 @@
set_frame_pointer_type(cx, llfn);
set_instrument_function(cx, llfn);
set_probestack(cx, llfn);
+ set_stackprotector(cx, llfn);
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
Attribute::Cold.apply_llfn(Function, llfn);
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index b6d682f..6d2ad70 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -17,6 +17,7 @@
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
+use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{FatalError, Handler, Level};
use rustc_fs_util::{link_or_copy, path_to_c_string};
@@ -53,6 +54,7 @@
output: &Path,
dwo_output: Option<&Path>,
file_type: llvm::FileType,
+ self_profiler_ref: &SelfProfilerRef,
) -> Result<(), FatalError> {
unsafe {
let output_c = path_to_c_string(output);
@@ -76,6 +78,19 @@
file_type,
)
};
+
+ // Record artifact sizes for self-profiling
+ if result == llvm::LLVMRustResult::Success {
+ let artifact_kind = match file_type {
+ llvm::FileType::ObjectFile => "object_file",
+ llvm::FileType::AssemblyFile => "assembly_file",
+ };
+ record_artifact_size(self_profiler_ref, artifact_kind, output);
+ if let Some(dwo_file) = dwo_output {
+ record_artifact_size(self_profiler_ref, "dwo_file", dwo_file);
+ }
+ }
+
result.into_result().map_err(|()| {
let msg = format!("could not write output to {}", output.display());
llvm_err(handler, &msg)
@@ -161,6 +176,7 @@
let ffunction_sections =
sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
let fdata_sections = ffunction_sections;
+ let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names;
let code_model = to_llvm_code_model(sess.code_model());
@@ -205,6 +221,7 @@
use_softfp,
ffunction_sections,
fdata_sections,
+ funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
@@ -284,7 +301,7 @@
cookie = 0;
}
let level = match level {
- llvm::DiagnosticLevel::Error => Level::Error,
+ llvm::DiagnosticLevel::Error => Level::Error { lint: false },
llvm::DiagnosticLevel::Warning => Level::Warning,
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
@@ -746,6 +763,14 @@
let thin = ThinBuffer::new(llmod);
let data = thin.data();
+ if let Some(bitcode_filename) = bc_out.file_name() {
+ cgcx.prof.artifact_size(
+ "llvm_bitcode",
+ bitcode_filename.to_string_lossy(),
+ data.len() as u64,
+ );
+ }
+
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
let _timer = cgcx.prof.generic_activity_with_arg(
"LLVM_module_codegen_emit_bitcode",
@@ -806,6 +831,11 @@
}
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
+
+ if result == llvm::LLVMRustResult::Success {
+ record_artifact_size(&cgcx.prof, "llvm_ir", &out);
+ }
+
result.into_result().map_err(|()| {
let msg = format!("failed to write LLVM IR to {}", out.display());
llvm_err(diag_handler, &msg)
@@ -836,6 +866,7 @@
&path,
None,
llvm::FileType::AssemblyFile,
+ &cgcx.prof,
)
})?;
}
@@ -869,6 +900,7 @@
&obj_out,
dwo_out,
llvm::FileType::ObjectFile,
+ &cgcx.prof,
)
})?;
}
@@ -1125,3 +1157,19 @@
symbol_name.starts_with(b"__llvm_profile_")
}
}
+
+fn record_artifact_size(
+ self_profiler_ref: &SelfProfilerRef,
+ artifact_kind: &'static str,
+ path: &Path,
+) {
+ // Don't stat the file if we are not going to record its size.
+ if !self_profiler_ref.enabled() {
+ return;
+ }
+
+ if let Some(artifact_name) = path.file_name() {
+ let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
+ self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size);
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 3026c2f..8766cae 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -113,8 +113,13 @@
let start_time = Instant::now();
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
- let (module, _) =
- tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+ let (module, _) = tcx.dep_graph.with_task(
+ dep_node,
+ tcx,
+ cgu_name,
+ module_codegen,
+ Some(dep_graph::hash_result),
+ );
let time_to_codegen = start_time.elapsed();
// We assume that the cost to run LLVM on a CGU is proportional to
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index d5deacf..ff88302 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -604,6 +604,32 @@
}
}
+ fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
+ let typeid_metadata = self.typeid_metadata(typeid);
+ let v = [self.const_usize(0), typeid_metadata];
+ unsafe {
+ llvm::LLVMGlobalSetMetadata(
+ function,
+ llvm::MD_type as c_uint,
+ llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+ self.cx.llcx,
+ v.as_ptr(),
+ v.len() as c_uint,
+ )),
+ )
+ }
+ }
+
+ fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
+ unsafe {
+ llvm::LLVMMDStringInContext(
+ self.cx.llcx,
+ typeid.as_ptr() as *const c_char,
+ typeid.as_bytes().len() as c_uint,
+ )
+ }
+ }
+
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
@@ -705,7 +731,7 @@
}
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+ 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);
@@ -717,7 +743,7 @@
}
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+ 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);
@@ -743,7 +769,7 @@
// we like. To ensure that LLVM picks the right instruction we choose
// the raw wasm intrinsic functions which avoid LLVM inserting all the
// other control flow automatically.
- if self.sess().target.arch == "wasm32" {
+ if self.sess().target.is_like_wasm {
let src_ty = self.cx.val_ty(val);
if self.cx.type_kind(src_ty) != TypeKind::Vector {
let float_width = self.cx.float_width(src_ty);
@@ -765,7 +791,7 @@
fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
// see `fptoui` above for why wasm is different here
- if self.sess().target.arch == "wasm32" {
+ if self.sess().target.is_like_wasm {
let src_ty = self.cx.val_ty(val);
if self.cx.type_kind(src_ty) != TypeKind::Vector {
let float_width = self.cx.float_width(src_ty);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 1afa6f0..b154ced 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -490,7 +490,7 @@
// Wasm statics with custom link sections get special treatment as they
// go into custom sections of the wasm executable.
- if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+ if self.tcx.sess.target.is_like_wasm {
if let Some(section) = attrs.link_section {
let section = llvm::LLVMMDStringInContext(
self.llcx,
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 257a0ac..613a8df 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -134,9 +134,6 @@
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
let mut target_data_layout = sess.target.data_layout.clone();
- if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
- target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
- }
if llvm_util::get_version() < (13, 0, 0) {
if sess.target.arch == "powerpc64" {
target_data_layout = target_data_layout.replace("-S128", "");
@@ -221,6 +218,15 @@
llvm::LLVMRustAddModuleFlag(llmod, 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);
+ }
+
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.is_like_msvc {
match sess.opts.cg.control_flow_guard {
@@ -591,7 +597,6 @@
ifn!("llvm.trap", fn() -> void);
ifn!("llvm.debugtrap", fn() -> void);
ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
- ifn!("llvm.sideeffect", fn() -> void);
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
@@ -779,6 +784,8 @@
ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
}
+ ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
+
if self.sess().opts.debuginfo != DebugInfo::None {
ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 1f1bd73..2a6bf7d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -322,7 +322,7 @@
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.
- let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+ let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c43141c..a7e34b0 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -19,7 +19,7 @@
use rustc_middle::ty::{self, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::{sym, symbol::kw, Span, Symbol};
-use rustc_target::abi::{self, HasDataLayout, Primitive};
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive};
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
use std::cmp::Ordering;
@@ -392,13 +392,12 @@
self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
}
- fn sideeffect(&mut self) {
- // This kind of check would make a ton of sense in the caller, but currently the only
- // caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM
- // codegen backend being used, and so is unable to check the LLVM version.
- if unsafe { llvm::LLVMRustVersionMajor() } < 12 {
- self.call_intrinsic("llvm.sideeffect", &[]);
- }
+ fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
+ // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
+ // optimization pass replaces calls to this intrinsic with code to test type membership.
+ let i8p_ty = self.type_i8p();
+ let bitcast = self.bitcast(pointer, i8p_ty);
+ self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
}
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
@@ -849,28 +848,39 @@
let arg_tys = sig.inputs();
if name == sym::simd_select_bitmask {
- let in_ty = arg_tys[0];
- let m_len = match in_ty.kind() {
- // Note that this `.unwrap()` crashes for isize/usize, that's sort
- // of intentional as there's not currently a use case for that.
- ty::Int(i) => i.bit_width().unwrap(),
- ty::Uint(i) => i.bit_width().unwrap(),
- _ => return_error!("`{}` is not an integral type", in_ty),
- };
require_simd!(arg_tys[1], "argument");
- let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
- require!(
- // Allow masks for vectors with fewer than 8 elements to be
- // represented with a u8 or i8.
- m_len == v_len || (m_len == 8 && v_len < 8),
- "mismatched lengths: mask length `{}` != other vector length `{}`",
- m_len,
- v_len
- );
+ let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+
+ let expected_int_bits = (len.max(8) - 1).next_power_of_two();
+ let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
+
+ let mask_ty = arg_tys[0];
+ let mask = match mask_ty.kind() {
+ ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+ ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+ ty::Array(elem, len)
+ if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+ && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+ == Some(expected_bytes) =>
+ {
+ let place = PlaceRef::alloca(bx, args[0].layout);
+ args[0].val.store(bx, place);
+ let int_ty = bx.type_ix(expected_bytes * 8);
+ let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
+ bx.load(int_ty, ptr, Align::ONE)
+ }
+ _ => return_error!(
+ "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
+ mask_ty,
+ expected_int_bits,
+ expected_bytes
+ ),
+ };
+
let i1 = bx.type_i1();
- let im = bx.type_ix(v_len);
- let i1xn = bx.type_vector(i1, v_len);
- let m_im = bx.trunc(args[0].immediate(), im);
+ let im = bx.type_ix(len);
+ let i1xn = bx.type_vector(i1, len);
+ let m_im = bx.trunc(mask, im);
let m_i1s = bx.bitcast(m_im, i1xn);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}
@@ -1048,16 +1058,16 @@
if name == sym::simd_bitmask {
// The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
- // vector mask and returns an unsigned integer containing the most
- // significant bit (MSB) of each lane.
-
- // If the vector has less than 8 lanes, a u8 is returned with zeroed
- // trailing bits.
+ // vector mask and returns the most significant bit (MSB) of each lane in the form
+ // of either:
+ // * an unsigned integer
+ // * an array of `u8`
+ // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
+ //
+ // The bit order of the result depends on the byte endianness, LSB-first for little
+ // endian and MSB-first for big endian.
let expected_int_bits = in_len.max(8);
- match ret_ty.kind() {
- ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (),
- _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits),
- }
+ let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
// Integer vector <i{in_bitwidth} x in_len>:
let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
@@ -1087,8 +1097,34 @@
let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
// Bitcast <i1 x N> to iN:
let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
- // Zero-extend iN to the bitmask type:
- return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+
+ match ret_ty.kind() {
+ ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
+ // Zero-extend iN to the bitmask type:
+ return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+ }
+ ty::Array(elem, len)
+ if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+ && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+ == Some(expected_bytes) =>
+ {
+ // Zero-extend iN to the array lengh:
+ let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
+
+ // Convert the integer to a byte array
+ let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
+ bx.store(ze, ptr, Align::ONE);
+ let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
+ let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
+ return Ok(bx.load(array_ty, ptr, Align::ONE));
+ }
+ _ => return_error!(
+ "cannot return `{}`, expected `u{}` or `[u8; {}]`",
+ ret_ty,
+ expected_int_bits,
+ expected_bytes
+ ),
+ }
}
fn simd_simple_float_intrinsic(
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 8f4d79e..c66d7d8 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -76,6 +76,27 @@
#[derive(Clone)]
pub struct LlvmCodegenBackend(());
+struct TimeTraceProfiler {
+ enabled: bool,
+}
+
+impl TimeTraceProfiler {
+ fn new(enabled: bool) -> Self {
+ if enabled {
+ unsafe { llvm::LLVMTimeTraceProfilerInitialize() }
+ }
+ TimeTraceProfiler { enabled }
+ }
+}
+
+impl Drop for TimeTraceProfiler {
+ fn drop(&mut self) {
+ if self.enabled {
+ unsafe { llvm::LLVMTimeTraceProfilerFinishThread() }
+ }
+ }
+}
+
impl ExtraBackendMethods for LlvmCodegenBackend {
fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
ModuleLlvm::new_metadata(tcx, mod_name)
@@ -119,6 +140,34 @@
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
llvm_util::tune_cpu(sess)
}
+
+ fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::spawn(move || {
+ let _profiler = TimeTraceProfiler::new(time_trace);
+ f()
+ })
+ }
+
+ fn spawn_named_thread<F, T>(
+ time_trace: bool,
+ name: String,
+ f: F,
+ ) -> std::io::Result<std::thread::JoinHandle<T>>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::Builder::new().name(name).spawn(move || {
+ let _profiler = TimeTraceProfiler::new(time_trace);
+ f()
+ })
+ }
}
impl WriteBackendMethods for LlvmCodegenBackend {
@@ -239,6 +288,31 @@
}
println!();
}
+ PrintRequest::StackProtectorStrategies => {
+ println!(
+ r#"Available stack protector strategies:
+ all
+ Generate stack canaries in all functions.
+
+ strong
+ Generate stack canaries in a function if it either:
+ - has a local variable of `[T; N]` type, regardless of `T` and `N`
+ - takes the address of a local variable.
+
+ (Note that a local variable being borrowed is not equivalent to its
+ address being taken: e.g. some borrows may be removed by optimization,
+ while by-value argument passing may be implemented with reference to a
+ local stack variable in the ABI.)
+
+ basic
+ Generate stack canaries in functions with:
+ - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
+
+ none
+ Do not generate stack canaries.
+"#
+ );
+ }
req => llvm_util::print(req, sess),
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 4c9ae4f..1d255c0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -166,6 +166,9 @@
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
WillReturn = 29,
+ StackProtectReq = 30,
+ StackProtectStrong = 31,
+ StackProtect = 32,
}
/// LLVMIntPredicate
@@ -416,6 +419,7 @@
MD_nontemporal = 9,
MD_mem_parallel_loop_access = 10,
MD_nonnull = 11,
+ MD_type = 19,
}
/// LLVMRustAsmDialect
@@ -1002,6 +1006,8 @@
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+ pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+ pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata;
// Operations on constants of any type
pub fn LLVMConstNull(Ty: &Type) -> &Value;
@@ -1734,6 +1740,8 @@
pub fn LLVMTimeTraceProfilerInitialize();
+ pub fn LLVMTimeTraceProfilerFinishThread();
+
pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char);
pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>);
@@ -1770,7 +1778,7 @@
pub fn LLVMDisposeMessage(message: *mut c_char);
- pub fn LLVMStartMultithreaded() -> Bool;
+ pub fn LLVMIsMultithreaded() -> Bool;
/// Returns a string describing the last error caused by an LLVMRust* call.
pub fn LLVMRustGetLastError() -> *const c_char;
@@ -2187,6 +2195,7 @@
UseSoftFP: bool,
FunctionSections: bool,
DataSections: bool,
+ UniqueSectionNames: bool,
TrapUnreachable: bool,
Singlethread: bool,
AsmComments: bool,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index c2136f1..3393c9b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -17,35 +17,25 @@
use std::ptr;
use std::slice;
use std::str;
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
-static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();
pub(crate) fn init(sess: &Session) {
unsafe {
// Before we touch LLVM, make sure that multithreading is enabled.
+ if llvm::LLVMIsMultithreaded() != 1 {
+ bug!("LLVM compiled without support for threads");
+ }
INIT.call_once(|| {
- if llvm::LLVMStartMultithreaded() != 1 {
- // use an extra bool to make sure that all future usage of LLVM
- // cannot proceed despite the Once not running more than once.
- POISONED.store(true, Ordering::SeqCst);
- }
-
configure_llvm(sess);
});
-
- if POISONED.load(Ordering::SeqCst) {
- bug!("couldn't enable multi-threaded LLVM");
- }
}
}
fn require_inited() {
- INIT.call_once(|| bug!("llvm is not initialized"));
- if POISONED.load(Ordering::SeqCst) {
- bug!("couldn't enable multi-threaded LLVM");
+ if !INIT.is_completed() {
+ bug!("LLVM is not initialized");
}
}
@@ -85,7 +75,9 @@
if sess.print_llvm_passes() {
add("-debug-pass=Structure", false);
}
- if !sess.opts.debugging_opts.no_generate_arange_section {
+ if sess.target.generate_arange_section
+ && !sess.opts.debugging_opts.no_generate_arange_section
+ {
add("-generate-arange-section", false);
}
@@ -95,8 +87,7 @@
// Ref:
// - https://github.com/rust-lang/rust/issues/85351
// - https://reviews.llvm.org/D103167
- let llvm_version = llvm_util::get_version();
- if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
+ if llvm_util::get_version() < (13, 0, 0) {
add("-enable-machine-outliner=never", false);
}
@@ -124,11 +115,6 @@
}
if sess.opts.debugging_opts.llvm_time_trace {
- // time-trace is not thread safe and running it in parallel will cause seg faults.
- if !sess.opts.debugging_opts.no_parallel_llvm {
- bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
- }
-
llvm::LLVMTimeTraceProfilerInitialize();
}
@@ -191,6 +177,7 @@
("aarch64", "dpb2") => vec!["ccdp"],
("aarch64", "frintts") => vec!["fptoint"],
("aarch64", "fcma") => vec!["complxnum"],
+ ("aarch64", "pmuv3") => vec!["perfmon"],
(_, s) => vec![s],
}
}
@@ -416,14 +403,6 @@
// -Ctarget-features
features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
- // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
- if get_version() >= (12, 0, 0)
- && sess.target.llvm_target.contains("aarch64-unknown-linux")
- && sess.target.llvm_target != "aarch64-unknown-linux-musl"
- {
- features.push("+outline-atomics".to_string());
- }
-
features
}
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index cf1c605..638b2a7 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -121,6 +121,19 @@
if sess.opts.json_artifact_notifications {
sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
}
+
+ if sess.prof.enabled() {
+ if let Some(artifact_name) = out_filename.file_name() {
+ // Record size for self-profiling
+ let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
+
+ sess.prof.artifact_size(
+ "linked_artifact",
+ artifact_name.to_string_lossy(),
+ file_size,
+ );
+ }
+ }
}
}
@@ -174,9 +187,8 @@
_ => {}
}
}
- let fmts = match fmts {
- Some(f) => f,
- None => return Err("could not find formats for rlibs".to_string()),
+ let Some(fmts) = fmts else {
+ return Err("could not find formats for rlibs".to_string());
};
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
@@ -1022,8 +1034,10 @@
SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
}
+ let strip = strip_value(sess);
+
if sess.target.is_like_osx {
- match sess.opts.debugging_opts.strip {
+ match strip {
Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None),
Strip::None => {}
@@ -1031,6 +1045,14 @@
}
}
+// Temporarily support both -Z strip and -C strip
+fn strip_value(sess: &Session) -> Strip {
+ match (sess.opts.debugging_opts.strip, sess.opts.cg.strip) {
+ (s, Strip::None) => s,
+ (_, s) => s,
+ }
+}
+
fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
let mut cmd = Command::new("strip");
if let Some(option) = option {
@@ -1096,10 +1118,10 @@
}
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
- fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
+ fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
let session_tlib =
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
- let path = session_tlib.join(&filename);
+ let path = session_tlib.join(filename);
if path.exists() {
return session_tlib;
} else {
@@ -2002,7 +2024,7 @@
cmd.optimize();
// Pass debuginfo and strip flags down to the linker.
- cmd.debuginfo(sess.opts.debugging_opts.strip);
+ cmd.debuginfo(strip_value(sess));
// We want to prevent the compiler from accidentally leaking in any system libraries,
// so by default we tell linkers not to link to any default libraries.
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 429dc45..15d16e7 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -219,19 +219,36 @@
}
impl<'a> GccLinker<'a> {
- /// Argument that must be passed *directly* to the linker
+ /// Passes an argument directly to the linker.
///
- /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
- fn linker_arg<S>(&mut self, arg: S) -> &mut Self
- where
- S: AsRef<OsStr>,
- {
- if !self.is_ld {
- let mut os = OsString::from("-Wl,");
- os.push(arg.as_ref());
- self.cmd.arg(os);
+ /// When the linker is not ld-like such as when using a compiler as a linker, the argument is
+ /// prepended by `-Wl,`.
+ fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+ self.linker_args(&[arg]);
+ self
+ }
+
+ /// Passes a series of arguments directly to the linker.
+ ///
+ /// When the linker is ld-like, the arguments are simply appended to the command. When the
+ /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
+ /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
+ /// single argument is appended to the command to ensure that the order of the arguments is
+ /// preserved by the compiler.
+ fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
+ if self.is_ld {
+ args.into_iter().for_each(|a| {
+ self.cmd.arg(a);
+ });
} else {
- self.cmd.arg(arg);
+ if !args.is_empty() {
+ let mut s = OsString::from("-Wl");
+ for a in args {
+ s.push(",");
+ s.push(a);
+ }
+ self.cmd.arg(s);
+ }
}
self
}
@@ -289,14 +306,19 @@
if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
};
- self.linker_arg(&format!("-plugin-opt={}", opt_level));
- self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
+ self.linker_args(&[
+ &format!("-plugin-opt={}", opt_level),
+ &format!("-plugin-opt=mcpu={}", self.target_cpu),
+ ]);
}
fn build_dylib(&mut self, out_filename: &Path) {
// On mac we need to tell the linker to let this library be rpathed
if self.sess.target.is_like_osx {
- self.cmd.arg("-dynamiclib");
+ if !self.is_ld {
+ self.cmd.arg("-dynamiclib");
+ }
+
self.linker_arg("-dylib");
// Note that the `osx_rpath_install_name` option here is a hack
@@ -304,10 +326,9 @@
// principled solution at some point to force the compiler to pass
// the right `-Wl,-install_name` with an `@rpath` in it.
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
- self.linker_arg("-install_name");
- let mut v = OsString::from("@rpath/");
- v.push(out_filename.file_name().unwrap());
- self.linker_arg(&v);
+ let mut rpath = OsString::from("@rpath/");
+ rpath.push(out_filename.file_name().unwrap());
+ self.linker_args(&[OsString::from("-install_name"), rpath]);
}
} else {
self.cmd.arg("-shared");
@@ -381,8 +402,7 @@
self.build_dylib(out_filename);
}
LinkOutputKind::WasiReactorExe => {
- self.linker_arg("--entry");
- self.linker_arg("_initialize");
+ self.linker_args(&["--entry", "_initialize"]);
}
}
// VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
@@ -454,8 +474,7 @@
self.cmd.arg(path);
}
fn full_relro(&mut self) {
- self.linker_arg("-zrelro");
- self.linker_arg("-znow");
+ self.linker_args(&["-zrelro", "-znow"]);
}
fn partial_relro(&mut self) {
self.linker_arg("-zrelro");
@@ -639,7 +658,6 @@
}
let is_windows = self.sess.target.is_like_windows;
- let mut arg = OsString::new();
let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
debug!("EXPORTED SYMBOLS:");
@@ -691,27 +709,18 @@
}
if self.sess.target.is_like_osx {
- if !self.is_ld {
- arg.push("-Wl,")
- }
- arg.push("-exported_symbols_list,");
+ self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
} else if self.sess.target.is_like_solaris {
- if !self.is_ld {
- arg.push("-Wl,")
- }
- arg.push("-M,");
+ self.linker_args(&[OsString::from("-M"), path.into()]);
} else {
- if !self.is_ld {
- arg.push("-Wl,")
- }
- // Both LD and LLD accept export list in *.def file form, there are no flags required
- if !is_windows {
- arg.push("--version-script=")
+ if is_windows {
+ self.linker_arg(path);
+ } else {
+ let mut arg = OsString::from("--version-script=");
+ arg.push(path);
+ self.linker_arg(arg);
}
}
-
- arg.push(&path);
- self.cmd.arg(arg);
}
fn subsystem(&mut self, subsystem: &str) {
@@ -769,8 +778,7 @@
self.linker_arg("--as-needed");
} else if self.sess.target.is_like_solaris {
// -z ignore is the Solaris equivalent to the GNU ld --as-needed option
- self.linker_arg("-z");
- self.linker_arg("ignore");
+ self.linker_args(&["-z", "ignore"]);
}
}
}
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 4a7090b3..f80f996 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -11,7 +11,7 @@
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{SymbolName, TyCtxt};
@@ -363,7 +363,7 @@
providers.wasm_import_module_map = wasm_import_module_map;
}
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
}
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index da34612..85d51ea 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -310,6 +310,7 @@
pub no_landing_pads: bool,
pub save_temps: bool,
pub fewer_names: bool,
+ pub time_trace: bool,
pub exported_symbols: Option<Arc<ExportedSymbols>>,
pub opts: Arc<config::Options>,
pub crate_types: Vec<CrateType>,
@@ -1039,6 +1040,7 @@
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,
opts: Arc::new(sess.opts.clone()),
prof: sess.prof.clone(),
exported_symbols,
@@ -1198,7 +1200,7 @@
// Each LLVM module is automatically sent back to the coordinator for LTO if
// necessary. There's already optimizations in place to avoid sending work
// back to the coordinator if LTO isn't requested.
- return thread::spawn(move || {
+ return B::spawn_thread(cgcx.time_trace, move || {
let mut worker_id_counter = 0;
let mut free_worker_ids = Vec::new();
let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
@@ -1615,59 +1617,57 @@
pub struct WorkerFatalError;
fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
- let builder = thread::Builder::new().name(work.short_description());
- builder
- .spawn(move || {
- // Set up a destructor which will fire off a message that we're done as
- // we exit.
- struct Bomb<B: ExtraBackendMethods> {
- coordinator_send: Sender<Box<dyn Any + Send>>,
- result: Option<Result<WorkItemResult<B>, FatalError>>,
- worker_id: usize,
+ B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
+ // Set up a destructor which will fire off a message that we're done as
+ // we exit.
+ struct Bomb<B: ExtraBackendMethods> {
+ coordinator_send: Sender<Box<dyn Any + Send>>,
+ result: Option<Result<WorkItemResult<B>, FatalError>>,
+ worker_id: usize,
+ }
+ impl<B: ExtraBackendMethods> Drop for Bomb<B> {
+ fn drop(&mut self) {
+ let worker_id = self.worker_id;
+ let msg = match self.result.take() {
+ Some(Ok(WorkItemResult::Compiled(m))) => {
+ Message::Done::<B> { result: Ok(m), worker_id }
+ }
+ Some(Ok(WorkItemResult::NeedsLink(m))) => {
+ Message::NeedsLink::<B> { module: m, worker_id }
+ }
+ Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
+ Message::NeedsFatLTO::<B> { result: m, worker_id }
+ }
+ Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
+ Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
+ }
+ Some(Err(FatalError)) => {
+ Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
+ }
+ None => Message::Done::<B> { result: Err(None), worker_id },
+ };
+ drop(self.coordinator_send.send(Box::new(msg)));
}
- impl<B: ExtraBackendMethods> Drop for Bomb<B> {
- fn drop(&mut self) {
- let worker_id = self.worker_id;
- let msg = match self.result.take() {
- Some(Ok(WorkItemResult::Compiled(m))) => {
- Message::Done::<B> { result: Ok(m), worker_id }
- }
- Some(Ok(WorkItemResult::NeedsLink(m))) => {
- Message::NeedsLink::<B> { module: m, worker_id }
- }
- Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
- Message::NeedsFatLTO::<B> { result: m, worker_id }
- }
- Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
- Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
- }
- Some(Err(FatalError)) => {
- Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
- }
- None => Message::Done::<B> { result: Err(None), worker_id },
- };
- drop(self.coordinator_send.send(Box::new(msg)));
- }
- }
+ }
- let mut bomb = Bomb::<B> {
- coordinator_send: cgcx.coordinator_send.clone(),
- result: None,
- worker_id: cgcx.worker,
- };
+ let mut bomb = Bomb::<B> {
+ coordinator_send: cgcx.coordinator_send.clone(),
+ result: None,
+ worker_id: cgcx.worker,
+ };
- // Execute the work itself, and if it finishes successfully then flag
- // ourselves as a success as well.
- //
- // Note that we ignore any `FatalError` coming out of `execute_work_item`,
- // as a diagnostic was already sent off to the main thread - just
- // surface that there was an error in this worker.
- bomb.result = {
- let _prof_timer = work.start_profiling(&cgcx);
- Some(execute_work_item(&cgcx, work))
- };
- })
- .expect("failed to spawn thread");
+ // Execute the work itself, and if it finishes successfully then flag
+ // ourselves as a success as well.
+ //
+ // Note that we ignore any `FatalError` coming out of `execute_work_item`,
+ // as a diagnostic was already sent off to the main thread - just
+ // surface that there was an error in this worker.
+ bomb.result = {
+ let _prof_timer = work.start_profiling(&cgcx);
+ Some(execute_work_item(&cgcx, work))
+ };
+ })
+ .expect("failed to spawn thread");
}
enum SharedEmitterMessage {
@@ -1757,7 +1757,7 @@
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
let mut err = match level {
- Level::Error => sess.struct_err(&msg),
+ Level::Error { lint: false } => sess.struct_err(&msg),
Level::Warning => sess.struct_warn(&msg),
Level::Note => sess.struct_note_without_error(&msg),
_ => bug!("Invalid inline asm diagnostic level"),
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index accb54e..ab119ae 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -124,10 +124,7 @@
// info for MSVC debugger. However, wrapping these types' names in a synthetic type
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
// types out to aid debugging in MSVC.
- let is_slice_or_str = match *inner_type.kind() {
- ty::Slice(_) | ty::Str => true,
- _ => false,
- };
+ let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
if !cpp_like_names {
output.push('&');
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index b759e3a..4c87d4d 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -3,6 +3,7 @@
#![feature(box_patterns)]
#![feature(try_blocks)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(once_cell)]
#![feature(nll)]
#![feature(associated_type_bounds)]
@@ -26,7 +27,7 @@
use rustc_hir::LangItem;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::dependency_format::Dependencies;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource};
use rustc_session::utils::NativeLibKind;
@@ -168,7 +169,7 @@
crate::target_features::provide(providers);
}
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
crate::back::symbol_export::provide_extern(providers);
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index b0a5631..c8f388b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -19,6 +19,7 @@
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
@@ -818,12 +819,43 @@
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
}
- let fn_ptr = match (llfn, instance) {
- (Some(llfn), _) => llfn,
- (None, Some(instance)) => bx.get_fn_addr(instance),
+ let (is_indirect_call, fn_ptr) = match (llfn, instance) {
+ (Some(llfn), _) => (true, llfn),
+ (None, Some(instance)) => (false, bx.get_fn_addr(instance)),
_ => span_bug!(span, "no llfn for call"),
};
+ // For backends that support CFI using type membership (i.e., testing whether a given
+ // pointer is associated with a type identifier).
+ if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
+ // Emit type metadata and checks.
+ // FIXME(rcvalle): Add support for generalized identifiers.
+ // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
+ let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
+ let typeid_metadata = bx.typeid_metadata(typeid);
+
+ // Test whether the function pointer is associated with the type identifier.
+ let cond = bx.type_test(fn_ptr, typeid_metadata);
+ let mut bx_pass = bx.build_sibling_block("type_test.pass");
+ let mut bx_fail = bx.build_sibling_block("type_test.fail");
+ bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
+
+ helper.do_call(
+ self,
+ &mut bx_pass,
+ fn_abi,
+ fn_ptr,
+ &llargs,
+ destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+ cleanup,
+ );
+
+ bx_fail.abort();
+ bx_fail.unreachable();
+
+ return;
+ }
+
helper.do_call(
self,
&mut bx,
@@ -845,6 +877,7 @@
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
+ instance: Instance<'_>,
) {
let span = terminator.source_info.span;
@@ -898,7 +931,7 @@
})
.collect();
- bx.codegen_inline_asm(template, &operands, options, line_spans);
+ bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
if let Some(target) = destination {
helper.funclet_br(self, &mut bx, target);
@@ -947,17 +980,6 @@
}
mir::TerminatorKind::Goto { target } => {
- if bb == target {
- // This is an unconditional branch back to this same basic block. That means we
- // have something like a `loop {}` statement. LLVM versions before 12.0
- // miscompile this because they assume forward progress. For older versions
- // try to handle just this specific case which comes up commonly in practice
- // (e.g., in embedded code).
- //
- // NB: the `sideeffect` currently checks for the LLVM version used internally.
- bx.sideeffect();
- }
-
helper.funclet_br(self, &mut bx, target);
}
@@ -1029,6 +1051,7 @@
options,
line_spans,
destination,
+ self.instance,
);
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 476ddbd..1ef863e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -4,6 +4,7 @@
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{FnAbi, PassMode};
use std::iter;
@@ -244,6 +245,13 @@
for (bb, _) in traversal::reverse_postorder(&mir) {
fx.codegen_block(bb);
}
+
+ // For backends that support CFI using type membership (i.e., testing whether a given pointer
+ // is associated with a type identifier).
+ if cx.tcx().sess.is_sanitizer_cfi_enabled() {
+ let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
+ bx.type_metadata(llfn, typeid);
+ }
}
/// Produces, for each argument, a `Value` pointing at the
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index ce6cec6..bea55bb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -343,9 +343,7 @@
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
.ty;
- let (llptr, llextra) = if let OperandValue::Ref(llptr, Some(llextra), _) = self {
- (llptr, llextra)
- } else {
+ let OperandValue::Ref(llptr, Some(llextra), _) = self else {
bug!("store_unsized called with a sized value")
};
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index fe7f628..2c96987 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -125,7 +125,7 @@
let count = self.codegen_operand(&mut bx, count).immediate();
let pointee_layout = dst_val
.layout
- .pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
+ .pointee_info_at(&bx, rustc_target::abi::Size::ZERO)
.expect("Expected pointer");
let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 8d7e961..b4420df 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -19,6 +19,8 @@
("crypto", Some(sym::arm_target_feature)),
("aes", Some(sym::arm_target_feature)),
("sha2", Some(sym::arm_target_feature)),
+ ("i8mm", Some(sym::arm_target_feature)),
+ ("dotprod", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
@@ -35,7 +37,6 @@
("thumb-mode", Some(sym::arm_target_feature)),
];
-// Commented features are not available in LLVM 10.0, or have since been renamed
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// FEAT_AdvSimd
("neon", Some(sym::aarch64_target_feature)),
@@ -66,13 +67,13 @@
// FEAT_DIT
("dit", Some(sym::aarch64_target_feature)),
// FEAT_FLAGM
- // ("flagm", Some(sym::aarch64_target_feature)),
+ ("flagm", Some(sym::aarch64_target_feature)),
// FEAT_SSBS
("ssbs", Some(sym::aarch64_target_feature)),
// FEAT_SB
("sb", Some(sym::aarch64_target_feature)),
// FEAT_PAUTH
- // ("pauth", Some(sym::aarch64_target_feature)),
+ ("pauth", Some(sym::aarch64_target_feature)),
// FEAT_DPB
("dpb", Some(sym::aarch64_target_feature)),
// FEAT_DPB2
@@ -90,13 +91,13 @@
// FEAT_FRINTTS
("frintts", Some(sym::aarch64_target_feature)),
// FEAT_I8MM
- // ("i8mm", Some(sym::aarch64_target_feature)),
+ ("i8mm", Some(sym::aarch64_target_feature)),
// FEAT_F32MM
- // ("f32mm", Some(sym::aarch64_target_feature)),
+ ("f32mm", Some(sym::aarch64_target_feature)),
// FEAT_F64MM
- // ("f64mm", Some(sym::aarch64_target_feature)),
+ ("f64mm", Some(sym::aarch64_target_feature)),
// FEAT_BF16
- // ("bf16", Some(sym::aarch64_target_feature)),
+ ("bf16", Some(sym::aarch64_target_feature)),
// FEAT_RAND
("rand", Some(sym::aarch64_target_feature)),
// FEAT_BTI
@@ -115,13 +116,23 @@
("sha3", Some(sym::aarch64_target_feature)),
// FEAT_SM3 & FEAT_SM4
("sm4", Some(sym::aarch64_target_feature)),
+ // FEAT_PAN
+ ("pan", Some(sym::aarch64_target_feature)),
+ // FEAT_LOR
+ ("lor", Some(sym::aarch64_target_feature)),
+ // FEAT_VHE
+ ("vh", Some(sym::aarch64_target_feature)),
+ // FEAT_PMUv3
+ ("pmuv3", Some(sym::aarch64_target_feature)),
+ // FEAT_SPE
+ ("spe", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
("v8.4a", Some(sym::aarch64_target_feature)),
("v8.5a", Some(sym::aarch64_target_feature)),
- // ("v8.6a", Some(sym::aarch64_target_feature)),
- // ("v8.7a", Some(sym::aarch64_target_feature)),
+ ("v8.6a", Some(sym::aarch64_target_feature)),
+ ("v8.7a", Some(sym::aarch64_target_feature)),
];
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs
index dd84958..a00d78d 100644
--- a/compiler/rustc_codegen_ssa/src/traits/abi.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs
@@ -4,5 +4,5 @@
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value);
- fn get_param(&self, index: usize) -> Self::Value;
+ fn get_param(&mut self, index: usize) -> Self::Value;
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs
index 86f2781..31f539e 100644
--- a/compiler/rustc_codegen_ssa/src/traits/asm.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs
@@ -58,6 +58,7 @@
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
line_spans: &[Span],
+ instance: Instance<'_>,
);
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 8129a14..9c8bc3b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -9,7 +9,7 @@
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_session::{
config::{self, OutputFilenames, PrintRequest},
@@ -80,7 +80,7 @@
}
fn provide(&self, _providers: &mut Providers) {}
- fn provide_extern(&self, _providers: &mut Providers) {}
+ fn provide_extern(&self, _providers: &mut ExternProviders) {}
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
@@ -142,4 +142,26 @@
) -> TargetMachineFactoryFn<Self>;
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
+
+ fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::spawn(f)
+ }
+
+ fn spawn_named_thread<F, T>(
+ _time_trace: bool,
+ name: String,
+ f: F,
+ ) -> std::io::Result<std::thread::JoinHandle<T>>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::Builder::new().name(name).spawn(f)
+ }
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index e7da96f..158e658 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -158,6 +158,8 @@
fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
fn nonnull_metadata(&mut self, load: Self::Value);
+ fn type_metadata(&mut self, function: Self::Function, typeid: String);
+ fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
fn store_with_flags(
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 777436a..02be6cd 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -20,10 +20,8 @@
fn abort(&mut self);
fn assume(&mut self, val: Self::Value);
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
- /// Emits a forced side effect.
- ///
- /// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
- fn sideeffect(&mut self);
+ /// Trait method used to test whether a given pointer is associated with a type identifier.
+ fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
/// Rust defined C-variadic functions.
fn va_start(&mut self, val: Self::Value) -> Self::Value;
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 5da1681..8729802 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -25,10 +25,7 @@
impl MachineStopType for ConstEvalErrKind {
fn is_hard_err(&self) -> bool {
- match self {
- Self::Panic { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Panic { .. })
}
}
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 57af0ff..6d3a89c 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -42,6 +42,7 @@
| DefKind::Static
| DefKind::ConstParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::AssocConst
),
"Unexpected DefKind: {:?}",
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 df4cc29..821b048 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -1,6 +1,5 @@
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
@@ -44,18 +43,16 @@
} else {
false
}
- } else if let Some(fn_like) = FnLikeNode::from_node(node) {
- if fn_like.constness() == hir::Constness::Const {
+ } else if let Some(fn_kind) = node.fn_kind() {
+ if fn_kind.constness() == hir::Constness::Const {
return true;
}
// 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)
- } else if let hir::Node::Ctor(_) = node {
- true
} else {
- false
+ 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 202c9ca..dacd8f7 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -30,34 +30,25 @@
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
- is_const_fn: bool,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
- // The list of functions we handle here must be in sync with
- // `is_lang_special_const_fn` in `transform/check_consts/mod.rs`.
+ // All `#[rustc_do_not_const_check]` functions should be hooked here.
let def_id = instance.def_id();
- if is_const_fn {
- if Some(def_id) == self.tcx.lang_items().const_eval_select() {
- // redirect to const_eval_select_ct
- if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
- return Ok(Some(
- ty::Instance::resolve(
- *self.tcx,
- ty::ParamEnv::reveal_all(),
- const_eval_select,
- instance.substs,
- )
- .unwrap()
- .unwrap(),
- ));
- }
+ if Some(def_id) == self.tcx.lang_items().const_eval_select() {
+ // redirect to const_eval_select_ct
+ if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
+ return Ok(Some(
+ ty::Instance::resolve(
+ *self.tcx,
+ ty::ParamEnv::reveal_all(),
+ const_eval_select,
+ instance.substs,
+ )
+ .unwrap()
+ .unwrap(),
+ ));
}
- return Ok(None);
- }
-
- if Some(def_id) == self.tcx.lang_items().panic_fn()
- || Some(def_id) == self.tcx.lang_items().panic_str()
- || Some(def_id) == self.tcx.lang_items().panic_display()
+ } else if Some(def_id) == self.tcx.lang_items().panic_display()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &str or &&str
@@ -72,9 +63,7 @@
let span = self.find_closest_untracked_caller_location();
let (file, line, col) = self.location_triple_for_span(span);
return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
- } else if Some(def_id) == self.tcx.lang_items().panic_fmt()
- || Some(def_id) == self.tcx.lang_items().begin_panic_fmt()
- {
+ } else if Some(def_id) == self.tcx.lang_items().panic_fmt() {
// For panic_fmt, call const_panic_fmt instead.
if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() {
return Ok(Some(
@@ -276,31 +265,22 @@
// Only check non-glue functions
if let ty::InstanceDef::Item(def) = instance.def {
- let mut is_const_fn = true;
-
// Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const
// at all.
if !ecx.tcx.is_const_fn_raw(def.did) {
// allow calling functions marked with #[default_method_body_is_const].
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
- is_const_fn = false;
+ // We certainly do *not* want to actually call the fn
+ // though, so be sure we return here.
+ throw_unsup_format!("calling non-const function `{}`", instance)
}
}
- // Some functions we support even if they are non-const -- but avoid testing
- // that for const fn!
- // `const_eval_select` is a const fn because it must use const trait bounds.
- if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? {
+ if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? {
// We call another const fn instead.
return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
}
-
- if !is_const_fn {
- // We certainly do *not* want to actually call the fn
- // though, so be sure we return here.
- throw_unsup_format!("calling non-const function `{}`", instance)
- }
}
// This is a const fn. Call it.
Ok(Some(ecx.load_mir(instance.def, None)?))
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 698742f..44da27a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -413,48 +413,33 @@
sym::simd_insert => {
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
let elem = &args[2];
- let input = &args[0];
- let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
+ let (input, input_len) = self.operand_to_simd(&args[0])?;
+ let (dest, dest_len) = self.place_to_simd(dest)?;
+ assert_eq!(input_len, dest_len, "Return vector length must match input length");
assert!(
- index < len,
- "Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
+ index < dest_len,
+ "Index `{}` must be in bounds of vector with length {}`",
index,
- e_ty,
- len
- );
- assert_eq!(
- input.layout, dest.layout,
- "Return type `{}` must match vector type `{}`",
- dest.layout.ty, input.layout.ty
- );
- assert_eq!(
- elem.layout.ty, e_ty,
- "Scalar element type `{}` must match vector element type `{}`",
- elem.layout.ty, e_ty
+ dest_len
);
- for i in 0..len {
- let place = self.place_index(dest, i)?;
- let value = if i == index { *elem } else { self.operand_index(input, i)? };
- self.copy_op(&value, &place)?;
+ for i in 0..dest_len {
+ let place = self.mplace_index(&dest, i)?;
+ let value =
+ if i == index { *elem } else { self.mplace_index(&input, i)?.into() };
+ self.copy_op(&value, &place.into())?;
}
}
sym::simd_extract => {
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
- let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
+ let (input, input_len) = self.operand_to_simd(&args[0])?;
assert!(
- index < len,
- "index `{}` is out-of-bounds of vector type `{}` with length `{}`",
+ index < input_len,
+ "index `{}` must be in bounds of vector with length `{}`",
index,
- e_ty,
- len
+ input_len
);
- assert_eq!(
- e_ty, dest.layout.ty,
- "Return type `{}` must match vector element type `{}`",
- dest.layout.ty, e_ty
- );
- self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
+ self.copy_op(&self.mplace_index(&input, index)?.into(), dest)?;
}
sym::likely | sym::unlikely | sym::black_box => {
// These just return their argument
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index d4cbba1..b5e97ec8 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -80,10 +80,17 @@
line: u32,
col: u32,
) -> MPlaceTy<'tcx, M::PointerTag> {
- let file =
- self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
- let line = Scalar::from_u32(line);
- let col = Scalar::from_u32(col);
+ let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail;
+ let file = if loc_details.file {
+ self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+ } else {
+ // FIXME: This creates a new allocation each time. It might be preferable to
+ // perform this allocation only once, and re-use the `MPlaceTy`.
+ // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
+ self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+ };
+ let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
+ let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
// Allocate memory for `CallerLocation` struct.
let loc_ty = self
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 a7012cd..5b4a5ac 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
@@ -138,10 +138,8 @@
args: &[GenericArg<'tcx>],
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- let args = args.iter().cloned().filter(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(_) => false,
- _ => true,
- });
+ let args =
+ args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
if args.clone().next().is_some() {
self.generic_delimiters(|cx| cx.comma_sep(args))
} else {
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 323e102..5120782 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -131,6 +131,10 @@
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ /// Whether to enforce validity (e.g., initialization and not having ptr provenance)
+ /// of integers and floats.
+ fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+
/// Whether function calls should be [ABI](Abi)-checked.
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
true
@@ -427,6 +431,11 @@
}
#[inline(always)]
+ fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+ true
+ }
+
+ #[inline(always)]
fn call_extra_fn(
_ecx: &mut InterpCx<$mir, $tcx, Self>,
fn_val: !,
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index b8b6ff9..4aa3c83 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -1057,20 +1057,19 @@
Some(dest_ptr) => dest_ptr,
};
- // first copy the relocations to a temporary buffer, because
- // `get_bytes_mut` will clear the relocations, which is correct,
- // since we don't want to keep any relocations at the target.
- // (`get_bytes_with_uninit_and_ptr` below checks that there are no
- // relocations overlapping the edges; those would not be handled correctly).
- let relocations =
- src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies);
- // Prepare a copy of the initialization mask.
- let compressed = src_alloc.compress_uninit_range(src_range);
- // This checks relocation edges on the src.
+ // This checks relocation edges on the src, which needs to happen before
+ // `prepare_relocation_copy`.
let src_bytes = src_alloc
.get_bytes_with_uninit_and_ptr(&tcx, src_range)
.map_err(|e| e.to_interp_error(src_alloc_id))?
.as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
+ // first copy the relocations to a temporary buffer, because
+ // `get_bytes_mut` will clear the relocations, which is correct,
+ // since we don't want to keep any relocations at the target.
+ let relocations =
+ src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies);
+ // Prepare a copy of the initialization mask.
+ let compressed = src_alloc.compress_uninit_range(src_range);
// Destination alloc preparations and access hooks.
let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?;
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index b6682b1..de9e94c 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -437,6 +437,18 @@
})
}
+ /// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements.
+ /// Also returns the number of elements.
+ pub fn operand_to_simd(
+ &self,
+ base: &OpTy<'tcx, M::PointerTag>,
+ ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+ // Basically we just transmute this place into an array following simd_size_and_type.
+ // This only works in memory, but repr(simd) types should never be immediates anyway.
+ assert!(base.layout.ty.is_simd());
+ self.mplace_to_simd(&base.assert_mem_place())
+ }
+
/// Read from a local. Will not actually access the local if reading from a ZST.
/// Will not access memory, instead an indirect `Operand` is returned.
///
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index ac000b1..a90582f 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -130,7 +130,12 @@
let signed = left_layout.abi.is_signed();
let size = u128::from(left_layout.size.bits());
let overflow = r >= size;
- let r = r % size; // mask to type size
+ // The shift offset is implicitly masked to the type size, to make sure this operation
+ // is always defined. This is the one MIR operator that does *not* directly map to a
+ // single LLVM operation. See
+ // <https://github.com/rust-lang/rust/blob/a3b9405ae7bb6ab4e8103b414e75c44598a10fd2/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
+ // for the corresponding truncation in our codegen backends.
+ let r = r % size;
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
let result = if signed {
let l = self.sign_extend(l, left_layout) as i128;
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index d425b84..d7f2853 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -200,7 +200,7 @@
}
} else {
// Go through the layout. There are lots of types that support a length,
- // e.g., SIMD types.
+ // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!)
match self.layout.fields {
FieldsShape::Array { count, .. } => Ok(count),
_ => bug!("len not supported on sized type {:?}", self.layout.ty),
@@ -533,6 +533,22 @@
})
}
+ /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements.
+ /// Also returns the number of elements.
+ pub fn mplace_to_simd(
+ &self,
+ base: &MPlaceTy<'tcx, M::PointerTag>,
+ ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+ // Basically we just transmute this place into an array following simd_size_and_type.
+ // (Transmuting is okay since this is an in-memory place. We also double-check the size
+ // stays the same.)
+ let (len, e_ty) = base.layout.ty.simd_size_and_type(*self.tcx);
+ let array = self.tcx.mk_array(e_ty, len);
+ let layout = self.layout_of(array)?;
+ assert_eq!(layout.size, base.layout.size);
+ Ok((MPlaceTy { layout, ..*base }, len))
+ }
+
/// Gets the place of a field inside the place, and also the field's type.
/// Just a convenience function, but used quite a bit.
/// This is the only projection that might have a side-effect: We cannot project
@@ -594,6 +610,16 @@
})
}
+ /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements.
+ /// Also returns the number of elements.
+ pub fn place_to_simd(
+ &mut self,
+ base: &PlaceTy<'tcx, M::PointerTag>,
+ ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+ let mplace = self.force_allocation(base)?;
+ self.mplace_to_simd(&mplace)
+ }
+
/// Computes a place. You should only use this if you intend to write into this
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
pub fn eval_place(
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 8d3544d..0020857 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -345,10 +345,8 @@
// Figure out how to pass which arguments.
// The Rust ABI is special: ZST get skipped.
- let rust_abi = match caller_abi {
- Abi::Rust | Abi::RustCall => true,
- _ => false,
- };
+ let rust_abi = matches!(caller_abi, Abi::Rust | Abi::RustCall);
+
// We have two iterators: Where the arguments come from,
// and where they go to.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index fc69770..6be3e19 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -520,7 +520,7 @@
let value = self.read_scalar(value)?;
// NOTE: Keep this in sync with the array optimization for int/float
// types below!
- if self.ctfe_mode.is_some() {
+ if M::enforce_number_validity(self.ecx) {
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
if !is_bits {
@@ -528,9 +528,6 @@
{ "{}", value } expected { "initialized plain (non-pointer) bytes" }
)
}
- } else {
- // At run-time, for now, we accept *anything* for these types, including
- // uninit. We should fix that, but let's start low.
}
Ok(true)
}
@@ -855,9 +852,10 @@
}
};
+ let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
match alloc.check_bytes(
alloc_range(Size::ZERO, size),
- /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(),
+ allow_uninit_and_ptr,
) {
// In the happy case, we needn't check anything else.
Ok(()) => {}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 7ce40b3..f308e76 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -13,6 +13,7 @@
#![feature(exact_size_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
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 d704c43..4e3a8b6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -12,7 +12,6 @@
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
-use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals;
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -22,54 +21,22 @@
use std::ops::Deref;
use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif};
+use super::{ConstCx, Qualif};
use crate::const_eval::is_unstable_const_fn;
-// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
-// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
-// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-type IndirectlyMutableResults<'mir, 'tcx> =
- rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
-
type QualifResults<'mir, 'tcx, Q> =
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
#[derive(Default)]
pub struct Qualifs<'mir, 'tcx> {
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
- needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
- indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
+ needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+ needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
}
impl Qualifs<'mir, 'tcx> {
- pub fn indirectly_mutable(
- &mut self,
- ccx: &'mir ConstCx<'mir, 'tcx>,
- local: Local,
- location: Location,
- ) -> bool {
- let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
- let ConstCx { tcx, body, param_env, .. } = *ccx;
-
- // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
- // allowed in a const.
- //
- // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
- // without breaking stable code?
- MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
- .unsound_ignore_borrow_on_drop()
- .into_engine(tcx, &body)
- .pass_name("const_qualification")
- .iterate_to_fixpoint()
- .into_results_cursor(&body)
- });
-
- indirectly_mutable.seek_before_primary_effect(location);
- indirectly_mutable.get().contains(local)
- }
-
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
@@ -80,21 +47,48 @@
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
- if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
+ if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
return false;
}
let needs_drop = self.needs_drop.get_or_insert_with(|| {
let ConstCx { tcx, body, .. } = *ccx;
+ FlowSensitiveAnalysis::new(NeedsDrop, ccx)
+ .into_engine(tcx, &body)
+ .iterate_to_fixpoint()
+ .into_results_cursor(&body)
+ });
+
+ needs_drop.seek_before_primary_effect(location);
+ needs_drop.get().contains(local)
+ }
+
+ /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
+ ///
+ /// Only updates the cursor if absolutely necessary
+ pub fn needs_non_const_drop(
+ &mut self,
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ local: Local,
+ location: Location,
+ ) -> bool {
+ let ty = ccx.body.local_decls[local].ty;
+ if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
+ return false;
+ }
+
+ let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
+ let ConstCx { tcx, body, .. } = *ccx;
+
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
.into_engine(tcx, &body)
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
- needs_drop.seek_before_primary_effect(location);
- needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ needs_non_const_drop.seek_before_primary_effect(location);
+ needs_non_const_drop.get().contains(local)
}
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
@@ -121,7 +115,7 @@
});
has_mut_interior.seek_before_primary_effect(location);
- has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ has_mut_interior.get().contains(local)
}
fn in_return_place(
@@ -137,10 +131,7 @@
.body
.basic_blocks()
.iter_enumerated()
- .find(|(_, block)| match block.terminator().kind {
- TerminatorKind::Return => true,
- _ => false,
- })
+ .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
.map(|(bb, _)| bb);
let return_block = match return_block {
@@ -167,12 +158,13 @@
.into_results_cursor(&ccx.body);
cursor.seek_after_primary_effect(return_loc);
- cursor.contains(RETURN_PLACE)
+ cursor.get().contains(RETURN_PLACE)
}
};
ConstQualifs {
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
+ 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,
@@ -730,7 +722,7 @@
match elem {
ProjectionElem::Deref => {
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
- if let ty::RawPtr(_) = base_ty.kind() {
+ if base_ty.is_unsafe_ptr() {
if proj_base.is_empty() {
let decl = &self.body.local_decls[place_local];
if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
@@ -739,7 +731,13 @@
return;
}
}
- self.check_op(ops::RawPtrDeref);
+
+ // `*const T` is stable, `*mut T` is not
+ if !base_ty.is_mutable_ptr() {
+ return;
+ }
+
+ self.check_op(ops::RawMutPtrDeref);
}
if context.is_mutating_use() {
@@ -825,6 +823,7 @@
Binder::dummy(TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
@@ -888,31 +887,27 @@
}
// At this point, we are calling a function, `callee`, whose `DefId` is known...
- if is_lang_special_const_fn(tcx, callee) {
- // `begin_panic` and `panic_display` are generic functions that accept
- // types other than str. Check to enforce that only str can be used in
- // const-eval.
- // const-eval of the `begin_panic` fn assumes the argument is `&str`
- if Some(callee) == tcx.lang_items().begin_panic_fn() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if ty.is_str() => (),
- _ => self.check_op(ops::PanicNonStr),
- }
+ // `begin_panic` and `panic_display` are generic functions that accept
+ // types other than str. Check to enforce that only str can be used in
+ // const-eval.
+
+ // const-eval of the `begin_panic` fn assumes the argument is `&str`
+ if Some(callee) == tcx.lang_items().begin_panic_fn() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if ty.is_str() => return,
+ _ => self.check_op(ops::PanicNonStr),
}
+ }
- // const-eval of the `panic_display` fn assumes the argument is `&&str`
- if Some(callee) == tcx.lang_items().panic_display() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
- {}
- _ => self.check_op(ops::PanicNonStr),
+ // const-eval of the `panic_display` fn assumes the argument is `&&str`
+ if Some(callee) == tcx.lang_items().panic_display() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+ {
+ return;
}
- }
-
- if is_lang_panic_fn(tcx, callee) {
- // run stability check on non-panic special const fns.
- return;
+ _ => self.check_op(ops::PanicNonStr),
}
}
@@ -999,7 +994,7 @@
}
// Forbid all `Drop` terminators unless the place being dropped is a local with no
- // projections that cannot be `NeedsDrop`.
+ // projections that cannot be `NeedsNonConstDrop`.
TerminatorKind::Drop { place: dropped_place, .. }
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
// If we are checking live drops after drop-elaboration, don't emit duplicate
@@ -1009,25 +1004,26 @@
}
let mut err_span = self.span;
+ let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
- let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty(
- self.ccx,
- dropped_place.ty(self.body, self.tcx).ty,
- );
+ let ty_needs_non_const_drop =
+ qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
+
+ debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
if !ty_needs_non_const_drop {
return;
}
- let needs_drop = if let Some(local) = dropped_place.as_local() {
+ let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
// Use the span where the local was declared as the span of the drop error.
err_span = self.body.local_decls[local].source_info.span;
- self.qualifs.needs_drop(self.ccx, local, location)
+ self.qualifs.needs_non_const_drop(self.ccx, local, location)
} else {
true
};
- if needs_drop {
+ if needs_non_const_drop {
self.check_op_spanned(
ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
err_span,
@@ -1065,8 +1061,9 @@
let mut fulfillment_cx = traits::FulfillmentContext::new();
let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
});
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 0a85228..dc44409 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -72,25 +72,6 @@
}
}
-/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
-pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
- Some(def_id) == tcx.lang_items().panic_fn()
- || Some(def_id) == tcx.lang_items().panic_str()
- || Some(def_id) == tcx.lang_items().panic_display()
- || Some(def_id) == tcx.lang_items().begin_panic_fn()
- || Some(def_id) == tcx.lang_items().panic_fmt()
- || Some(def_id) == tcx.lang_items().begin_panic_fmt()
-}
-
-/// Returns `true` if this `DefId` points to one of the lang items that will be handled differently
-/// in const_eval.
-pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
- // We can allow calls to these functions because `hook_special_const_fn` in
- // `const_eval/machine.rs` ensures the calls are handled specially.
- // Keep in sync with what that function handles!
- is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select()
-}
-
pub fn rustc_allow_const_fn_unstable(
tcx: TyCtxt<'tcx>,
def_id: DefId,
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 230d023..6391c88 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -400,18 +400,18 @@
}
#[derive(Debug)]
-pub struct RawPtrDeref;
-impl NonConstOp for RawPtrDeref {
+pub struct RawMutPtrDeref;
+impl NonConstOp for RawMutPtrDeref {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
- Status::Unstable(sym::const_raw_ptr_deref)
+ Status::Unstable(sym::const_mut_refs)
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
- sym::const_raw_ptr_deref,
+ sym::const_mut_refs,
span,
- &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),),
+ &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
)
}
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index 1a8c8b1..7a2be3c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -97,7 +97,7 @@
// `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
// initialized with `None` and never changed, it still emits drop glue.
// Hence we additionally check the qualifs here to allow more code to pass.
- if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
+ if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
self.check_live_drop(span);
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 5eb7d7a..abc5a3c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -21,7 +21,8 @@
) -> ConstQualifs {
ConstQualifs {
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
- needs_drop: NeedsNonConstDrop::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,
}
@@ -45,6 +46,9 @@
/// Whether this `Qualif` is cleared when a local is moved from.
const IS_CLEARED_ON_MOVE: bool = false;
+ /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted.
+ const ALLOW_PROMOTED: bool = false;
+
/// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`.
fn in_qualifs(qualifs: &ConstQualifs) -> bool;
@@ -98,17 +102,40 @@
}
/// Constant containing an ADT that implements `Drop`.
-/// This must be ruled out (a) because we cannot run `Drop` during compile-time
-/// as that might not be a `const fn`, and (b) because implicit promotion would
-/// remove side-effects that occur as part of dropping that value.
+/// This must be ruled out because implicit promotion would remove side-effects
+/// that occur as part of dropping that value. N.B., the implicit promotion has
+/// to reject const Drop implementations because even if side-effects are ruled
+/// out through other means, the execution of the drop could diverge.
+pub struct NeedsDrop;
+
+impl Qualif for NeedsDrop {
+ const ANALYSIS_NAME: &'static str = "flow_needs_drop";
+ const IS_CLEARED_ON_MOVE: bool = true;
+
+ fn in_qualifs(qualifs: &ConstQualifs) -> bool {
+ qualifs.needs_drop
+ }
+
+ fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+ ty.needs_drop(cx.tcx, cx.param_env)
+ }
+
+ fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
+ adt.has_dtor(cx.tcx)
+ }
+}
+
+/// Constant containing an ADT that implements non-const `Drop`.
+/// This must be ruled out because we cannot run `Drop` during compile-time.
pub struct NeedsNonConstDrop;
impl Qualif for NeedsNonConstDrop {
const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop";
const IS_CLEARED_ON_MOVE: bool = true;
+ const ALLOW_PROMOTED: bool = true;
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
- qualifs.needs_drop
+ qualifs.needs_non_const_drop
}
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
@@ -122,9 +149,7 @@
Ok([..]) => {}
}
- let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() {
- did
- } else {
+ let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else {
// there is no way to define a type that needs non-const drop
// without having the lang item present.
return false;
@@ -137,6 +162,7 @@
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
@@ -144,11 +170,12 @@
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
selcx.select(&obligation)
});
- match implsrc {
- Ok(Some(ImplSource::ConstDrop(_)))
- | Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false,
- _ => true,
- }
+ !matches!(
+ implsrc,
+ Ok(Some(
+ ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+ ))
+ )
}
fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
@@ -232,6 +259,9 @@
if Q::in_adt_inherently(cx, def, substs) {
return true;
}
+ if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
+ return true;
+ }
}
// Otherwise, proceed structurally...
@@ -289,9 +319,12 @@
// 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 {
- assert!(promoted.is_none());
+ // 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.
+ assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Don't peek inside trait associated constants.
- if cx.tcx.trait_of_item(def.did).is_none() {
+ if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
} else {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 8e1b69a..b70b387 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -4,8 +4,12 @@
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
+use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
+use rustc_mir_dataflow::fmt::DebugWithContext;
+use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_span::DUMMY_SP;
+use std::fmt;
use std::marker::PhantomData;
use super::{qualifs, ConstCx, Qualif};
@@ -13,13 +17,13 @@
/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis`.
///
-/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
-/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via
-/// an indirect assignment or function call.
+/// To account for indirect assignments, data flow conservatively assumes that local becomes
+/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
+/// mutation, which includes shared borrows of places with interior mutability. The type of
+/// borrowed place must contain the qualif.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
ccx: &'a ConstCx<'mir, 'tcx>,
- qualifs_per_local: &'a mut BitSet<Local>,
-
+ state: &'a mut State,
_qualif: PhantomData<Q>,
}
@@ -27,27 +31,38 @@
where
Q: Qualif,
{
- fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet<Local>) -> Self {
- TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData }
+ fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
+ TransferFunction { ccx, state, _qualif: PhantomData }
}
fn initialize_state(&mut self) {
- self.qualifs_per_local.clear();
+ self.state.qualif.clear();
+ self.state.borrow.clear();
for arg in self.ccx.body.args_iter() {
let arg_ty = self.ccx.body.local_decls[arg].ty;
if Q::in_any_value_of_ty(self.ccx, arg_ty) {
- self.qualifs_per_local.insert(arg);
+ self.state.qualif.insert(arg);
}
}
}
- fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
+ fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
debug_assert!(!place.is_indirect());
+ if !value {
+ for (base, _elem) in place.iter_projections() {
+ let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
+ if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
+ value = true;
+ break;
+ }
+ }
+ }
+
match (value, place.as_ref()) {
(true, mir::PlaceRef { local, .. }) => {
- self.qualifs_per_local.insert(local);
+ self.state.qualif.insert(local);
}
// For now, we do not clear the qualif if a local is overwritten in full by
@@ -55,7 +70,7 @@
// with aggregates where we overwrite all fields with assignments, which would not
// get this feature.
(false, mir::PlaceRef { local: _, projection: &[] }) => {
- // self.qualifs_per_local.remove(*local);
+ // self.state.qualif.remove(*local);
}
_ => {}
@@ -78,6 +93,37 @@
self.assign_qualif_direct(&return_place, qualif);
}
}
+
+ fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+ // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
+ // it might allow mutation until resolution of #56604.
+ true
+ }
+
+ fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
+ match kind {
+ mir::BorrowKind::Mut { .. } => true,
+ mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
+ self.shared_borrow_allows_mutation(place)
+ }
+ }
+ }
+
+ /// `&` only allow mutation if the borrowed place is `!Freeze`.
+ ///
+ /// This assumes that it is UB to take the address of a struct field whose type is
+ /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
+ /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
+ /// have to check the type of the borrowed **local** instead of the borrowed **place**
+ /// below. See [rust-lang/unsafe-code-guidelines#134].
+ ///
+ /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
+ fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
+ !place
+ .ty(self.ccx.body, self.ccx.tcx)
+ .ty
+ .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+ }
}
impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
@@ -95,7 +141,12 @@
// it no longer needs to be dropped.
if let mir::Operand::Move(place) = operand {
if let Some(local) = place.as_local() {
- self.qualifs_per_local.remove(local);
+ // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
+ // implementation we retain qualif if a local had been borrowed before. This might
+ // not be strictly necessary since the local is no longer initialized.
+ if !self.state.borrow.contains(local) {
+ self.state.qualif.remove(local);
+ }
}
}
}
@@ -106,11 +157,8 @@
rvalue: &mir::Rvalue<'tcx>,
location: Location,
) {
- let qualif = qualifs::in_rvalue::<Q, _>(
- self.ccx,
- &mut |l| self.qualifs_per_local.contains(l),
- rvalue,
- );
+ let qualif =
+ qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue);
if !place.is_indirect() {
self.assign_qualif_direct(place, qualif);
}
@@ -120,6 +168,58 @@
self.super_assign(place, rvalue, location);
}
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
+ self.super_rvalue(rvalue, location);
+
+ match rvalue {
+ mir::Rvalue::AddressOf(mt, borrowed_place) => {
+ if !borrowed_place.is_indirect()
+ && self.address_of_allows_mutation(*mt, *borrowed_place)
+ {
+ let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+ if Q::in_any_value_of_ty(self.ccx, place_ty) {
+ self.state.qualif.insert(borrowed_place.local);
+ self.state.borrow.insert(borrowed_place.local);
+ }
+ }
+ }
+
+ mir::Rvalue::Ref(_, kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place)
+ {
+ let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+ if Q::in_any_value_of_ty(self.ccx, place_ty) {
+ self.state.qualif.insert(borrowed_place.local);
+ self.state.borrow.insert(borrowed_place.local);
+ }
+ }
+ }
+
+ mir::Rvalue::Cast(..)
+ | mir::Rvalue::ShallowInitBox(..)
+ | mir::Rvalue::Use(..)
+ | mir::Rvalue::ThreadLocalRef(..)
+ | mir::Rvalue::Repeat(..)
+ | mir::Rvalue::Len(..)
+ | mir::Rvalue::BinaryOp(..)
+ | mir::Rvalue::CheckedBinaryOp(..)
+ | mir::Rvalue::NullaryOp(..)
+ | mir::Rvalue::UnaryOp(..)
+ | mir::Rvalue::Discriminant(..)
+ | mir::Rvalue::Aggregate(..) => {}
+ }
+ }
+
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+ match statement.kind {
+ StatementKind::StorageDead(local) => {
+ self.state.qualif.remove(local);
+ self.state.borrow.remove(local);
+ }
+ _ => self.super_statement(statement, location),
+ }
+ }
+
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
// here; that occurs in `apply_call_return_effect`.
@@ -127,7 +227,7 @@
if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
let qualif = qualifs::in_operand::<Q, _>(
self.ccx,
- &mut |l| self.qualifs_per_local.contains(l),
+ &mut |l| self.state.qualif.contains(l),
value,
);
@@ -136,6 +236,9 @@
}
}
+ // We ignore borrow on drop because custom drop impls are not allowed in consts.
+ // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
+
// We need to assign qualifs to the dropped location before visiting the operand that
// replaces it since qualifs can be cleared on move.
self.super_terminator(terminator, location);
@@ -156,24 +259,89 @@
FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
}
- fn transfer_function(
- &self,
- state: &'a mut BitSet<Local>,
- ) -> TransferFunction<'a, 'mir, 'tcx, Q> {
+ fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
TransferFunction::<Q>::new(self.ccx, state)
}
}
+#[derive(Debug, PartialEq, Eq)]
+pub(super) struct State {
+ /// Describes whether a local contains qualif.
+ pub qualif: BitSet<Local>,
+ /// Describes whether a local's address escaped and it might become qualified as a result an
+ /// indirect mutation.
+ pub borrow: BitSet<Local>,
+}
+
+impl Clone for State {
+ fn clone(&self) -> Self {
+ State { qualif: self.qualif.clone(), borrow: self.borrow.clone() }
+ }
+
+ // Data flow engine when possible uses `clone_from` for domain values.
+ // Providing an implementation will avoid some intermediate memory allocations.
+ fn clone_from(&mut self, other: &Self) {
+ self.qualif.clone_from(&other.qualif);
+ self.borrow.clone_from(&other.borrow);
+ }
+}
+
+impl State {
+ #[inline]
+ pub(super) fn contains(&self, local: Local) -> bool {
+ self.qualif.contains(local)
+ }
+}
+
+impl<C> DebugWithContext<C> for State {
+ fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("qualif: ")?;
+ self.qualif.fmt_with(ctxt, f)?;
+ f.write_str(" borrow: ")?;
+ self.borrow.fmt_with(ctxt, f)?;
+ Ok(())
+ }
+
+ fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self == old {
+ return Ok(());
+ }
+
+ if self.qualif != old.qualif {
+ f.write_str("qualif: ")?;
+ self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?;
+ f.write_str("\n")?;
+ }
+
+ if self.borrow != old.borrow {
+ f.write_str("borrow: ")?;
+ self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
+ f.write_str("\n")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl JoinSemiLattice for State {
+ fn join(&mut self, other: &Self) -> bool {
+ self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
+ }
+}
+
impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
- type Domain = BitSet<Local>;
+ type Domain = State;
const NAME: &'static str = Q::ANALYSIS_NAME;
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
- BitSet::new_empty(body.local_decls.len())
+ State {
+ qualif: BitSet::new_empty(body.local_decls.len()),
+ borrow: BitSet::new_empty(body.local_decls.len()),
+ }
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 7cfe3d7..a92b20f 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -26,7 +26,7 @@
use std::cell::Cell;
use std::{cmp, iter, mem};
-use crate::transform::check_consts::{is_lang_special_const_fn, qualifs, ConstCx};
+use crate::transform::check_consts::{qualifs, ConstCx};
use crate::transform::MirPass;
/// A `MirPass` for promotion.
@@ -93,17 +93,8 @@
/// returned value in a promoted MIR, unless it's a subset
/// of a larger candidate.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Candidate {
- /// Borrow of a constant temporary, candidate for lifetime extension.
- Ref(Location),
-}
-
-impl Candidate {
- fn source_info(&self, body: &Body<'_>) -> SourceInfo {
- match self {
- Candidate::Ref(location) => *body.source_info(*location),
- }
- }
+pub struct Candidate {
+ location: Location,
}
struct Collector<'a, 'tcx> {
@@ -167,7 +158,7 @@
match *rvalue {
Rvalue::Ref(..) => {
- self.candidates.push(Candidate::Ref(location));
+ self.candidates.push(Candidate { location });
}
_ => {}
}
@@ -209,36 +200,33 @@
impl<'tcx> Validator<'_, 'tcx> {
fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
- match candidate {
- Candidate::Ref(loc) => {
- let statement = &self.body[loc.block].statements[loc.statement_index];
- match &statement.kind {
- StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
- // We can only promote interior borrows of promotable temps (non-temps
- // don't get promoted anyway).
- self.validate_local(place.local)?;
+ let loc = candidate.location;
+ let statement = &self.body[loc.block].statements[loc.statement_index];
+ match &statement.kind {
+ StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
+ // We can only promote interior borrows of promotable temps (non-temps
+ // don't get promoted anyway).
+ self.validate_local(place.local)?;
- // The reference operation itself must be promotable.
- // (Needs to come after `validate_local` to avoid ICEs.)
- self.validate_ref(*kind, place)?;
+ // The reference operation itself must be promotable.
+ // (Needs to come after `validate_local` to avoid ICEs.)
+ self.validate_ref(*kind, place)?;
- // We do not check all the projections (they do not get promoted anyway),
- // but we do stay away from promoting anything involving a dereference.
- if place.projection.contains(&ProjectionElem::Deref) {
- return Err(Unpromotable);
- }
-
- // We cannot promote things that need dropping, since the promoted value
- // would not get dropped.
- if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) {
- return Err(Unpromotable);
- }
-
- Ok(())
- }
- _ => bug!(),
+ // We do not check all the projections (they do not get promoted anyway),
+ // but we do stay away from promoting anything involving a dereference.
+ if place.projection.contains(&ProjectionElem::Deref) {
+ return Err(Unpromotable);
}
+
+ // We cannot promote things that need dropping, since the promoted value
+ // would not get dropped.
+ if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
+ return Err(Unpromotable);
+ }
+
+ Ok(())
}
+ _ => bug!(),
}
}
@@ -656,9 +644,7 @@
}
let is_const_fn = match *fn_ty.kind() {
- ty::FnDef(def_id, _) => {
- self.tcx.is_const_fn_raw(def_id) || is_lang_special_const_fn(self.tcx, def_id)
- }
+ ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
_ => false,
};
if !is_const_fn {
@@ -837,11 +823,7 @@
new_temp
}
- fn promote_candidate(
- mut self,
- candidate: Candidate,
- next_promoted_id: usize,
- ) -> Option<Body<'tcx>> {
+ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> {
let def = self.source.source.with_opt_param();
let mut rvalue = {
let promoted = &mut self.promoted;
@@ -877,58 +859,55 @@
}))
};
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
- match candidate {
- Candidate::Ref(loc) => {
- let statement = &mut blocks[loc.block].statements[loc.statement_index];
- match statement.kind {
- StatementKind::Assign(box (
- _,
- Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
- )) => {
- // Use the underlying local for this (necessarily interior) borrow.
- let ty = local_decls.local_decls()[place.local].ty;
- let span = statement.source_info.span;
+ let loc = candidate.location;
+ let statement = &mut blocks[loc.block].statements[loc.statement_index];
+ match statement.kind {
+ StatementKind::Assign(box (
+ _,
+ Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
+ )) => {
+ // Use the underlying local for this (necessarily interior) borrow.
+ let ty = local_decls.local_decls()[place.local].ty;
+ let span = statement.source_info.span;
- let ref_ty = tcx.mk_ref(
- tcx.lifetimes.re_erased,
- ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
- );
+ let ref_ty = tcx.mk_ref(
+ tcx.lifetimes.re_erased,
+ ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
+ );
- *region = tcx.lifetimes.re_erased;
+ *region = tcx.lifetimes.re_erased;
- let mut projection = vec![PlaceElem::Deref];
- projection.extend(place.projection);
- place.projection = tcx.intern_place_elems(&projection);
+ let mut projection = vec![PlaceElem::Deref];
+ projection.extend(place.projection);
+ place.projection = tcx.intern_place_elems(&projection);
- // Create a temp to hold the promoted reference.
- // This is because `*r` requires `r` to be a local,
- // otherwise we would use the `promoted` directly.
- let mut promoted_ref = LocalDecl::new(ref_ty, span);
- promoted_ref.source_info = statement.source_info;
- let promoted_ref = local_decls.push(promoted_ref);
- assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+ // Create a temp to hold the promoted reference.
+ // This is because `*r` requires `r` to be a local,
+ // otherwise we would use the `promoted` directly.
+ let mut promoted_ref = LocalDecl::new(ref_ty, span);
+ promoted_ref.source_info = statement.source_info;
+ let promoted_ref = local_decls.push(promoted_ref);
+ assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
- let promoted_ref_statement = Statement {
- source_info: statement.source_info,
- kind: StatementKind::Assign(Box::new((
- Place::from(promoted_ref),
- Rvalue::Use(promoted_operand(ref_ty, span)),
- ))),
- };
- self.extra_statements.push((loc, promoted_ref_statement));
+ let promoted_ref_statement = Statement {
+ source_info: statement.source_info,
+ kind: StatementKind::Assign(Box::new((
+ Place::from(promoted_ref),
+ Rvalue::Use(promoted_operand(ref_ty, span)),
+ ))),
+ };
+ self.extra_statements.push((loc, promoted_ref_statement));
- Rvalue::Ref(
- tcx.lifetimes.re_erased,
- borrow_kind,
- Place {
- local: mem::replace(&mut place.local, promoted_ref),
- projection: List::empty(),
- },
- )
- }
- _ => bug!(),
- }
+ Rvalue::Ref(
+ tcx.lifetimes.re_erased,
+ borrow_kind,
+ Place {
+ local: mem::replace(&mut place.local, promoted_ref),
+ projection: List::empty(),
+ },
+ )
}
+ _ => bug!(),
}
};
@@ -940,7 +919,7 @@
let span = self.promoted.span;
self.assign(RETURN_PLACE, rvalue, span);
- Some(self.promoted)
+ self.promoted
}
}
@@ -970,17 +949,13 @@
let mut extra_statements = vec![];
for candidate in candidates.into_iter().rev() {
- match candidate {
- Candidate::Ref(Location { block, statement_index }) => {
- if let StatementKind::Assign(box (place, _)) =
- &body[block].statements[statement_index].kind
- {
- if let Some(local) = place.as_local() {
- if temps[local] == TempState::PromotedOut {
- // Already promoted.
- continue;
- }
- }
+ let Location { block, statement_index } = candidate.location;
+ if let StatementKind::Assign(box (place, _)) = &body[block].statements[statement_index].kind
+ {
+ if let Some(local) = place.as_local() {
+ if temps[local] == TempState::PromotedOut {
+ // Already promoted.
+ continue;
}
}
}
@@ -988,7 +963,7 @@
// Declare return place local so that `mir::Body::new` doesn't complain.
let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect();
- let mut scope = body.source_scopes[candidate.source_info(body).scope].clone();
+ let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone();
scope.parent_scope = None;
let promoted = Body::new(
@@ -1013,11 +988,9 @@
keep_original: false,
};
- //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
- if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) {
- promoted.source.promoted = Some(promotions.next_index());
- promotions.push(promoted);
- }
+ let mut promoted = promoter.promote_candidate(candidate, promotions.len());
+ promoted.source.promoted = Some(promotions.next_index());
+ promotions.push(promoted);
}
// Insert each of `extra_statements` before its indicated location, which
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 4996257..e3395df 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -23,7 +23,7 @@
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_index = { path = "../rustc_index", package = "rustc_index" }
bitflags = "1.2.1"
-measureme = "9.1.0"
+measureme = "10.0.0"
libc = "0.2"
stacker = "0.1.14"
tempfile = "3.2"
diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs
index 81e2501..3c7bea2 100644
--- a/compiler/rustc_data_structures/src/base_n.rs
+++ b/compiler/rustc_data_structures/src/base_n.rs
@@ -14,7 +14,7 @@
#[inline]
pub fn push_str(mut n: u128, base: usize, output: &mut String) {
- debug_assert!((2..=MAX_BASE).contains(&base));
+ debug_assert!(base >= 2 && base <= MAX_BASE);
let mut s = [0u8; 128];
let mut index = 0;
diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
index 9ff401c..1aa7ac0 100644
--- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
@@ -206,11 +206,17 @@
AdjacentEdges { graph: self, direction, next: first_edge }
}
- pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
+ pub fn successor_nodes<'a>(
+ &'a self,
+ source: NodeIndex,
+ ) -> impl Iterator<Item = NodeIndex> + 'a {
self.outgoing_edges(source).targets()
}
- pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
+ pub fn predecessor_nodes<'a>(
+ &'a self,
+ target: NodeIndex,
+ ) -> impl Iterator<Item = NodeIndex> + 'a {
self.incoming_edges(target).sources()
}
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 1c6979d..a9db349 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -48,7 +48,7 @@
let node = frame.node;
visited[node] = true;
- for successor in frame.iter.by_ref() {
+ while let Some(successor) = frame.iter.next() {
if !visited[successor] {
stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
continue 'recurse;
@@ -112,7 +112,7 @@
/// This is equivalent to just invoke `next` repeatedly until
/// you get a `None` result.
pub fn complete_search(&mut self) {
- for _ in self {}
+ while let Some(_) = self.next() {}
}
/// Returns true if node has been visited thus far.
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 94e115e..77784bf 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -11,7 +11,6 @@
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(bool_to_option)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index caf515b..25b7a84 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -390,7 +390,7 @@
.map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
.collect();
- self.compress(|_| unreachable!());
+ self.compress(|_| assert!(false));
errors
}
@@ -612,7 +612,7 @@
fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
let orig_nodes_len = self.nodes.len();
let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
- assert!(node_rewrites.is_empty());
+ debug_assert!(node_rewrites.is_empty());
node_rewrites.extend(0..orig_nodes_len);
let mut dead_nodes = 0;
@@ -623,13 +623,13 @@
// self.nodes[0..index - dead_nodes] are the first remaining nodes
// self.nodes[index - dead_nodes..index] are all dead
// self.nodes[index..] are unchanged
- for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() {
+ for index in 0..orig_nodes_len {
let node = &self.nodes[index];
match node.state.get() {
NodeState::Pending | NodeState::Waiting => {
if dead_nodes > 0 {
self.nodes.swap(index, index - dead_nodes);
- *node_rewrite -= dead_nodes;
+ node_rewrites[index] -= dead_nodes;
}
}
NodeState::Done => {
@@ -646,7 +646,7 @@
}
// Extract the success stories.
outcome_cb(&node.obligation);
- *node_rewrite = orig_nodes_len;
+ node_rewrites[index] = orig_nodes_len;
dead_nodes += 1;
}
NodeState::Error => {
@@ -655,7 +655,7 @@
// check against.
self.active_cache.remove(&node.obligation.as_cache_key());
self.insert_into_error_cache(index);
- *node_rewrite = orig_nodes_len;
+ node_rewrites[index] = orig_nodes_len;
dead_nodes += 1;
}
NodeState::Success => unreachable!(),
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 0bbd0ed..c219392 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -110,12 +110,14 @@
const FUNCTION_ARGS = 1 << 6;
const LLVM = 1 << 7;
const INCR_RESULT_HASHING = 1 << 8;
+ const ARTIFACT_SIZES = 1 << 9;
const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
Self::QUERY_PROVIDERS.bits |
Self::QUERY_BLOCKED.bits |
Self::INCR_CACHE_LOADS.bits |
- Self::INCR_RESULT_HASHING.bits;
+ Self::INCR_RESULT_HASHING.bits |
+ Self::ARTIFACT_SIZES.bits;
const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits;
}
@@ -136,6 +138,7 @@
("args", EventFilter::ARGS),
("llvm", EventFilter::LLVM),
("incr-result-hashing", EventFilter::INCR_RESULT_HASHING),
+ ("artifact-sizes", EventFilter::ARTIFACT_SIZES),
];
/// Something that uniquely identifies a query invocation.
@@ -285,6 +288,33 @@
})
}
+ /// Record the size of an artifact that the compiler produces
+ ///
+ /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.)
+ /// `artifact_name` is an identifier to the specific artifact being stored (usually a filename)
+ #[inline(always)]
+ pub fn artifact_size<A>(&self, artifact_kind: &str, artifact_name: A, size: u64)
+ where
+ A: Borrow<str> + Into<String>,
+ {
+ drop(self.exec(EventFilter::ARTIFACT_SIZES, |profiler| {
+ let builder = EventIdBuilder::new(&profiler.profiler);
+ let event_label = profiler.get_or_alloc_cached_string(artifact_kind);
+ let event_arg = profiler.get_or_alloc_cached_string(artifact_name);
+ let event_id = builder.from_label_and_arg(event_label, event_arg);
+ let thread_id = get_thread_id();
+
+ profiler.profiler.record_integer_event(
+ profiler.artifact_size_event_kind,
+ event_id,
+ thread_id,
+ size,
+ );
+
+ TimingGuard::none()
+ }))
+ }
+
#[inline(always)]
pub fn generic_activity_with_args(
&self,
@@ -372,7 +402,7 @@
) {
drop(self.exec(event_filter, |profiler| {
let event_id = StringId::new_virtual(query_invocation_id.0);
- let thread_id = std::thread::current().id().as_u64().get() as u32;
+ let thread_id = get_thread_id();
profiler.profiler.record_instant_event(
event_kind(profiler),
@@ -425,6 +455,7 @@
incremental_result_hashing_event_kind: StringId,
query_blocked_event_kind: StringId,
query_cache_hit_event_kind: StringId,
+ artifact_size_event_kind: StringId,
}
impl SelfProfiler {
@@ -447,6 +478,7 @@
profiler.alloc_string("IncrementalResultHashing");
let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
+ let artifact_size_event_kind = profiler.alloc_string("ArtifactSize");
let mut event_filter_mask = EventFilter::empty();
@@ -491,6 +523,7 @@
incremental_result_hashing_event_kind,
query_blocked_event_kind,
query_cache_hit_event_kind,
+ artifact_size_event_kind,
})
}
@@ -561,7 +594,7 @@
event_kind: StringId,
event_id: EventId,
) -> TimingGuard<'a> {
- let thread_id = std::thread::current().id().as_u64().get() as u32;
+ let thread_id = get_thread_id();
let raw_profiler = &profiler.profiler;
let timing_guard =
raw_profiler.start_recording_interval_event(event_kind, event_id, thread_id);
@@ -655,6 +688,10 @@
format!("{:.3}", dur.as_secs_f64())
}
+fn get_thread_id() -> u32 {
+ std::thread::current().id().as_u64().get() as u32
+}
+
// Memory reporting
cfg_if! {
if #[cfg(windows)] {
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index e80db08..9efea12 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -1,3 +1,4 @@
+use crate::stable_hasher::{HashStable, StableHasher};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::iter::FromIterator;
@@ -16,17 +17,26 @@
/// stores data in a more compact way. It also supports accessing contiguous
/// ranges of elements as a slice, and slices of already sorted elements can be
/// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
-pub struct SortedMap<K: Ord, V> {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+pub struct SortedMap<K, V> {
data: Vec<(K, V)>,
}
-impl<K: Ord, V> SortedMap<K, V> {
+impl<K, V> Default for SortedMap<K, V> {
#[inline]
- pub fn new() -> SortedMap<K, V> {
- SortedMap { data: vec![] }
+ fn default() -> SortedMap<K, V> {
+ SortedMap { data: Vec::new() }
}
+}
+impl<K, V> SortedMap<K, V> {
+ #[inline]
+ pub const fn new() -> SortedMap<K, V> {
+ SortedMap { data: Vec::new() }
+ }
+}
+
+impl<K: Ord, V> SortedMap<K, V> {
/// Construct a `SortedMap` from a presorted set of elements. This is faster
/// than creating an empty map and then inserting the elements individually.
///
@@ -205,10 +215,10 @@
R: RangeBounds<K>,
{
let start = match range.start_bound() {
- Bound::Included(k) => match self.lookup_index_for(k) {
+ Bound::Included(ref k) => match self.lookup_index_for(k) {
Ok(index) | Err(index) => index,
},
- Bound::Excluded(k) => match self.lookup_index_for(k) {
+ Bound::Excluded(ref k) => match self.lookup_index_for(k) {
Ok(index) => index + 1,
Err(index) => index,
},
@@ -216,11 +226,11 @@
};
let end = match range.end_bound() {
- Bound::Included(k) => match self.lookup_index_for(k) {
+ Bound::Included(ref k) => match self.lookup_index_for(k) {
Ok(index) => index + 1,
Err(index) => index,
},
- Bound::Excluded(k) => match self.lookup_index_for(k) {
+ Bound::Excluded(ref k) => match self.lookup_index_for(k) {
Ok(index) | Err(index) => index,
},
Bound::Unbounded => self.data.len(),
@@ -281,5 +291,12 @@
}
}
+impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
+ #[inline]
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.data.hash_stable(ctx, hasher);
+ }
+}
+
#[cfg(test)]
mod tests;
diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index 1395bb1..61c7239 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -34,39 +34,47 @@
}
impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
+ #[inline]
pub fn new() -> Self {
SortedIndexMultiMap { items: IndexVec::new(), idx_sorted_by_item_key: Vec::new() }
}
+ #[inline]
pub fn len(&self) -> usize {
self.items.len()
}
+ #[inline]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
/// Returns an iterator over the items in the map in insertion order.
+ #[inline]
pub fn into_iter(self) -> impl DoubleEndedIterator<Item = (K, V)> {
self.items.into_iter()
}
/// Returns an iterator over the items in the map in insertion order along with their indices.
+ #[inline]
pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator<Item = (I, (K, V))> {
self.items.into_iter_enumerated()
}
/// Returns an iterator over the items in the map in insertion order.
+ #[inline]
pub fn iter(&self) -> impl '_ + DoubleEndedIterator<Item = (&K, &V)> {
self.items.iter().map(|(ref k, ref v)| (k, v))
}
/// Returns an iterator over the items in the map in insertion order along with their indices.
+ #[inline]
pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator<Item = (I, (&K, &V))> {
self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v)))
}
/// Returns the item in the map with the given index.
+ #[inline]
pub fn get(&self, idx: I) -> Option<&(K, V)> {
self.items.get(idx)
}
@@ -75,7 +83,8 @@
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
- pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> {
+ #[inline]
+ pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
self.get_by_key_enumerated(key).map(|(_, v)| v)
}
@@ -84,7 +93,8 @@
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
- pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> {
+ #[inline]
+ pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
let (k, v) = &self.items[i];
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index d4274e9..2de05cd 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -257,7 +257,11 @@
pub fn remove(&mut self, key: &K) -> Option<V> {
match self {
SsoHashMap::Array(array) => {
- array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1)
+ if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+ Some(array.swap_remove(index).1)
+ } else {
+ None
+ }
}
SsoHashMap::Map(map) => map.remove(key),
}
@@ -268,7 +272,11 @@
pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> {
match self {
SsoHashMap::Array(array) => {
- array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index))
+ if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+ Some(array.swap_remove(index))
+ } else {
+ None
+ }
}
SsoHashMap::Map(map) => map.remove_entry(key),
}
@@ -415,14 +423,14 @@
/// adapts Item of array reference iterator to Item of hashmap reference iterator.
#[inline(always)]
-fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) {
+fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
let (a, b) = pair;
(a, b)
}
/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
#[inline(always)]
-fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
+fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
let (a, b) = pair;
(a, b)
}
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index f71522d..29baf4e 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -75,7 +75,7 @@
/// An iterator visiting all elements in arbitrary order.
/// The iterator element type is `&'a T`.
#[inline]
- pub fn iter(&self) -> impl Iterator<Item = &T> {
+ pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
self.into_iter()
}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 2e992e7..f800ec6 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -229,14 +229,14 @@
impl<CTX> HashStable<CTX> for f32 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
- let val: u32 = self.to_bits();
+ let val: u32 = unsafe { ::std::mem::transmute(*self) };
val.hash_stable(ctx, hasher);
}
}
impl<CTX> HashStable<CTX> for f64 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
- let val: u64 = self.to_bits();
+ let val: u64 = unsafe { ::std::mem::transmute(*self) };
val.hash_stable(ctx, hasher);
}
}
@@ -301,6 +301,13 @@
}
}
+impl<CTX> HashStable<CTX> for [u8] {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.len().hash_stable(ctx, hasher);
+ hasher.write(self);
+ }
+}
+
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
#[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs
index ba22c7f..a4964b7 100644
--- a/compiler/rustc_data_structures/src/stack.rs
+++ b/compiler/rustc_data_structures/src/stack.rs
@@ -5,7 +5,6 @@
// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
// on. This flag has performance relevant characteristics. Don't set it too high.
-#[allow(clippy::identity_op)]
const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs
index 9e605ea..9b07f86 100644
--- a/compiler/rustc_data_structures/src/tiny_list.rs
+++ b/compiler/rustc_data_structures/src/tiny_list.rs
@@ -48,7 +48,7 @@
#[inline]
pub fn contains(&self, data: &T) -> bool {
let mut elem = self.head.as_ref();
- while let Some(e) = elem {
+ while let Some(ref e) = elem {
if &e.data == data {
return true;
}
diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs
index ce60d40..1cf030d 100644
--- a/compiler/rustc_data_structures/src/vec_linked_list.rs
+++ b/compiler/rustc_data_structures/src/vec_linked_list.rs
@@ -2,8 +2,8 @@
pub fn iter<Ls>(
first: Option<Ls::LinkIndex>,
- links: &Ls,
-) -> impl Iterator<Item = Ls::LinkIndex> + '_
+ links: &'a Ls,
+) -> impl Iterator<Item = Ls::LinkIndex> + 'a
where
Ls: Links,
{
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 9a57ec9..6ff9434 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -267,6 +267,7 @@
None,
compiler.output_dir(),
compiler.output_file(),
+ compiler.temps_dir(),
);
if should_stop == Compilation::Stop {
@@ -295,6 +296,7 @@
Some(compiler.input()),
compiler.output_dir(),
compiler.output_file(),
+ compiler.temps_dir(),
)
.and_then(|| {
RustcDefaultCalls::list_metadata(
@@ -647,6 +649,7 @@
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
@@ -685,7 +688,7 @@
});
let attrs = attrs.as_ref().unwrap();
let t_outputs = rustc_interface::util::build_output_filenames(
- input, odir, ofile, attrs, sess,
+ input, odir, ofile, temps_dir, attrs, sess,
);
let id = rustc_session::output::find_crate_name(sess, attrs, input);
if *req == PrintRequest::CrateName {
@@ -733,7 +736,12 @@
println!("{}", cfg);
}
}
- RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
+ RelocationModels
+ | CodeModels
+ | TlsModels
+ | TargetCPUs
+ | StackProtectorStrategies
+ | TargetFeatures => {
codegen_backend.print(*req, sess);
}
// Any output here interferes with Cargo's parsing of other printed output
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 8e8bea9..2e9050d 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -59,23 +59,23 @@
}
fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
where
- F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate<'_>) -> A,
+ F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A,
{
match *ppmode {
PpHirMode::Normal => {
let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
- f(&annotation, tcx.hir().krate())
+ f(&annotation, tcx.hir())
}
PpHirMode::Identified => {
let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
- f(&annotation, tcx.hir().krate())
+ f(&annotation, tcx.hir())
}
PpHirMode::Typed => {
abort_on_err(tcx.analysis(()), tcx.sess);
let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
- tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate()))
+ tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir()))
}
}
}
@@ -443,17 +443,27 @@
format!("{:#?}", krate)
}
- Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
+ Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
debug!("pretty printing HIR {:?}", s);
let sess = annotation.sess();
let sm = sess.source_map();
- pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann())
+ let attrs = |id| hir_map.attrs(id);
+ pprust_hir::print_crate(
+ sm,
+ hir_map.root_module(),
+ src_name,
+ src,
+ &attrs,
+ annotation.pp_ann(),
+ )
}),
- HirTree => call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, krate| {
- debug!("pretty printing HIR tree");
- format!("{:#?}", krate)
- }),
+ HirTree => {
+ call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| {
+ debug!("pretty printing HIR tree");
+ format!("{:#?}", hir_map.krate())
+ })
+ }
_ => unreachable!(),
};
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 724e3f7..ce26ff6 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -484,12 +484,13 @@
E0783: include_str!("./error_codes/E0783.md"),
E0784: include_str!("./error_codes/E0784.md"),
E0785: include_str!("./error_codes/E0785.md"),
+E0786: include_str!("./error_codes/E0786.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
-// E0019, merged into E0015
-// E0035, merged into E0087/E0089
-// E0036, merged into E0087/E0089
+// E0019, // merged into E0015
+// E0035, // merged into E0087/E0089
+// E0036, // merged into E0087/E0089
// E0068,
// E0085,
// E0086,
@@ -504,8 +505,8 @@
// E0134,
// E0135,
// E0141,
-// E0153, unused error code
-// E0157, unused error code
+// E0153, // unused error code
+// E0157, // unused error code
// E0159, // use of trait `{}` as struct constructor
// E0163, // merged into E0071
// E0167,
@@ -573,24 +574,24 @@
// between structures with the same definition
// E0385, // {} in an aliasable location
// E0402, // cannot use an outer type parameter in this context
-// E0406, merged into 420
-// E0410, merged into 408
-// E0413, merged into 530
-// E0414, merged into 530
-// E0417, merged into 532
-// E0418, merged into 532
-// E0419, merged into 531
-// E0420, merged into 532
-// E0421, merged into 531
-// E0427, merged into 530
+// E0406, // merged into 420
+// E0410, // merged into 408
+// E0413, // merged into 530
+// E0414, // merged into 530
+// E0417, // merged into 532
+// E0418, // merged into 532
+// E0419, // merged into 531
+// E0420, // merged into 532
+// E0421, // merged into 531
+// E0427, // merged into 530
// E0456, // plugin `..` is not available for triple `..`
E0457, // plugin `..` only found in rlib format, but must be available...
E0460, // found possibly newer version of crate `..`
E0461, // couldn't find crate `..` with expected target triple ..
E0462, // found staticlib `..` instead of rlib or dylib
E0465, // multiple .. candidates for `..` found
-// E0467, removed
-// E0470, removed
+// E0467, // removed
+// E0470, // removed
// E0471, // constant evaluation error (in pattern)
E0472, // llvm_asm! is unsupported on this target
// E0473, // dereference of reference outside its lifetime
@@ -610,8 +611,7 @@
E0490, // a value of type `..` is borrowed for too long
E0514, // metadata version mismatch
E0519, // local crate and dependency have same (crate-name, disambiguator)
- // two dependencies have same (crate-name, disambiguator) but different SVH
- E0523,
+ E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
// E0548, // replaced with a generic attribute input check
@@ -638,7 +638,7 @@
E0711, // a feature has been declared with conflicting stability attributes
E0717, // rustc_promotable without stability attribute
// E0721, // `await` keyword
-// E0723, unstable feature in `const` context
+// E0723, // unstable feature in `const` context
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md
index da53b67..4405a21 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0206.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0206.md
@@ -4,15 +4,12 @@
Erroneous code example:
```compile_fail,E0206
-type Foo = [u8; 256];
-impl Copy for Foo { } // error!
-
#[derive(Copy, Clone)]
struct Bar;
impl Copy for &'static mut Bar { } // error!
```
-You can only implement `Copy` for a struct or an enum. Both of the previous
-examples will fail, because neither `[u8; 256]` nor `&'static mut Bar`
-(mutable reference to `Bar`) is a struct or enum.
+You can only implement `Copy` for a struct or an enum.
+The previous example will fail because `&'static mut Bar`
+is not a struct or enum.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0482.md b/compiler/rustc_error_codes/src/error_codes/E0482.md
index 58ebf43..ad36381 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0482.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0482.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
A lifetime of a returned value does not outlive the function call.
Erroneous code example:
-```compile_fail,E0482
+```compile_fail,E0700
fn prefix<'a>(
words: impl Iterator<Item = &'a str>
) -> impl Iterator<Item = String> { // error!
@@ -41,7 +43,7 @@
A similar lifetime problem might arise when returning closures:
-```compile_fail,E0482
+```compile_fail,E0700
fn foo(
x: &mut Vec<i32>
) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0637.md b/compiler/rustc_error_codes/src/error_codes/E0637.md
index d906895..62d5565 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0637.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0637.md
@@ -1,35 +1,51 @@
-An underscore `_` character has been used as the identifier for a lifetime.
+`'_` lifetime name or `&T` without an explicit lifetime name has been used
+on illegal place.
Erroneous code example:
```compile_fail,E0106,E0637
-fn longest<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
- //^^ `'_` is a reserved lifetime name
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ //^^ `'_` is a reserved lifetime name
if str1.len() > str2.len() {
str1
} else {
str2
}
}
+
+fn and_without_explicit_lifetime<T>()
+where
+ T: Into<&u32>,
+ //^ `&` without an explicit lifetime name
+{
+}
```
-`'_`, cannot be used as a lifetime identifier because it is a reserved for the
-anonymous lifetime. To fix this, use a lowercase letter such as 'a, or a series
-of lowercase letters such as `'foo`. For more information, see [the
-book][bk-no]. For more information on using the anonymous lifetime in rust
-nightly, see [the nightly book][bk-al].
+First, `'_` cannot be used as a lifetime identifier in some places
+because it is a reserved for the anonymous lifetime. Second, `&T`
+without an explicit lifetime name cannot also be used in some places.
+To fix them, use a lowercase letter such as `'a`, or a series
+of lowercase letters such as `'foo`. For more information about lifetime
+identifier, see [the book][bk-no]. For more information on using
+the anonymous lifetime in Rust 2018, see [the Rust 2018 blog post][blog-al].
Corrected example:
```
-fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
+fn underscore_lifetime<'a>(str1: &'a str, str2: &'a str) -> &'a str {
if str1.len() > str2.len() {
str1
} else {
str2
}
}
+
+fn and_without_explicit_lifetime<'foo, T>()
+where
+ T: Into<&'foo u32>,
+{
+}
```
[bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols
-[bk-al]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.html
+[blog-al]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#more-lifetime-elision-rules
diff --git a/compiler/rustc_error_codes/src/error_codes/E0786.md b/compiler/rustc_error_codes/src/error_codes/E0786.md
new file mode 100644
index 0000000..4a9635bf
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0786.md
@@ -0,0 +1,14 @@
+A metadata file was invalid.
+
+Erroneous code example:
+
+```ignore (needs extern files)
+use ::foo; // error: found invalid metadata files for crate `foo`
+```
+
+When loading crates, each crate must have a valid metadata file.
+Invalid files could be caused by filesystem corruption,
+an IO error while reading the file, or (rarely) a bug in the compiler itself.
+
+Consider deleting the file and recreating it,
+or reporting a bug against the compiler.
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 1eb4974..9db8f75 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -66,7 +66,7 @@
/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
match level {
- Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error,
+ Level::Bug | Level::Fatal | Level::Error { .. } => AnnotationType::Error,
Level::Warning => AnnotationType::Warning,
Level::Note => AnnotationType::Note,
Level::Help => AnnotationType::Help,
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 41a7326..e5116cd 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -114,7 +114,7 @@
pub fn is_error(&self) -> bool {
match self.level {
- Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true,
+ Level::Bug | Level::Fatal | Level::Error { .. } | Level::FailureNote => true,
Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false,
}
@@ -465,10 +465,14 @@
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self {
+ let mut suggestions: Vec<_> = suggestions.collect();
+ suggestions.sort();
+ let substitutions = suggestions
+ .into_iter()
+ .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
+ .collect();
self.suggestions.push(CodeSuggestion {
- substitutions: suggestions
- .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
- .collect(),
+ substitutions,
msg: msg.to_owned(),
style: SuggestionStyle::ShowCode,
applicability,
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 7fa29bd..d64a589 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -15,7 +15,7 @@
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{
- CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
+ CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle,
};
@@ -449,11 +449,7 @@
span: &mut MultiSpan,
children: &mut Vec<SubDiagnostic>,
) {
- let source_map = if let Some(ref sm) = source_map {
- sm
- } else {
- return;
- };
+ let Some(source_map) = source_map else { return };
debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children);
self.fix_multispan_in_extern_macros(source_map, span);
for child in children.iter_mut() {
@@ -527,14 +523,27 @@
}
}
-/// An emitter that does nothing when emitting a diagnostic.
-pub struct SilentEmitter;
+/// An emitter that does nothing when emitting a non-fatal diagnostic.
+/// Fatal diagnostics are forwarded to `fatal_handler` to avoid silent
+/// failures of rustc, as witnessed e.g. in issue #89358.
+pub struct SilentEmitter {
+ pub fatal_handler: Handler,
+ pub fatal_note: Option<String>,
+}
impl Emitter for SilentEmitter {
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
- fn emit_diagnostic(&mut self, _: &Diagnostic) {}
+ fn emit_diagnostic(&mut self, d: &Diagnostic) {
+ if d.level == Level::Fatal {
+ let mut d = d.clone();
+ if let Some(ref note) = self.fatal_note {
+ d.note(note);
+ }
+ self.fatal_handler.emit_diagnostic(&d);
+ }
+ }
}
/// Maximum number of lines we will print for a multiline suggestion; arbitrary.
@@ -721,7 +730,7 @@
}
let source_string = match file.get_line(line.line_index - 1) {
- Some(s) => replace_tabs(&*s),
+ Some(s) => normalize_whitespace(&*s),
None => return Vec::new(),
};
@@ -1257,22 +1266,37 @@
}
self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
} else {
+ let mut label_width = 0;
// The failure note level itself does not provide any useful diagnostic information
if *level != Level::FailureNote {
buffer.append(0, level.to_str(), Style::Level(*level));
+ label_width += level.to_str().len();
}
// only render error codes, not lint codes
if let Some(DiagnosticId::Error(ref code)) = *code {
buffer.append(0, "[", Style::Level(*level));
buffer.append(0, &code, Style::Level(*level));
buffer.append(0, "]", Style::Level(*level));
+ label_width += 2 + code.len();
}
let header_style = if is_secondary { Style::HeaderMsg } else { Style::MainHeaderMsg };
if *level != Level::FailureNote {
buffer.append(0, ": ", header_style);
+ label_width += 2;
}
for &(ref text, _) in msg.iter() {
- buffer.append(0, &replace_tabs(text), header_style);
+ // Account for newlines to align output to its label.
+ for (line, text) in normalize_whitespace(text).lines().enumerate() {
+ buffer.append(
+ 0 + line,
+ &format!(
+ "{}{}",
+ if line == 0 { String::new() } else { " ".repeat(label_width) },
+ text
+ ),
+ header_style,
+ );
+ }
}
}
@@ -1526,7 +1550,7 @@
self.draw_line(
&mut buffer,
- &replace_tabs(&unannotated_line),
+ &normalize_whitespace(&unannotated_line),
annotated_file.lines[line_idx + 1].line_index - 1,
last_buffer_line_num,
width_offset,
@@ -1648,7 +1672,7 @@
buffer.puts(
row_num - 1,
max_line_num_len + 3,
- &replace_tabs(
+ &normalize_whitespace(
&*file_lines
.file
.get_line(file_lines.lines[line_pos].line_index)
@@ -1674,7 +1698,7 @@
}
// print the suggestion
- buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
+ buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle);
// Colorize addition/replacements with green.
for &SubstitutionHighlight { start, end } in highlight_parts {
@@ -2057,6 +2081,7 @@
// We replace some characters so the CLI output is always consistent and underlines aligned.
const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
('\t', " "), // We do our own tab replacement
+ ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
@@ -2068,7 +2093,7 @@
('\u{2069}', ""),
];
-fn replace_tabs(str: &str) -> String {
+fn normalize_whitespace(str: &str) -> String {
let mut s = str.to_string();
for (c, replacement) in OUTPUT_REPLACEMENTS {
s = s.replace(*c, replacement);
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 9b2094a..bb3d3a4 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -6,8 +6,9 @@
#![feature(crate_visibility_modifier)]
#![feature(backtrace)]
#![feature(if_let_guard)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(nll)]
#[macro_use]
@@ -410,6 +411,8 @@
/// as well as inconsistent state observation.
struct HandlerInner {
flags: HandlerFlags,
+ /// The number of lint errors that have been emitted.
+ lint_err_count: usize,
/// The number of errors that have been emitted, including duplicates.
///
/// This is not necessarily the count that's reported to the user once
@@ -549,6 +552,7 @@
flags,
inner: Lock::new(HandlerInner {
flags,
+ lint_err_count: 0,
err_count: 0,
warn_count: 0,
deduplicated_err_count: 0,
@@ -725,7 +729,13 @@
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Level::Error, msg)
+ DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
+ }
+
+ /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
+ #[doc(hidden)]
+ pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
@@ -789,11 +799,14 @@
}
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
- self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
+ self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span);
}
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
- self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
+ self.emit_diag_at_span(
+ Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
+ span,
+ );
}
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
@@ -861,6 +874,9 @@
pub fn has_errors(&self) -> bool {
self.inner.borrow().has_errors()
}
+ pub fn has_errors_or_lint_errors(&self) -> bool {
+ self.inner.borrow().has_errors_or_lint_errors()
+ }
pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.inner.borrow().has_errors_or_delayed_span_bugs()
}
@@ -978,7 +994,11 @@
}
}
if diagnostic.is_error() {
- self.bump_err_count();
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.bump_lint_err_count();
+ } else {
+ self.bump_err_count();
+ }
} else {
self.bump_warn_count();
}
@@ -1072,11 +1092,14 @@
fn has_errors(&self) -> bool {
self.err_count() > 0
}
+ fn has_errors_or_lint_errors(&self) -> bool {
+ self.has_errors() || self.lint_err_count > 0
+ }
fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.has_errors() || !self.delayed_span_bugs.is_empty()
}
fn has_any_message(&self) -> bool {
- self.err_count() > 0 || self.warn_count > 0
+ self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
}
fn abort_if_errors(&mut self) {
@@ -1130,7 +1153,7 @@
}
fn err(&mut self, msg: &str) {
- self.emit_error(Error, msg);
+ self.emit_error(Error { lint: false }, msg);
}
/// Emit an error; level should be `Error` or `Fatal`.
@@ -1166,6 +1189,11 @@
}
}
+ fn bump_lint_err_count(&mut self) {
+ self.lint_err_count += 1;
+ self.panic_if_treat_err_as_bug();
+ }
+
fn bump_err_count(&mut self) {
self.err_count += 1;
self.panic_if_treat_err_as_bug();
@@ -1209,7 +1237,10 @@
pub enum Level {
Bug,
Fatal,
- Error,
+ Error {
+ /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
+ lint: bool,
+ },
Warning,
Note,
Help,
@@ -1228,7 +1259,7 @@
fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new();
match self {
- Bug | Fatal | Error => {
+ Bug | Fatal | Error { .. } => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
Warning => {
@@ -1249,7 +1280,7 @@
pub fn to_str(self) -> &'static str {
match self {
Bug => "error: internal compiler error",
- Fatal | Error => "error",
+ Fatal | Error { .. } => "error",
Warning => "warning",
Note => "note",
Help => "help",
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index f548e28..89dbd64 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -383,7 +383,7 @@
Unsafe::No,
ModKind::Loaded(krate.items, Inline::Yes, krate.span)
),
- ident: Ident::invalid(),
+ ident: Ident::empty(),
id: ast::DUMMY_NODE_ID,
vis: ast::Visibility {
span: krate.span.shrink_to_lo(),
@@ -447,9 +447,7 @@
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
- let (invoc, ext) = if let Some(invoc) = invocations.pop() {
- invoc
- } else {
+ let Some((invoc, ext)) = invocations.pop() else {
self.resolve_imports();
if undetermined_invocations.is_empty() {
break;
@@ -1426,7 +1424,7 @@
_ => unreachable!(),
})
}
- ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
+ 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.
@@ -1508,7 +1506,7 @@
_ => {
item.attrs = attrs;
// The crate root is special - don't assign an ID to it.
- if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
+ 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)
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 6dfeb04..4e84a9d 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,9 +1,10 @@
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(destructuring_assignment)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(if_let_guard)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 363cc72..dedc6c6 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -204,7 +204,7 @@
pprust::token_to_string(&token),
);
sess.span_diagnostic.span_err(token.span, &msg);
- TokenTree::MetaVar(token.span, Ident::invalid())
+ TokenTree::MetaVar(token.span, Ident::empty())
}
// There are no more tokens. Just return the `$` we already have.
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 9ed5c8b..88e1623 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -19,9 +19,7 @@
struct Marker(LocalExpnId, Transparency);
impl MutVisitor for Marker {
- fn token_visiting_enabled(&self) -> bool {
- true
- }
+ const VISIT_TOKENS: bool = true;
fn visit_span(&mut self, span: &mut Span) {
*span = span.apply_mark(self.0.to_expn_id(), self.1)
@@ -116,10 +114,8 @@
loop {
// Look at the last frame on the stack.
- let tree = if let Some(tree) = stack.last_mut().unwrap().next() {
- // If it still has a TokenTree we have not looked at yet, use that tree.
- tree
- } else {
+ // If it still has a TokenTree we have not looked at yet, use that tree.
+ let Some(tree) = stack.last_mut().unwrap().next() else {
// This else-case never produces a value for `tree` (it `continue`s or `return`s).
// Otherwise, if we have just reached the end of a sequence and we can keep repeating,
@@ -190,9 +186,7 @@
LockstepIterSize::Constraint(len, _) => {
// We do this to avoid an extra clone above. We know that this is a
// sequence already.
- let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq {
- (sp, seq)
- } else {
+ let mbe::TokenTree::Sequence(sp, seq) = seq else {
unreachable!()
};
diff --git a/compiler/rustc_expand/src/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs
index 0068539..8974d45 100644
--- a/compiler/rustc_expand/src/mut_visit/tests.rs
+++ b/compiler/rustc_expand/src/mut_visit/tests.rs
@@ -15,9 +15,8 @@
struct ToZzIdentMutVisitor;
impl MutVisitor for ToZzIdentMutVisitor {
- fn token_visiting_enabled(&self) -> bool {
- true
- }
+ const VISIT_TOKENS: bool = true;
+
fn visit_ident(&mut self, ident: &mut Ident) {
*ident = Ident::from_str("zz");
}
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 8e78fcb..12b6bc7 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -23,7 +23,7 @@
}
}
- let ident = Ident::invalid();
+ let ident = Ident::empty();
let attrs = Vec::new();
let vis = vis.unwrap_or(ast::Visibility {
span: DUMMY_SP,
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 3f84979..42c17a6 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -24,8 +24,9 @@
span: Span,
input: TokenStream,
) -> Result<TokenStream, ErrorReported> {
+ let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
- self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
+ self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
let mut err = ecx.struct_span_err(span, "proc macro panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
@@ -48,9 +49,10 @@
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorReported> {
+ let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client
- .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
+ .run(&EXEC_STRATEGY, server, annotation, annotated, proc_macro_backtrace)
.map_err(|e| {
let mut err = ecx.struct_span_err(span, "custom attribute panicked");
if let Some(s) = e.as_str() {
@@ -97,19 +99,19 @@
nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
};
+ let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
- let stream =
- match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) {
- Ok(stream) => stream,
- Err(e) => {
- let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
- }
- err.emit();
- return ExpandResult::Ready(vec![]);
+ let stream = match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
+ Ok(stream) => stream,
+ Err(e) => {
+ let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
}
- };
+ err.emit();
+ return ExpandResult::Ready(vec![]);
+ }
+ };
let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
let mut parser =
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 5cb9719..fa9e98b 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,4 +1,4 @@
-use crate::base::{ExtCtxt, ResolverExpand};
+use crate::base::ExtCtxt;
use rustc_ast as ast;
use rustc_ast::token::{self, Nonterminal, NtIdent};
@@ -7,7 +7,7 @@
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::Diagnostic;
+use rustc_errors::{Diagnostic, PResult};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::BuiltinLintDiagnostics;
use rustc_parse::lexer::nfc_normalize;
@@ -53,11 +53,11 @@
}
}
-impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)>
+impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
for TokenTree<Group, Punct, Ident, Literal>
{
fn from_internal(
- ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_>),
+ ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>),
) -> Self {
use rustc_ast::token::*;
@@ -146,10 +146,10 @@
SingleQuote => op!('\''),
Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
- Ident(name, is_raw) => tt!(Ident::new(rustc.sess, name, is_raw)),
+ Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)),
Lifetime(name) => {
let ident = symbol::Ident::new(name, span).without_first_quote();
- stack.push(tt!(Ident::new(rustc.sess, ident.name, false)));
+ stack.push(tt!(Ident::new(rustc.sess(), ident.name, false)));
tt!(Punct::new('\'', true))
}
Literal(lit) => tt!(Literal { lit }),
@@ -181,15 +181,15 @@
Interpolated(nt)
if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) =>
{
- TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span))
+ TokenTree::Ident(Ident::new(rustc.sess(), name.name, is_raw, name.span))
}
Interpolated(nt) => {
- let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No);
+ let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
TokenTree::Group(Group {
delimiter: Delimiter::None,
stream,
span: DelimSpan::from_single(span),
- flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess),
+ flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()),
})
}
@@ -273,7 +273,7 @@
impl ToInternal<rustc_errors::Level> for Level {
fn to_internal(self) -> rustc_errors::Level {
match self {
- Level::Error => rustc_errors::Level::Error,
+ Level::Error => rustc_errors::Level::Error { lint: false },
Level::Warning => rustc_errors::Level::Warning,
Level::Note => rustc_errors::Level::Note,
Level::Help => rustc_errors::Level::Help,
@@ -355,38 +355,38 @@
span: Span,
}
-pub(crate) struct Rustc<'a> {
- resolver: &'a dyn ResolverExpand,
- sess: &'a ParseSess,
+pub(crate) struct Rustc<'a, 'b> {
+ ecx: &'a mut ExtCtxt<'b>,
def_site: Span,
call_site: Span,
mixed_site: Span,
- span_debug: bool,
krate: CrateNum,
rebased_spans: FxHashMap<usize, Span>,
}
-impl<'a> Rustc<'a> {
- pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
- let expn_data = cx.current_expansion.id.expn_data();
+impl<'a, 'b> Rustc<'a, 'b> {
+ pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self {
+ let expn_data = ecx.current_expansion.id.expn_data();
Rustc {
- resolver: cx.resolver,
- sess: cx.parse_sess(),
- def_site: cx.with_def_site_ctxt(expn_data.def_site),
- call_site: cx.with_call_site_ctxt(expn_data.call_site),
- mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
- span_debug: cx.ecfg.span_debug,
+ def_site: ecx.with_def_site_ctxt(expn_data.def_site),
+ call_site: ecx.with_call_site_ctxt(expn_data.call_site),
+ mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site),
krate: expn_data.macro_def_id.unwrap().krate,
rebased_spans: FxHashMap::default(),
+ ecx,
}
}
+ fn sess(&self) -> &ParseSess {
+ self.ecx.parse_sess()
+ }
+
fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) }
}
}
-impl server::Types for Rustc<'_> {
+impl server::Types for Rustc<'_, '_> {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
@@ -401,17 +401,20 @@
type Span = Span;
}
-impl server::FreeFunctions for Rustc<'_> {
+impl server::FreeFunctions for Rustc<'_, '_> {
fn track_env_var(&mut self, var: &str, value: Option<&str>) {
- self.sess.env_depinfo.borrow_mut().insert((Symbol::intern(var), value.map(Symbol::intern)));
+ self.sess()
+ .env_depinfo
+ .borrow_mut()
+ .insert((Symbol::intern(var), value.map(Symbol::intern)));
}
fn track_path(&mut self, path: &str) {
- self.sess.file_depinfo.borrow_mut().insert(Symbol::intern(path));
+ self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path));
}
}
-impl server::TokenStream for Rustc<'_> {
+impl server::TokenStream for Rustc<'_, '_> {
fn new(&mut self) -> Self::TokenStream {
TokenStream::default()
}
@@ -422,13 +425,62 @@
parse_stream_from_source_str(
FileName::proc_macro_source_code(src),
src.to_string(),
- self.sess,
+ self.sess(),
Some(self.call_site),
)
}
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
pprust::tts_to_string(stream)
}
+ fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
+ // Parse the expression from our tokenstream.
+ let expr: PResult<'_, _> = try {
+ let mut p = rustc_parse::stream_to_parser(
+ self.sess(),
+ stream.clone(),
+ Some("proc_macro expand expr"),
+ );
+ let expr = p.parse_expr()?;
+ if p.token != token::Eof {
+ p.unexpected()?;
+ }
+ expr
+ };
+ let expr = expr.map_err(|mut err| err.emit())?;
+
+ // Perform eager expansion on the expression.
+ let expr = self
+ .ecx
+ .expander()
+ .fully_expand_fragment(crate::expand::AstFragment::Expr(expr))
+ .make_expr();
+
+ // NOTE: For now, limit `expand_expr` to exclusively expand to literals.
+ // This may be relaxed in the future.
+ // We don't use `nt_to_tokenstream` as the tokenstream currently cannot
+ // be recovered in the general case.
+ match &expr.kind {
+ ast::ExprKind::Lit(l) => {
+ Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into())
+ }
+ ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
+ ast::ExprKind::Lit(l) => match l.token {
+ token::Lit { kind: token::Integer | token::Float, .. } => {
+ Ok(std::array::IntoIter::new([
+ // FIXME: The span of the `-` token is lost when
+ // parsing, so we cannot faithfully recover it here.
+ tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
+ tokenstream::TokenTree::token(token::Literal(l.token), l.span),
+ ])
+ .collect())
+ }
+ _ => Err(()),
+ },
+ _ => Err(()),
+ },
+ _ => Err(()),
+ }
+ }
fn from_token_tree(
&mut self,
tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
@@ -440,7 +492,7 @@
}
}
-impl server::TokenStreamBuilder for Rustc<'_> {
+impl server::TokenStreamBuilder for Rustc<'_, '_> {
fn new(&mut self) -> Self::TokenStreamBuilder {
tokenstream::TokenStreamBuilder::new()
}
@@ -452,7 +504,7 @@
}
}
-impl server::TokenStreamIter for Rustc<'_> {
+impl server::TokenStreamIter for Rustc<'_, '_> {
fn next(
&mut self,
iter: &mut Self::TokenStreamIter,
@@ -477,7 +529,7 @@
}
}
-impl server::Group for Rustc<'_> {
+impl server::Group for Rustc<'_, '_> {
fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
Group {
delimiter,
@@ -506,7 +558,7 @@
}
}
-impl server::Punct for Rustc<'_> {
+impl server::Punct for Rustc<'_, '_> {
fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
}
@@ -524,9 +576,9 @@
}
}
-impl server::Ident for Rustc<'_> {
+impl server::Ident for Rustc<'_, '_> {
fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
- Ident::new(self.sess, Symbol::intern(string), is_raw, span)
+ Ident::new(self.sess(), Symbol::intern(string), is_raw, span)
}
fn span(&mut self, ident: Self::Ident) -> Self::Span {
ident.span
@@ -536,10 +588,10 @@
}
}
-impl server::Literal for Rustc<'_> {
+impl server::Literal for Rustc<'_, '_> {
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
let name = FileName::proc_macro_source_code(s);
- let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned());
+ let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
let first_span = parser.token.span.data();
let minus_present = parser.eat(&token::BinOp(token::Minus));
@@ -675,7 +727,7 @@
}
}
-impl server::SourceFile for Rustc<'_> {
+impl server::SourceFile for Rustc<'_, '_> {
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
Lrc::ptr_eq(file1, file2)
}
@@ -695,7 +747,7 @@
}
}
-impl server::MultiSpan for Rustc<'_> {
+impl server::MultiSpan for Rustc<'_, '_> {
fn new(&mut self) -> Self::MultiSpan {
vec![]
}
@@ -704,7 +756,7 @@
}
}
-impl server::Diagnostic for Rustc<'_> {
+impl server::Diagnostic for Rustc<'_, '_> {
fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
let mut diag = Diagnostic::new(level.to_internal(), msg);
diag.set_span(MultiSpan::from_spans(spans));
@@ -720,13 +772,13 @@
diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
}
fn emit(&mut self, diag: Self::Diagnostic) {
- self.sess.span_diagnostic.emit_diagnostic(&diag);
+ self.sess().span_diagnostic.emit_diagnostic(&diag);
}
}
-impl server::Span for Rustc<'_> {
+impl server::Span for Rustc<'_, '_> {
fn debug(&mut self, span: Self::Span) -> String {
- if self.span_debug {
+ if self.ecx.ecfg.span_debug {
format!("{:?}", span)
} else {
format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
@@ -742,7 +794,7 @@
self.mixed_site
}
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
- self.sess.source_map().lookup_char_pos(span.lo()).file
+ self.sess().source_map().lookup_char_pos(span.lo()).file
}
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
span.parent_callsite()
@@ -751,11 +803,11 @@
span.source_callsite()
}
fn start(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess.source_map().lookup_char_pos(span.lo());
+ let loc = self.sess().source_map().lookup_char_pos(span.lo());
LineColumn { line: loc.line, column: loc.col.to_usize() }
}
fn end(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess.source_map().lookup_char_pos(span.hi());
+ let loc = self.sess().source_map().lookup_char_pos(span.hi());
LineColumn { line: loc.line, column: loc.col.to_usize() }
}
fn before(&mut self, span: Self::Span) -> Self::Span {
@@ -765,8 +817,8 @@
span.shrink_to_hi()
}
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
- let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
- let other_loc = self.sess.source_map().lookup_char_pos(second.lo());
+ let self_loc = self.sess().source_map().lookup_char_pos(first.lo());
+ let other_loc = self.sess().source_map().lookup_char_pos(second.lo());
if self_loc.file.name != other_loc.file.name {
return None;
@@ -778,7 +830,7 @@
span.with_ctxt(at.ctxt())
}
fn source_text(&mut self, span: Self::Span) -> Option<String> {
- self.sess.source_map().span_to_snippet(span).ok()
+ self.sess().source_map().span_to_snippet(span).ok()
}
/// Saves the provided span into the metadata of
/// *the crate we are currently compiling*, which must
@@ -805,10 +857,10 @@
/// since we've loaded `my_proc_macro` from disk in order to execute it).
/// In this way, we have obtained a span pointing into `my_proc_macro`
fn save_span(&mut self, span: Self::Span) -> usize {
- self.sess.save_proc_macro_span(span)
+ self.sess().save_proc_macro_span(span)
}
fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
- let (resolver, krate, def_site) = (self.resolver, self.krate, self.def_site);
+ let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
*self.rebased_spans.entry(id).or_insert_with(|| {
// FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
// replace it with a def-site context until we are encoding it properly.
@@ -821,11 +873,11 @@
fn ident_name_compatibility_hack(
nt: &Nonterminal,
orig_span: Span,
- rustc: &mut Rustc<'_>,
+ rustc: &mut Rustc<'_, '_>,
) -> Option<(rustc_span::symbol::Ident, bool)> {
if let NtIdent(ident, is_raw) = nt {
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
- let source_map = rustc.sess.source_map();
+ let source_map = rustc.sess().source_map();
let filename = source_map.span_to_filename(orig_span);
if let FileName::Real(RealFileName::LocalPath(path)) = filename {
let matches_prefix = |prefix, filename| {
@@ -846,7 +898,7 @@
let snippet = source_map.span_to_snippet(orig_span);
if snippet.as_deref() == Ok("$name") {
if time_macros_impl {
- rustc.sess.buffer_lint_with_diagnostic(
+ rustc.sess().buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
@@ -871,7 +923,7 @@
.and_then(|c| c.parse::<u32>().ok())
.map_or(false, |v| v < 40)
{
- rustc.sess.buffer_lint_with_diagnostic(
+ rustc.sess().buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
@@ -894,7 +946,7 @@
source_map.span_to_filename(rustc.def_site)
{
if macro_path.to_string_lossy().contains("pin-project-internal-0.") {
- rustc.sess.buffer_lint_with_diagnostic(
+ rustc.sess().buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 0d7a2af..6950fae 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -34,6 +34,9 @@
/// These are used to test this portion of the compiler,
/// they don't actually mean anything.
(accepted, test_accepted_feature, "1.0.0", None, None),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// -------------------------------------------------------------------------
// feature-group-end: for testing purposes
@@ -43,260 +46,269 @@
// feature-group-start: accepted features
// -------------------------------------------------------------------------
- /// Allows using associated `type`s in `trait`s.
- (accepted, associated_types, "1.0.0", None, None),
- /// Allows using assigning a default type to type parameters in algebraic data type definitions.
- (accepted, default_type_params, "1.0.0", None, None),
- // FIXME: explain `globs`.
- (accepted, globs, "1.0.0", None, None),
- /// Allows `macro_rules!` items.
- (accepted, macro_rules, "1.0.0", None, None),
- /// Allows use of `&foo[a..b]` as a slicing syntax.
- (accepted, slicing_syntax, "1.0.0", None, None),
- /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418).
- (accepted, struct_variant, "1.0.0", None, None),
- /// Allows indexing tuples.
- (accepted, tuple_indexing, "1.0.0", None, None),
- /// Allows the use of `if let` expressions.
- (accepted, if_let, "1.0.0", None, None),
- /// Allows the use of `while let` expressions.
- (accepted, while_let, "1.0.0", None, None),
- /// Allows using `#![no_std]`.
- (accepted, no_std, "1.6.0", None, None),
- /// Allows overloading augmented assignment operations like `a += b`.
- (accepted, augmented_assignments, "1.8.0", Some(28235), None),
- /// Allows empty structs and enum variants with braces.
- (accepted, braced_empty_structs, "1.8.0", Some(29720), None),
- /// Allows `#[deprecated]` attribute.
- (accepted, deprecated, "1.9.0", Some(29935), None),
- /// Allows macros to appear in the type position.
- (accepted, type_macros, "1.13.0", Some(27245), None),
- /// Allows use of the postfix `?` operator in expressions.
- (accepted, question_mark, "1.13.0", Some(31436), None),
- /// Allows `..` in tuple (struct) patterns.
- (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None),
- /// Allows some increased flexibility in the name resolution rules,
- /// especially around globs and shadowing (RFC 1560).
- (accepted, item_like_imports, "1.15.0", Some(35120), None),
- /// Allows using `Self` and associated types in struct expressions and patterns.
- (accepted, more_struct_aliases, "1.16.0", Some(37544), None),
- /// Allows elision of `'static` lifetimes in `static`s and `const`s.
- (accepted, static_in_const, "1.17.0", Some(35897), None),
- /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
- (accepted, field_init_shorthand, "1.17.0", Some(37340), None),
- /// Allows the definition recursive static items.
- (accepted, static_recursion, "1.17.0", Some(29719), None),
- /// Allows `pub(restricted)` visibilities (RFC 1422).
- (accepted, pub_restricted, "1.18.0", Some(32409), None),
- /// Allows `#![windows_subsystem]`.
- (accepted, windows_subsystem, "1.18.0", Some(37499), None),
- /// Allows `break {expr}` with a value inside `loop`s.
- (accepted, loop_break_value, "1.19.0", Some(37339), None),
- /// Allows numeric fields in struct expressions and patterns.
- (accepted, relaxed_adts, "1.19.0", Some(35626), None),
- /// Allows coercing non capturing closures to function pointers.
- (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
- /// Allows attributes on struct literal fields.
- (accepted, struct_field_attributes, "1.20.0", Some(38814), None),
- /// Allows the definition of associated constants in `trait` or `impl` blocks.
- (accepted, associated_consts, "1.20.0", Some(29646), None),
- /// Allows usage of the `compile_error!` macro.
- (accepted, compile_error, "1.20.0", Some(40872), None),
- /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414).
- (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None),
- /// Allows `Drop` types in constants (RFC 1440).
- (accepted, drop_types_in_const, "1.22.0", Some(33156), None),
/// Allows the sysV64 ABI to be specified on all platforms
/// instead of just the platforms on which it is the C ABI.
(accepted, abi_sysv64, "1.24.0", Some(36167), None),
- /// Allows `repr(align(16))` struct attribute (RFC 1358).
- (accepted, repr_align, "1.25.0", Some(33626), None),
- /// Allows '|' at beginning of match arms (RFC 1925).
- (accepted, match_beginning_vert, "1.25.0", Some(44101), None),
- /// Allows nested groups in `use` items (RFC 2128).
- (accepted, use_nested_groups, "1.25.0", Some(44494), None),
- /// Allows indexing into constant arrays.
- (accepted, const_indexing, "1.26.0", Some(29947), None),
- /// Allows using `a..=b` and `..=b` as inclusive range syntaxes.
- (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
- /// Allows `..=` in patterns (RFC 1192).
- (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
- /// Allows `fn main()` with return types which implements `Termination` (RFC 1937).
- (accepted, termination_trait, "1.26.0", Some(43301), None),
- /// Allows implementing `Clone` for closures where possible (RFC 2132).
- (accepted, clone_closures, "1.26.0", Some(44490), None),
- /// Allows implementing `Copy` for closures where possible (RFC 2132).
- (accepted, copy_closures, "1.26.0", Some(44490), None),
- /// Allows `impl Trait` in function arguments.
- (accepted, universal_impl_trait, "1.26.0", Some(34511), None),
- /// Allows `impl Trait` in function return types.
- (accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
- /// Allows using the `u128` and `i128` types.
- (accepted, i128_type, "1.26.0", Some(35118), None),
- /// Allows default match binding modes (RFC 2005).
- (accepted, match_default_bindings, "1.26.0", Some(42640), None),
- /// Allows `'_` placeholder lifetimes.
- (accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
- /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327).
- (accepted, generic_param_attrs, "1.27.0", Some(48848), None),
- /// Allows `cfg(target_feature = "...")`.
- (accepted, cfg_target_feature, "1.27.0", Some(29717), None),
- /// Allows `#[target_feature(...)]`.
- (accepted, target_feature, "1.27.0", None, None),
- /// Allows using `dyn Trait` as a syntax for trait objects.
- (accepted, dyn_trait, "1.27.0", Some(44662), None),
- /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940).
- (accepted, fn_must_use, "1.27.0", Some(43302), None),
- /// Allows use of the `:lifetime` macro fragment specifier.
- (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
- /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937).
- (accepted, termination_trait_test, "1.27.0", Some(48854), None),
- /// Allows the `#[global_allocator]` attribute.
- (accepted, global_allocator, "1.28.0", Some(27389), None),
- /// Allows `#[repr(transparent)]` attribute on newtype structs.
- (accepted, repr_transparent, "1.28.0", Some(43036), None),
- /// Allows procedural macros in `proc-macro` crates.
- (accepted, proc_macro, "1.29.0", Some(38356), None),
- /// Allows `foo.rs` as an alternative to `foo/mod.rs`.
- (accepted, non_modrs_mods, "1.30.0", Some(44660), None),
- /// Allows use of the `:vis` macro fragment specifier
- (accepted, macro_vis_matcher, "1.30.0", Some(41022), None),
- /// Allows importing and reexporting macros with `use`,
- /// enables macro modularization in general.
- (accepted, use_extern_macros, "1.30.0", Some(35896), None),
- /// Allows keywords to be escaped for use as identifiers.
- (accepted, raw_identifiers, "1.30.0", Some(48589), None),
- /// Allows attributes scoped to tools.
- (accepted, tool_attributes, "1.30.0", Some(44690), None),
- /// Allows multi-segment paths in attributes and derives.
- (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None),
- /// Allows all literals in attribute lists and values of key-value pairs.
- (accepted, attr_literals, "1.30.0", Some(34981), None),
- /// Allows inferring outlives requirements (RFC 2093).
- (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None),
- /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`.
- /// This defines the behavior of panics.
- (accepted, panic_handler, "1.30.0", Some(44489), None),
- /// Allows `#[used]` to preserve symbols (see llvm.compiler.used).
- (accepted, used, "1.30.0", Some(40289), None),
- /// Allows `crate` in paths.
- (accepted, crate_in_paths, "1.30.0", Some(45477), None),
- /// Allows resolving absolute paths as paths from other crates.
- (accepted, extern_absolute_paths, "1.30.0", Some(44660), None),
- /// Allows access to crate names passed via `--extern` through prelude.
- (accepted, extern_prelude, "1.30.0", Some(44660), None),
- /// Allows parentheses in patterns.
- (accepted, pattern_parentheses, "1.31.0", Some(51087), None),
- /// Allows the definition of `const fn` functions.
- (accepted, min_const_fn, "1.31.0", Some(53555), None),
- /// Allows scoped lints.
- (accepted, tool_lints, "1.31.0", Some(44690), None),
- /// Allows lifetime elision in `impl` headers. For example:
- /// + `impl<I:Iterator> Iterator for &mut Iterator`
- /// + `impl Debug for Foo<'_>`
- (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None),
- /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude.
- (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None),
- /// Allows use of the `:literal` macro fragment specifier (RFC 1576).
- (accepted, macro_literal_matcher, "1.32.0", Some(35625), None),
- /// Allows use of `?` as the Kleene "at most one" operator in macros.
- (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None),
- /// Allows `Self` struct constructor (RFC 2302).
- (accepted, self_struct_ctor, "1.32.0", Some(51994), None),
- /// Allows `Self` in type definitions (RFC 2300).
- (accepted, self_in_typedefs, "1.32.0", Some(49303), None),
- /// Allows `use x::y;` to search `x` in the current scope.
- (accepted, uniform_paths, "1.32.0", Some(53130), None),
- /// Allows integer match exhaustiveness checking (RFC 2591).
- (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None),
- /// Allows `use path as _;` and `extern crate c as _;`.
- (accepted, underscore_imports, "1.33.0", Some(48216), None),
- /// Allows `#[repr(packed(N))]` attribute on structs.
- (accepted, repr_packed, "1.33.0", Some(33158), None),
- /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
- (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
- /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
- (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None),
- /// Allows let bindings, assignments and destructuring in `const` functions and constants.
- /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used
- /// at the same time as let bindings.
- (accepted, const_let, "1.33.0", Some(48821), None),
- /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
- (accepted, cfg_attr_multi, "1.33.0", Some(54881), None),
- /// Allows top level or-patterns (`p | q`) in `if let` and `while let`.
- (accepted, if_while_or_patterns, "1.33.0", Some(48215), None),
- /// Allows `cfg(target_vendor = "...")`.
- (accepted, cfg_target_vendor, "1.33.0", Some(29718), None),
- /// Allows `extern crate self as foo;`.
- /// This puts local crate root into extern prelude under name `foo`.
- (accepted, extern_crate_self, "1.34.0", Some(56409), None),
- /// Allows arbitrary delimited token streams in non-macro attributes.
- (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None),
- /// Allows paths to enum variants on type aliases including `Self`.
- (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None),
- /// Allows using `#[repr(align(X))]` on enums with equivalent semantics
- /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`.
- (accepted, repr_align_enum, "1.37.0", Some(57996), None),
- /// Allows `const _: TYPE = VALUE`.
- (accepted, underscore_const_names, "1.37.0", Some(54912), None),
+ /// Allows the definition of associated constants in `trait` or `impl` blocks.
+ (accepted, associated_consts, "1.20.0", Some(29646), None),
+ /// Allows using associated `type`s in `trait`s.
+ (accepted, associated_types, "1.0.0", None, None),
/// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions.
(accepted, async_await, "1.39.0", Some(50547), None),
+ /// Allows all literals in attribute lists and values of key-value pairs.
+ (accepted, attr_literals, "1.30.0", Some(34981), None),
+ /// Allows overloading augmented assignment operations like `a += b`.
+ (accepted, augmented_assignments, "1.8.0", Some(28235), None),
/// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
- /// Allows attributes in formal function parameters.
- (accepted, param_attrs, "1.39.0", Some(60406), None),
- /// Allows macro invocations in `extern {}` blocks.
- (accepted, macros_in_extern, "1.40.0", Some(49476), None),
- /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
- (accepted, non_exhaustive, "1.40.0", Some(44109), None),
- /// Allows calling constructor functions in `const fn`.
- (accepted, const_constructor, "1.40.0", Some(61456), None),
- /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
- (accepted, cfg_doctest, "1.40.0", Some(62210), None),
- /// Allows relaxing the coherence rules such that
- /// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted.
- (accepted, re_rebalance_coherence, "1.41.0", Some(55437), None),
- /// Allows #[repr(transparent)] on univariant enums (RFC 2645).
- (accepted, transparent_enums, "1.42.0", Some(60405), None),
- /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
- (accepted, slice_patterns, "1.42.0", Some(62254), None),
- /// Allows the use of `if` and `match` in constants.
- (accepted, const_if_match, "1.46.0", Some(49146), None),
- /// Allows the use of `loop` and `while` in constants.
- (accepted, const_loop, "1.46.0", Some(52000), None),
- /// Allows `#[track_caller]` to be used which provides
- /// accurate caller location reporting during panic (RFC 2091).
- (accepted, track_caller, "1.46.0", Some(47809), None),
- /// Allows `#[doc(alias = "...")]`.
- (accepted, doc_alias, "1.48.0", Some(50146), None),
- /// Allows patterns with concurrent by-move and by-ref bindings.
- /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
- (accepted, move_ref_pattern, "1.49.0", Some(68354), None),
- /// The smallest useful subset of const generics.
- (accepted, min_const_generics, "1.51.0", Some(74878), None),
- /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
- (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668), None),
- /// Allows the use of or-patterns (e.g., `0 | 1`).
- (accepted, or_patterns, "1.53.0", Some(54883), None),
- /// Allows defining identifiers beyond ASCII.
- (accepted, non_ascii_idents, "1.53.0", Some(55467), None),
- /// Allows arbitrary expressions in key-value attributes at parse time.
- (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
- /// Allows unsizing coercions in `const fn`.
- (accepted, const_fn_unsize, "1.54.0", Some(64992), None),
- /// Allows `impl Trait` with multiple unrelated lifetimes.
- (accepted, member_constraints, "1.54.0", Some(61997), None),
/// Allows bindings in the subpattern of a binding pattern.
/// For example, you can write `x @ Some(y)`.
(accepted, bindings_after_at, "1.56.0", Some(65490), None),
+ /// Allows empty structs and enum variants with braces.
+ (accepted, braced_empty_structs, "1.8.0", Some(29720), None),
+ /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
+ (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),
+ /// Allows `cfg(target_feature = "...")`.
+ (accepted, cfg_target_feature, "1.27.0", Some(29717), None),
+ /// Allows `cfg(target_vendor = "...")`.
+ (accepted, cfg_target_vendor, "1.33.0", Some(29718), None),
+ /// Allows implementing `Clone` for closures where possible (RFC 2132).
+ (accepted, clone_closures, "1.26.0", Some(44490), None),
+ /// Allows coercing non capturing closures to function pointers.
+ (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
+ /// Allows usage of the `compile_error!` macro.
+ (accepted, compile_error, "1.20.0", Some(40872), None),
+ /// Allows `impl Trait` in function return types.
+ (accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
+ /// Allows calling constructor functions in `const fn`.
+ (accepted, const_constructor, "1.40.0", Some(61456), None),
/// Allows calling `transmute` in const fn
(accepted, const_fn_transmute, "1.56.0", Some(53605), None),
/// Allows accessing fields of unions inside `const` functions.
(accepted, const_fn_union, "1.56.0", Some(51909), None),
- /// Allows macro attributes to observe output of `#[derive]`.
- (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
+ /// Allows unsizing coercions in `const fn`.
+ (accepted, const_fn_unsize, "1.54.0", Some(64992), None),
+ /// Allows the use of `if` and `match` in constants.
+ (accepted, const_if_match, "1.46.0", Some(49146), None),
+ /// Allows indexing into constant arrays.
+ (accepted, const_indexing, "1.26.0", Some(29947), None),
+ /// Allows let bindings, assignments and destructuring in `const` functions and constants.
+ /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used
+ /// at the same time as let bindings.
+ (accepted, const_let, "1.33.0", Some(48821), None),
+ /// Allows the use of `loop` and `while` in constants.
+ (accepted, const_loop, "1.46.0", Some(52000), None),
/// Allows panicking during const eval (producing compile-time errors).
(accepted, const_panic, "1.57.0", Some(51999), None),
+ /// Allows dereferencing raw pointers during const eval.
+ (accepted, const_raw_ptr_deref, "1.58.0", Some(51911), None),
+ /// Allows implementing `Copy` for closures where possible (RFC 2132).
+ (accepted, copy_closures, "1.26.0", Some(44490), None),
+ /// Allows `crate` in paths.
+ (accepted, crate_in_paths, "1.30.0", Some(45477), None),
+ /// Allows using assigning a default type to type parameters in algebraic data type definitions.
+ (accepted, default_type_params, "1.0.0", None, None),
+ /// Allows `#[deprecated]` attribute.
+ (accepted, deprecated, "1.9.0", Some(29935), None),
+ /// Allows `#[doc(alias = "...")]`.
+ (accepted, doc_alias, "1.48.0", Some(50146), None),
+ /// Allows `..` in tuple (struct) patterns.
+ (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None),
+ /// Allows `..=` in patterns (RFC 1192).
+ (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
+ /// Allows `Drop` types in constants (RFC 1440).
+ (accepted, drop_types_in_const, "1.22.0", Some(33156), None),
+ /// Allows using `dyn Trait` as a syntax for trait objects.
+ (accepted, dyn_trait, "1.27.0", Some(44662), None),
+ /// Allows integer match exhaustiveness checking (RFC 2591).
+ (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None),
+ /// Allows arbitrary expressions in key-value attributes at parse time.
+ (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
+ /// Allows resolving absolute paths as paths from other crates.
+ (accepted, extern_absolute_paths, "1.30.0", Some(44660), None),
+ /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude.
+ (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None),
+ /// Allows `extern crate self as foo;`.
+ /// This puts local crate root into extern prelude under name `foo`.
+ (accepted, extern_crate_self, "1.34.0", Some(56409), None),
+ /// Allows access to crate names passed via `--extern` through prelude.
+ (accepted, extern_prelude, "1.30.0", Some(44660), None),
+ /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
+ (accepted, field_init_shorthand, "1.17.0", Some(37340), None),
+ /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940).
+ (accepted, fn_must_use, "1.27.0", Some(43302), None),
+ /// Allows capturing variables in scope using format_args!
+ (accepted, format_args_capture, "1.58.0", Some(67984), None),
+ /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327).
+ (accepted, generic_param_attrs, "1.27.0", Some(48848), None),
+ /// Allows the `#[global_allocator]` attribute.
+ (accepted, global_allocator, "1.28.0", Some(27389), None),
+ // FIXME: explain `globs`.
+ (accepted, globs, "1.0.0", None, None),
+ /// Allows using the `u128` and `i128` types.
+ (accepted, i128_type, "1.26.0", Some(35118), None),
+ /// Allows the use of `if let` expressions.
+ (accepted, if_let, "1.0.0", None, None),
+ /// Allows top level or-patterns (`p | q`) in `if let` and `while let`.
+ (accepted, if_while_or_patterns, "1.33.0", Some(48215), None),
+ /// Allows lifetime elision in `impl` headers. For example:
+ /// + `impl<I:Iterator> Iterator for &mut Iterator`
+ /// + `impl Debug for Foo<'_>`
+ (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None),
+ /// Allows using `a..=b` and `..=b` as inclusive range syntaxes.
+ (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
+ /// Allows inferring outlives requirements (RFC 2093).
+ (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None),
+ /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
+ (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
+ /// Allows some increased flexibility in the name resolution rules,
+ /// especially around globs and shadowing (RFC 1560).
+ (accepted, item_like_imports, "1.15.0", Some(35120), None),
+ /// Allows `break {expr}` with a value inside `loop`s.
+ (accepted, loop_break_value, "1.19.0", Some(37339), None),
+ /// Allows use of `?` as the Kleene "at most one" operator in macros.
+ (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None),
+ /// Allows macro attributes to observe output of `#[derive]`.
+ (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
+ /// Allows use of the `:lifetime` macro fragment specifier.
+ (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
+ /// Allows use of the `:literal` macro fragment specifier (RFC 1576).
+ (accepted, macro_literal_matcher, "1.32.0", Some(35625), None),
+ /// Allows `macro_rules!` items.
+ (accepted, macro_rules, "1.0.0", None, None),
+ /// Allows use of the `:vis` macro fragment specifier
+ (accepted, macro_vis_matcher, "1.30.0", Some(41022), None),
+ /// Allows macro invocations in `extern {}` blocks.
+ (accepted, macros_in_extern, "1.40.0", Some(49476), None),
+ /// Allows '|' at beginning of match arms (RFC 1925).
+ (accepted, match_beginning_vert, "1.25.0", Some(44101), None),
+ /// Allows default match binding modes (RFC 2005).
+ (accepted, match_default_bindings, "1.26.0", Some(42640), None),
+ /// Allows `impl Trait` with multiple unrelated lifetimes.
+ (accepted, member_constraints, "1.54.0", Some(61997), None),
+ /// Allows the definition of `const fn` functions.
+ (accepted, min_const_fn, "1.31.0", Some(53555), None),
+ /// The smallest useful subset of const generics.
+ (accepted, min_const_generics, "1.51.0", Some(74878), None),
+ /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
+ (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None),
+ /// Allows using `Self` and associated types in struct expressions and patterns.
+ (accepted, more_struct_aliases, "1.16.0", Some(37544), None),
+ /// Allows patterns with concurrent by-move and by-ref bindings.
+ /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
+ (accepted, move_ref_pattern, "1.49.0", Some(68354), None),
+ /// Allows using `#![no_std]`.
+ (accepted, no_std, "1.6.0", None, None),
+ /// Allows defining identifiers beyond ASCII.
+ (accepted, non_ascii_idents, "1.53.0", Some(55467), None),
+ /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008).
+ (accepted, non_exhaustive, "1.40.0", Some(44109), None),
+ /// Allows `foo.rs` as an alternative to `foo/mod.rs`.
+ (accepted, non_modrs_mods, "1.30.0", Some(44660), None),
+ /// Allows the use of or-patterns (e.g., `0 | 1`).
+ (accepted, or_patterns, "1.53.0", Some(54883), None),
+ /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`.
+ /// This defines the behavior of panics.
+ (accepted, panic_handler, "1.30.0", Some(44489), None),
+ /// Allows attributes in formal function parameters.
+ (accepted, param_attrs, "1.39.0", Some(60406), None),
+ /// Allows parentheses in patterns.
+ (accepted, pattern_parentheses, "1.31.0", Some(51087), None),
+ /// Allows procedural macros in `proc-macro` crates.
+ (accepted, proc_macro, "1.29.0", Some(38356), None),
+ /// Allows multi-segment paths in attributes and derives.
+ (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None),
+ /// Allows `pub(restricted)` visibilities (RFC 1422).
+ (accepted, pub_restricted, "1.18.0", Some(32409), None),
+ /// Allows use of the postfix `?` operator in expressions.
+ (accepted, question_mark, "1.13.0", Some(31436), None),
+ /// Allows keywords to be escaped for use as identifiers.
+ (accepted, raw_identifiers, "1.30.0", Some(48589), None),
+ /// Allows relaxing the coherence rules such that
+ /// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted.
+ (accepted, re_rebalance_coherence, "1.41.0", Some(55437), None),
+ /// Allows numeric fields in struct expressions and patterns.
+ (accepted, relaxed_adts, "1.19.0", Some(35626), None),
+ /// Lessens the requirements for structs to implement `Unsize`.
+ (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None),
+ /// Allows `repr(align(16))` struct attribute (RFC 1358).
+ (accepted, repr_align, "1.25.0", Some(33626), None),
+ /// Allows using `#[repr(align(X))]` on enums with equivalent semantics
+ /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`.
+ (accepted, repr_align_enum, "1.37.0", Some(57996), None),
+ /// Allows `#[repr(packed(N))]` attribute on structs.
+ (accepted, repr_packed, "1.33.0", Some(33158), None),
+ /// Allows `#[repr(transparent)]` attribute on newtype structs.
+ (accepted, repr_transparent, "1.28.0", Some(43036), None),
+ /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414).
+ (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None),
+ /// Allows `Self` in type definitions (RFC 2300).
+ (accepted, self_in_typedefs, "1.32.0", Some(49303), None),
+ /// Allows `Self` struct constructor (RFC 2302).
+ (accepted, self_struct_ctor, "1.32.0", Some(51994), None),
+ /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
+ (accepted, slice_patterns, "1.42.0", Some(62254), None),
+ /// Allows use of `&foo[a..b]` as a slicing syntax.
+ (accepted, slicing_syntax, "1.0.0", None, None),
+ /// Allows elision of `'static` lifetimes in `static`s and `const`s.
+ (accepted, static_in_const, "1.17.0", Some(35897), None),
+ /// Allows the definition recursive static items.
+ (accepted, static_recursion, "1.17.0", Some(29719), None),
+ /// Allows attributes on struct literal fields.
+ (accepted, struct_field_attributes, "1.20.0", Some(38814), None),
+ /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418).
+ (accepted, struct_variant, "1.0.0", None, None),
+ /// Allows `#[target_feature(...)]`.
+ (accepted, target_feature, "1.27.0", None, None),
+ /// Allows `fn main()` with return types which implements `Termination` (RFC 1937).
+ (accepted, termination_trait, "1.26.0", Some(43301), None),
+ /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937).
+ (accepted, termination_trait_test, "1.27.0", Some(48854), None),
+ /// Allows attributes scoped to tools.
+ (accepted, tool_attributes, "1.30.0", Some(44690), None),
+ /// Allows scoped lints.
+ (accepted, tool_lints, "1.31.0", Some(44690), None),
+ /// Allows `#[track_caller]` to be used which provides
+ /// accurate caller location reporting during panic (RFC 2091).
+ (accepted, track_caller, "1.46.0", Some(47809), None),
+ /// Allows #[repr(transparent)] on univariant enums (RFC 2645).
+ (accepted, transparent_enums, "1.42.0", Some(60405), None),
+ /// Allows indexing tuples.
+ (accepted, tuple_indexing, "1.0.0", None, None),
+ /// Allows paths to enum variants on type aliases including `Self`.
+ (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None),
+ /// Allows macros to appear in the type position.
+ (accepted, type_macros, "1.13.0", Some(27245), None),
+ /// Allows `const _: TYPE = VALUE`.
+ (accepted, underscore_const_names, "1.37.0", Some(54912), None),
+ /// Allows `use path as _;` and `extern crate c as _;`.
+ (accepted, underscore_imports, "1.33.0", Some(48216), None),
+ /// Allows `'_` placeholder lifetimes.
+ (accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
+ /// Allows `use x::y;` to search `x` in the current scope.
+ (accepted, uniform_paths, "1.32.0", Some(53130), None),
+ /// Allows `impl Trait` in function arguments.
+ (accepted, universal_impl_trait, "1.26.0", Some(34511), None),
+ /// Allows arbitrary delimited token streams in non-macro attributes.
+ (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None),
+ /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
+ (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668), None),
+ /// Allows importing and reexporting macros with `use`,
+ /// enables macro modularization in general.
+ (accepted, use_extern_macros, "1.30.0", Some(35896), None),
+ /// Allows nested groups in `use` items (RFC 2128).
+ (accepted, use_nested_groups, "1.25.0", Some(44494), None),
+ /// Allows `#[used]` to preserve symbols (see llvm.compiler.used).
+ (accepted, used, "1.30.0", Some(40289), None),
+ /// Allows the use of `while let` expressions.
+ (accepted, while_let, "1.0.0", None, None),
+ /// Allows `#![windows_subsystem]`.
+ (accepted, windows_subsystem, "1.18.0", Some(37499), None),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// -------------------------------------------------------------------------
// feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 0ba7640..7860f92 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -101,9 +101,13 @@
}
}
+// See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more
+// documentation about handling feature gates.
+//
// If you change this, please modify `src/doc/unstable-book` as well.
//
-// Don't ever remove anything from this list; move them to `removed.rs`.
+// Don't ever remove anything from this list; move them to `accepted.rs` if
+// accepted or `removed.rs` if removed.
//
// The version numbers here correspond to the version in which the current status
// was set. This is most important for knowing when a particular feature became
@@ -118,130 +122,103 @@
#[rustfmt::skip]
declare_features! (
// -------------------------------------------------------------------------
- // feature-group-start: internal feature gates
+ // feature-group-start: internal feature gates (no tracking issue)
// -------------------------------------------------------------------------
-
// no-tracking-issue-start
- /// Allows using `rustc_*` attributes (RFC 572).
- (active, rustc_attrs, "1.0.0", None, None),
-
- /// Allows using compiler's own crates.
- (active, rustc_private, "1.0.0", Some(27812), None),
-
- /// Allows using the `rust-intrinsic`'s "ABI".
- (active, intrinsics, "1.0.0", None, None),
-
- /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
- (active, lang_items, "1.0.0", None, None),
-
- /// Allows using the `#[stable]` and `#[unstable]` attributes.
- (active, staged_api, "1.0.0", None, None),
-
- /// Allows using `#[allow_internal_unstable]`. This is an
- /// attribute on `macro_rules!` and can't use the attribute handling
- /// below (it has to be checked before expansion possibly makes
- /// macros disappear).
- (active, allow_internal_unstable, "1.0.0", None, None),
-
+ /// Allows using the `thiscall` ABI.
+ (active, abi_thiscall, "1.19.0", None, None),
+ /// Allows using the `unadjusted` ABI; perma-unstable.
+ (active, abi_unadjusted, "1.16.0", None, None),
+ /// Allows using the `vectorcall` ABI.
+ (active, abi_vectorcall, "1.7.0", None, None),
+ /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
+ (active, allocator_internals, "1.20.0", None, None),
/// Allows using `#[allow_internal_unsafe]`. This is an
/// attribute on `macro_rules!` and can't use the attribute handling
/// below (it has to be checked before expansion possibly makes
/// macros disappear).
(active, allow_internal_unsafe, "1.0.0", None, None),
-
- /// no-tracking-issue-end
-
- /// Allows using `#[link_name="llvm.*"]`.
- (active, link_llvm_intrinsics, "1.0.0", Some(29602), None),
-
- /// Allows using the `box $expr` syntax.
- (active, box_syntax, "1.0.0", Some(49733), None),
-
- /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
- (active, start, "1.0.0", Some(29633), None),
-
- /// Allows using the `#[fundamental]` attribute.
- (active, fundamental, "1.0.0", Some(29635), None),
-
- /// Allows using the `rust-call` ABI.
- (active, unboxed_closures, "1.0.0", Some(29625), None),
-
- /// Allows using the `#[linkage = ".."]` attribute.
- (active, linkage, "1.0.0", Some(29603), None),
-
- /// Allows using `box` in patterns (RFC 469).
- (active, box_patterns, "1.0.0", Some(29641), None),
-
- // no-tracking-issue-start
-
- /// Allows using `#[prelude_import]` on glob `use` items.
- (active, prelude_import, "1.2.0", None, None),
-
- // no-tracking-issue-end
-
- // no-tracking-issue-start
-
- /// Allows using `#[omit_gdb_pretty_printer_section]`.
- (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
-
- /// Allows using the `vectorcall` ABI.
- (active, abi_vectorcall, "1.7.0", None, None),
-
- // no-tracking-issue-end
-
- /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
- /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
- /// feature with the same name exists.
- (active, structural_match, "1.8.0", Some(31434), None),
-
- /// Allows using the `may_dangle` attribute (RFC 1327).
- (active, dropck_eyepatch, "1.10.0", Some(34761), None),
-
- /// Allows using the `#![panic_runtime]` attribute.
- (active, panic_runtime, "1.10.0", Some(32837), None),
-
- /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed.
- (active, needs_panic_runtime, "1.10.0", Some(32837), None),
-
- // no-tracking-issue-start
-
+ /// Allows using `#[allow_internal_unstable]`. This is an
+ /// attribute on `macro_rules!` and can't use the attribute handling
+ /// below (it has to be checked before expansion possibly makes
+ /// macros disappear).
+ (active, allow_internal_unstable, "1.0.0", None, None),
/// Allows identifying the `compiler_builtins` crate.
(active, compiler_builtins, "1.13.0", None, None),
-
- /// Allows using the `unadjusted` ABI; perma-unstable.
- (active, abi_unadjusted, "1.16.0", None, None),
-
- /// Used to identify crates that contain the profiler runtime.
- (active, profiler_runtime, "1.18.0", None, None),
-
- /// Allows using the `thiscall` ABI.
- (active, abi_thiscall, "1.19.0", None, None),
-
- /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
- (active, allocator_internals, "1.20.0", None, None),
-
- /// Added for testing E0705; perma-unstable.
- (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
-
+ /// Allows using the `rust-intrinsic`'s "ABI".
+ (active, intrinsics, "1.0.0", None, None),
+ /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
+ (active, lang_items, "1.0.0", None, None),
/// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`,
/// it is not on path for eventual stabilization).
(active, no_niche, "1.42.0", None, None),
+ /// Allows using `#[omit_gdb_pretty_printer_section]`.
+ (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
+ /// Allows using `#[prelude_import]` on glob `use` items.
+ (active, prelude_import, "1.2.0", None, None),
+ /// Used to identify crates that contain the profiler runtime.
+ (active, profiler_runtime, "1.18.0", None, None),
+ /// Allows using `rustc_*` attributes (RFC 572).
+ (active, rustc_attrs, "1.0.0", None, None),
+ /// Allows using the `#[stable]` and `#[unstable]` attributes.
+ (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)),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
- /// Allows using `#[rustc_allow_const_fn_unstable]`.
- /// This is an attribute on `const fn` for the same
- /// purpose as `#[allow_internal_unstable]`.
- (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
+ // no-tracking-issue-end
+ // -------------------------------------------------------------------------
+ // feature-group-end: internal feature gates (no tracking issue)
+ // -------------------------------------------------------------------------
+
+ // -------------------------------------------------------------------------
+ // feature-group-start: internal feature gates
+ // -------------------------------------------------------------------------
/// Allows features specific to auto traits.
/// Renamed from `optin_builtin_traits`.
(active, auto_traits, "1.50.0", Some(13231), None),
-
+ /// Allows using `box` in patterns (RFC 469).
+ (active, box_patterns, "1.0.0", Some(29641), None),
+ /// Allows using the `box $expr` syntax.
+ (active, box_syntax, "1.0.0", Some(49733), None),
/// Allows `#[doc(notable_trait)]`.
/// Renamed from `doc_spotlight`.
(active, doc_notable_trait, "1.52.0", Some(45040), None),
-
- // no-tracking-issue-end
+ /// Allows using the `may_dangle` attribute (RFC 1327).
+ (active, dropck_eyepatch, "1.10.0", Some(34761), None),
+ /// Allows using the `#[fundamental]` attribute.
+ (active, fundamental, "1.0.0", Some(29635), None),
+ /// Allows using `#[link_name="llvm.*"]`.
+ (active, link_llvm_intrinsics, "1.0.0", Some(29602), None),
+ /// Allows using the `#[linkage = ".."]` attribute.
+ (active, linkage, "1.0.0", Some(29603), None),
+ /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed.
+ (active, needs_panic_runtime, "1.10.0", Some(32837), None),
+ /// Allows using the `#![panic_runtime]` attribute.
+ (active, panic_runtime, "1.10.0", Some(32837), None),
+ /// Allows using `#[rustc_allow_const_fn_unstable]`.
+ /// This is an attribute on `const fn` for the same
+ /// purpose as `#[allow_internal_unstable]`.
+ (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
+ /// Allows using compiler's own crates.
+ (active, rustc_private, "1.0.0", Some(27812), None),
+ /// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`.
+ (active, rustdoc_internals, "1.58.0", Some(90418), None),
+ /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
+ (active, start, "1.0.0", Some(29633), None),
+ /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
+ /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
+ /// feature with the same name exists.
+ (active, structural_match, "1.8.0", Some(31434), None),
+ /// Allows using the `rust-call` ABI.
+ (active, unboxed_closures, "1.0.0", Some(29625), None),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// -------------------------------------------------------------------------
// feature-group-end: internal feature gates
@@ -254,23 +231,26 @@
// FIXME: Document these and merge with the list below.
// Unstable `#[target_feature]` directives.
- (active, arm_target_feature, "1.27.0", Some(44839), None),
(active, aarch64_target_feature, "1.27.0", Some(44839), None),
- (active, hexagon_target_feature, "1.27.0", Some(44839), None),
- (active, powerpc_target_feature, "1.27.0", Some(44839), None),
- (active, mips_target_feature, "1.27.0", Some(44839), None),
+ (active, adx_target_feature, "1.32.0", Some(44839), None),
+ (active, arm_target_feature, "1.27.0", Some(44839), None),
(active, avx512_target_feature, "1.27.0", Some(44839), None),
+ (active, bpf_target_feature, "1.54.0", Some(44839), None),
+ (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
+ (active, ermsb_target_feature, "1.49.0", Some(44839), None),
+ (active, f16c_target_feature, "1.36.0", Some(44839), None),
+ (active, hexagon_target_feature, "1.27.0", Some(44839), None),
+ (active, mips_target_feature, "1.27.0", Some(44839), None),
+ (active, movbe_target_feature, "1.34.0", Some(44839), None),
+ (active, powerpc_target_feature, "1.27.0", Some(44839), None),
+ (active, riscv_target_feature, "1.45.0", Some(44839), None),
+ (active, rtm_target_feature, "1.35.0", Some(44839), None),
(active, sse4a_target_feature, "1.27.0", Some(44839), None),
(active, tbm_target_feature, "1.27.0", Some(44839), None),
(active, wasm_target_feature, "1.30.0", Some(44839), None),
- (active, adx_target_feature, "1.32.0", Some(44839), None),
- (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
- (active, movbe_target_feature, "1.34.0", Some(44839), None),
- (active, rtm_target_feature, "1.35.0", Some(44839), None),
- (active, f16c_target_feature, "1.36.0", Some(44839), None),
- (active, riscv_target_feature, "1.45.0", Some(44839), None),
- (active, ermsb_target_feature, "1.49.0", Some(44839), None),
- (active, bpf_target_feature, "1.54.0", Some(44839), None),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates (target features)
@@ -280,65 +260,273 @@
// feature-group-start: actual feature gates
// -------------------------------------------------------------------------
- /// Allows using `#![plugin(myplugin)]`.
- (active, plugin, "1.0.0", Some(29597), None),
-
- /// Allows using `#[thread_local]` on `static` items.
- (active, thread_local, "1.0.0", Some(29594), None),
-
- /// Allows the use of SIMD types in functions declared in `extern` blocks.
- (active, simd_ffi, "1.0.0", Some(27731), None),
-
- /// Allows using non lexical lifetimes (RFC 2094).
- (active, nll, "1.0.0", Some(43234), None),
-
+ /// Allows using the `amdgpu-kernel` ABI.
+ (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
+ /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
+ (active, abi_avr_interrupt, "1.45.0", Some(69664), None),
+ /// Allows `extern "C-cmse-nonsecure-call" fn()`.
+ (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
+ /// Allows using the `efiapi` ABI.
+ (active, abi_efiapi, "1.40.0", Some(65815), None),
+ /// Allows `extern "msp430-interrupt" fn()`.
+ (active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
+ /// Allows `extern "ptx-*" fn()`.
+ (active, abi_ptx, "1.15.0", Some(38788), None),
+ /// Allows `extern "x86-interrupt" fn()`.
+ (active, abi_x86_interrupt, "1.17.0", Some(40180), None),
+ /// Allows additional const parameter types, such as `&'static str` or user defined types
+ (incomplete, adt_const_params, "1.56.0", Some(44580), None),
+ /// Allows 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),
+ /// Enables experimental inline assembly support for additional architectures.
+ (active, asm_experimental_arch, "1.58.0", Some(72016), None),
+ /// Allows using `sym` operands in inline assembly.
+ (active, asm_sym, "1.58.0", Some(72016), None),
+ /// Allows the user of associated type bounds.
+ (active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows associated type defaults.
(active, associated_type_defaults, "1.2.0", Some(29661), None),
-
- /// Allows `#![no_core]`.
- (active, no_core, "1.3.0", Some(29639), None),
-
- /// Allows default type parameters to influence type inference.
- (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
-
- /// Allows `repr(simd)` and importing the various simd intrinsics.
- (active, repr_simd, "1.4.0", Some(27731), None),
-
- /// Allows `extern "platform-intrinsic" { ... }`.
- (active, platform_intrinsics, "1.4.0", Some(27731), None),
-
- /// Allows attributes on expressions and non-item statements.
- (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
-
- /// Allows the use of type ascription in expressions.
- (active, type_ascription, "1.6.0", Some(23416), None),
-
+ /// Allows `async || body` closures.
+ (active, async_closure, "1.37.0", Some(62290), None),
+ /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
+ (active, c_unwind, "1.52.0", Some(74990), None),
+ /// Allows using C-variadics.
+ (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_thread_local)`.
(active, cfg_target_thread_local, "1.7.0", Some(29594), None),
-
- /// Allows specialization of implementations (RFC 1210).
- (incomplete, specialization, "1.7.0", Some(31844), None),
-
+ /// Allow conditional compilation depending on rust version
+ (active, cfg_version, "1.45.0", Some(64796), None),
+ /// Allows `#[track_caller]` on closures and generators.
+ (active, closure_track_caller, "1.57.0", Some(87417), None),
+ /// Allows to use the `#[cmse_nonsecure_entry]` attribute.
+ (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
+ /// Allows `async {}` expressions in const contexts.
+ (active, const_async_blocks, "1.53.0", Some(85368), None),
+ // Allows limiting the evaluation steps of const expressions
+ (active, const_eval_limit, "1.43.0", Some(67217), None),
+ /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
+ (active, const_extern_fn, "1.40.0", Some(64926), None),
+ /// Allows basic arithmetic on floating point types in a `const fn`.
+ (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
+ /// 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),
+ /// Allows `for _ in _` loops in const contexts.
+ (active, const_for, "1.56.0", Some(87575), None),
+ /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
+ (active, const_generics_defaults, "1.51.0", Some(44580), None),
+ /// Allows argument and return position `impl Trait` in a `const fn`.
+ (active, const_impl_trait, "1.48.0", Some(77463), None),
+ /// Allows using `&mut` in constant functions.
+ (active, const_mut_refs, "1.41.0", Some(57349), None),
+ /// Be more precise when looking for live drops in a const context.
+ (active, const_precise_live_drops, "1.46.0", Some(73255), None),
+ /// Allows references to types with interior mutability within constants
+ (active, const_refs_to_cell, "1.51.0", Some(80384), None),
+ /// Allows `impl const Trait for T` syntax.
+ (active, const_trait_impl, "1.42.0", Some(67792), None),
+ /// Allows the `?` operator in const contexts.
+ (active, const_try, "1.56.0", Some(74935), None),
+ /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
+ (active, crate_visibility_modifier, "1.23.0", Some(53120), None),
+ /// Allows non-builtin attributes in inner attribute position.
+ (active, custom_inner_attributes, "1.30.0", Some(54726), None),
+ /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
+ (active, custom_test_frameworks, "1.30.0", Some(50297), None),
+ /// Allows declarative macros 2.0 (`macro`).
+ (active, decl_macro, "1.17.0", Some(39412), None),
+ /// Allows rustc to inject a default alloc_error_handler
+ (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
+ /// Allows default type parameters to influence type inference.
+ (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
+ /// Allows `#[derive(Default)]` and `#[default]` on enums.
+ (active, derive_default_enum, "1.56.0", Some(86985), None),
+ /// Allows the use of destructuring assignments.
+ (active, destructuring_assignment, "1.49.0", Some(71126), None),
+ /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
+ (active, doc_auto_cfg, "1.58.0", Some(43781), None),
+ /// Allows `#[doc(cfg(...))]`.
+ (active, doc_cfg, "1.21.0", Some(43781), None),
+ /// Allows `#[doc(cfg_hide(...))]`.
+ (active, doc_cfg_hide, "1.57.0", Some(43781), None),
+ /// Allows `#[doc(masked)]`.
+ (active, doc_masked, "1.21.0", Some(44027), None),
+ /// Allows `X..Y` patterns.
+ (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
+ /// Allows exhaustive pattern matching on types that contain uninhabited types.
+ (active, exhaustive_patterns, "1.13.0", Some(51085), None),
+ /// Allows explicit generic arguments specification with `impl Trait` present.
+ (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None),
+ /// Allows defining `extern type`s.
+ (active, extern_types, "1.23.0", Some(43467), None),
+ /// Allows the use of `#[ffi_const]` on foreign functions.
+ (active, ffi_const, "1.45.0", Some(58328), None),
+ /// Allows the use of `#[ffi_pure]` on foreign functions.
+ (active, ffi_pure, "1.45.0", Some(58329), None),
+ /// Allows using `#[ffi_returns_twice]` on foreign functions.
+ (active, ffi_returns_twice, "1.34.0", Some(58314), None),
+ /// Allows using `#[repr(align(...))]` on function items
+ (active, fn_align, "1.53.0", Some(82232), None),
+ /// Allows defining generators.
+ (active, generators, "1.21.0", Some(43122), None),
+ /// Infer generic args for both consts and types.
+ (active, generic_arg_infer, "1.55.0", Some(85077), None),
+ /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
+ (active, generic_associated_types, "1.23.0", Some(44265), None),
+ /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
+ (incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
+ /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
+ (active, half_open_range_patterns, "1.41.0", Some(67264), None),
+ /// Allows `if let` guard in match arms.
+ (active, if_let_guard, "1.47.0", Some(51114), None),
+ /// Allows using imported `main` function
+ (active, imported_main, "1.53.0", Some(28937), None),
+ /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
+ (active, in_band_lifetimes, "1.23.0", Some(44524), None),
+ /// Allows inferring `'static` outlives requirements (RFC 2093).
+ (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
+ /// Allows associated types in inherent impls.
+ (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
+ /// Allow anonymous constants from an inline `const` block
+ (active, inline_const, "1.49.0", Some(76001), None),
+ /// Allow anonymous constants from an inline `const` block in pattern position
+ (incomplete, inline_const_pat, "1.58.0", Some(76001), None),
+ /// Allows using `pointer` and `reference` in intra-doc links
+ (active, intra_doc_pointers, "1.51.0", Some(80896), None),
+ /// Allows `#[instruction_set(_)]` attribute
+ (active, isa_attribute, "1.48.0", Some(74727), None),
+ /// Allows `'a: { break 'a; }`.
+ (active, label_break_value, "1.28.0", Some(48594), None),
+ // 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),
+ /// Allows `let...else` statements.
+ (active, let_else, "1.56.0", Some(87335), None),
+ /// Allows `#[link(..., cfg(..))]`.
+ (active, link_cfg, "1.14.0", Some(37406), None),
+ /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
+ (active, lint_reasons, "1.31.0", Some(54503), None),
+ /// Allows `#[marker]` on certain traits allowing overlapping implementations.
+ (active, marker_trait_attr, "1.30.0", Some(29864), None),
/// A minimal, sound subset of specialization intended to be used by the
/// standard library until the soundness issues with specialization
/// are fixed.
(active, min_specialization, "1.7.0", Some(31844), None),
-
+ /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
+ (active, more_qualified_paths, "1.54.0", Some(86935), None),
+ /// Allows the `#[must_not_suspend]` attribute.
+ (active, must_not_suspend, "1.57.0", Some(83310), None),
/// Allows using `#[naked]` on functions.
(active, naked_functions, "1.9.0", Some(32408), None),
-
- /// Allows `cfg(target_has_atomic = "...")`.
- (active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
-
- /// Allows `X..Y` patterns.
- (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
-
+ /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
+ (active, native_link_modifiers, "1.53.0", Some(81490), None),
+ /// Allows specifying the as-needed link modifier
+ (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
+ /// Allows specifying the bundle link modifier
+ (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
+ /// Allows specifying the verbatim link modifier
+ (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
+ /// Allows specifying the whole-archive link modifier
+ (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None),
+ /// Allow negative trait implementations.
+ (active, negative_impls, "1.44.0", Some(68318), None),
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
(active, never_type, "1.13.0", Some(35121), None),
-
- /// Allows exhaustive pattern matching on types that contain uninhabited types.
- (active, exhaustive_patterns, "1.13.0", Some(51085), None),
-
+ /// Allows diverging expressions to fall back to `!` rather than `()`.
+ (active, never_type_fallback, "1.41.0", Some(65992), None),
+ /// Allows using non lexical lifetimes (RFC 2094).
+ (active, nll, "1.0.0", Some(43234), None),
+ /// Allows `#![no_core]`.
+ (active, no_core, "1.3.0", Some(29639), None),
+ /// Allows function attribute `#[no_coverage]`, to bypass coverage
+ /// instrumentation of that function.
+ (active, no_coverage, "1.53.0", Some(84605), None),
+ /// Allows the use of `no_sanitize` attribute.
+ (active, no_sanitize, "1.42.0", Some(39699), None),
+ /// Allows using the `non_exhaustive_omitted_patterns` lint.
+ (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
+ /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
+ /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
+ /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
+ (active, object_safe_for_dispatch, "1.40.0", Some(43561), None),
+ /// Allows using `#[optimize(X)]`.
+ (active, optimize_attribute, "1.34.0", Some(54882), None),
+ /// Allows `extern "platform-intrinsic" { ... }`.
+ (active, platform_intrinsics, "1.4.0", Some(27731), None),
+ /// Allows using `#![plugin(myplugin)]`.
+ (active, plugin, "1.0.0", Some(29597), None),
+ /// Allows exhaustive integer pattern matching on `usize` and `isize`.
+ (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
+ /// Allows macro attributes on expressions, statements and non-inline modules.
+ (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
+ /// Allows the use of raw-dylibs (RFC 2627).
+ (incomplete, raw_dylib, "1.40.0", Some(58713), None),
+ /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
+ (active, raw_ref_op, "1.41.0", Some(64490), None),
+ /// Allows using the `#[register_attr]` attribute.
+ (active, register_attr, "1.41.0", Some(66080), None),
+ /// Allows using the `#[register_tool]` attribute.
+ (active, register_tool, "1.41.0", Some(66079), None),
+ /// Allows the `#[repr(i128)]` attribute for enums.
+ (incomplete, repr128, "1.16.0", Some(56071), None),
+ /// Allows `repr(simd)` and importing the various simd intrinsics.
+ (active, repr_simd, "1.4.0", Some(27731), None),
+ /// Allows the use of SIMD types in functions declared in `extern` blocks.
+ (active, simd_ffi, "1.0.0", Some(27731), None),
+ /// Allows specialization of implementations (RFC 1210).
+ (incomplete, specialization, "1.7.0", Some(31844), None),
+ /// Allows `#[link(kind="static-nobundle"...)]`.
+ (active, static_nobundle, "1.16.0", Some(37403), None),
+ /// Allows attributes on expressions and non-item statements.
+ (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
+ /// Allows the use of `#[target_feature]` on safe functions.
+ (active, target_feature_11, "1.45.0", Some(69098), None),
+ /// Allows using `#[thread_local]` on `static` items.
+ (active, thread_local, "1.0.0", Some(29594), None),
+ /// Allows defining `trait X = A + B;` alias items.
+ (active, trait_alias, "1.24.0", Some(41517), None),
+ /// Allows upcasting trait objects via supertraits.
+ /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
+ (incomplete, trait_upcasting, "1.56.0", Some(65991), None),
+ /// Allows #[repr(transparent)] on unions (RFC 2645).
+ (active, transparent_unions, "1.37.0", Some(60405), None),
+ /// Allows inconsistent bounds in where clauses.
+ (active, trivial_bounds, "1.28.0", Some(48214), None),
+ /// Allows using `try {...}` expressions.
+ (active, try_blocks, "1.29.0", Some(31436), None),
+ /// Allows `impl Trait` to be used inside type aliases (RFC 2515).
+ (active, type_alias_impl_trait, "1.38.0", Some(63063), None),
+ /// Allows the use of type ascription in expressions.
+ (active, type_ascription, "1.6.0", Some(23416), None),
+ /// Allows creation of instances of a struct by moving fields that have
+ /// not changed from prior instances of the same struct (RFC #2528)
+ (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None),
+ /// Allows unsized fn parameters.
+ (active, unsized_fn_params, "1.49.0", Some(48055), None),
+ /// Allows unsized rvalues at arguments and parameters.
+ (incomplete, unsized_locals, "1.30.0", Some(48055), None),
+ /// Allows unsized tuple coercion.
+ (active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
/// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields
/// that don't implement `Copy` as long as they don't have any drop glue.
/// This is checked recursively. On encountering type variable where no progress can be made,
@@ -346,346 +534,11 @@
///
/// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0.
(active, untagged_unions, "1.13.0", Some(55149), None),
-
- /// Allows `#[link(..., cfg(..))]`.
- (active, link_cfg, "1.14.0", Some(37406), None),
-
- /// Allows `extern "ptx-*" fn()`.
- (active, abi_ptx, "1.15.0", Some(38788), None),
-
- /// Allows the `#[repr(i128)]` attribute for enums.
- (incomplete, repr128, "1.16.0", Some(56071), None),
-
- /// Allows `#[link(kind="static-nobundle"...)]`.
- (active, static_nobundle, "1.16.0", Some(37403), None),
-
- /// Allows `extern "msp430-interrupt" fn()`.
- (active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
-
- /// Allows declarative macros 2.0 (`macro`).
- (active, decl_macro, "1.17.0", Some(39412), None),
-
- /// Allows `extern "x86-interrupt" fn()`.
- (active, abi_x86_interrupt, "1.17.0", Some(40180), None),
-
- /// Allows a test to fail without failing the whole suite.
- (active, allow_fail, "1.19.0", Some(46488), None),
-
- /// Allows unsized tuple coercion.
- (active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
-
- /// Allows defining generators.
- (active, generators, "1.21.0", Some(43122), None),
-
- /// Allows `#[doc(cfg(...))]`.
- (active, doc_cfg, "1.21.0", Some(43781), None),
-
- /// Allows `#[doc(masked)]`.
- (active, doc_masked, "1.21.0", Some(44027), None),
-
- /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
- (active, crate_visibility_modifier, "1.23.0", Some(53120), None),
-
- /// Allows defining `extern type`s.
- (active, extern_types, "1.23.0", Some(43467), None),
-
- /// Allows trait methods with arbitrary self types.
- (active, arbitrary_self_types, "1.23.0", Some(44874), None),
-
- /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
- (active, in_band_lifetimes, "1.23.0", Some(44524), None),
-
- /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
- (active, generic_associated_types, "1.23.0", Some(44265), None),
-
- /// Allows defining `trait X = A + B;` alias items.
- (active, trait_alias, "1.24.0", Some(41517), None),
-
- /// Allows inferring `'static` outlives requirements (RFC 2093).
- (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
-
- /// Allows dereferencing raw pointers during const eval.
- (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
-
- /// Allows inconsistent bounds in where clauses.
- (active, trivial_bounds, "1.28.0", Some(48214), None),
-
- /// Allows `'a: { break 'a; }`.
- (active, label_break_value, "1.28.0", Some(48594), None),
-
- /// Allows using `#[doc(keyword = "...")]`.
- (active, doc_keyword, "1.28.0", Some(51315), None),
-
- /// Allows using `try {...}` expressions.
- (active, try_blocks, "1.29.0", Some(31436), None),
-
- /// Allows defining an `#[alloc_error_handler]`.
- (active, alloc_error_handler, "1.29.0", Some(51540), None),
-
- /// Allows using the `amdgpu-kernel` ABI.
- (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
-
- /// Allows `#[marker]` on certain traits allowing overlapping implementations.
- (active, marker_trait_attr, "1.30.0", Some(29864), None),
-
- /// Allows macro attributes on expressions, statements and non-inline modules.
- (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
-
- /// Allows unsized rvalues at arguments and parameters.
- (incomplete, unsized_locals, "1.30.0", Some(48055), None),
-
- /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
- (active, custom_test_frameworks, "1.30.0", Some(50297), None),
-
- /// Allows non-builtin attributes in inner attribute position.
- (active, custom_inner_attributes, "1.30.0", Some(54726), None),
-
- /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
- (active, lint_reasons, "1.31.0", Some(54503), None),
-
- /// Allows exhaustive integer pattern matching on `usize` and `isize`.
- (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
-
- /// Allows using `#[ffi_returns_twice]` on foreign functions.
- (active, ffi_returns_twice, "1.34.0", Some(58314), None),
-
- /// Allows using `#[optimize(X)]`.
- (active, optimize_attribute, "1.34.0", Some(54882), None),
-
- /// Allows using C-variadics.
- (active, c_variadic, "1.34.0", Some(44930), None),
-
- /// Allows the user of associated type bounds.
- (active, associated_type_bounds, "1.34.0", Some(52662), None),
-
- /// Allows `if/while p && let q = r && ...` chains.
- (incomplete, let_chains, "1.37.0", Some(53667), None),
-
- /// Allows #[repr(transparent)] on unions (RFC 2645).
- (active, transparent_unions, "1.37.0", Some(60405), None),
-
- /// Allows explicit discriminants on non-unit enum variants.
- (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
-
- /// Allows `async || body` closures.
- (active, async_closure, "1.37.0", Some(62290), None),
-
- /// Allows `impl Trait` to be used inside type aliases (RFC 2515).
- (active, type_alias_impl_trait, "1.38.0", Some(63063), None),
-
- /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
- (active, const_extern_fn, "1.40.0", Some(64926), None),
-
- /// Allows the use of raw-dylibs (RFC 2627).
- (incomplete, raw_dylib, "1.40.0", Some(58713), None),
-
- /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
- /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
- /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
- (active, object_safe_for_dispatch, "1.40.0", Some(43561), None),
-
- /// Allows using the `efiapi` ABI.
- (active, abi_efiapi, "1.40.0", Some(65815), None),
-
- /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
- (active, raw_ref_op, "1.41.0", Some(64490), None),
-
- /// Allows diverging expressions to fall back to `!` rather than `()`.
- (active, never_type_fallback, "1.41.0", Some(65992), None),
-
- /// Allows using the `#[register_attr]` attribute.
- (active, register_attr, "1.41.0", Some(66080), None),
-
- /// Allows using the `#[register_tool]` attribute.
- (active, register_tool, "1.41.0", Some(66079), None),
-
- /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
- (active, cfg_sanitize, "1.41.0", Some(39699), None),
-
- /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
- (active, half_open_range_patterns, "1.41.0", Some(67264), None),
-
- /// Allows using `&mut` in constant functions.
- (active, const_mut_refs, "1.41.0", Some(57349), None),
-
- /// Allows `impl const Trait for T` syntax.
- (active, const_trait_impl, "1.42.0", Some(67792), None),
-
- /// Allows the use of `no_sanitize` attribute.
- (active, no_sanitize, "1.42.0", Some(39699), None),
-
- // Allows limiting the evaluation steps of const expressions
- (active, const_eval_limit, "1.43.0", Some(67217), None),
-
- /// Allow negative trait implementations.
- (active, negative_impls, "1.44.0", Some(68318), None),
-
- /// Allows the use of `#[target_feature]` on safe functions.
- (active, target_feature_11, "1.45.0", Some(69098), None),
-
- /// Allow conditional compilation depending on rust version
- (active, cfg_version, "1.45.0", Some(64796), None),
-
- /// Allows the use of `#[ffi_pure]` on foreign functions.
- (active, ffi_pure, "1.45.0", Some(58329), None),
-
- /// Allows the use of `#[ffi_const]` on foreign functions.
- (active, ffi_const, "1.45.0", Some(58328), None),
-
- /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
- (active, abi_avr_interrupt, "1.45.0", Some(69664), None),
-
- /// Be more precise when looking for live drops in a const context.
- (active, const_precise_live_drops, "1.46.0", Some(73255), None),
-
- /// Allows capturing variables in scope using format_args!
- (active, format_args_capture, "1.46.0", Some(67984), None),
-
- /// Allows `if let` guard in match arms.
- (active, if_let_guard, "1.47.0", Some(51114), None),
-
- /// Allows basic arithmetic on floating point types in a `const fn`.
- (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
-
- /// Allows using and casting function pointers in a `const fn`.
- (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
-
- /// Allows to use the `#[cmse_nonsecure_entry]` attribute.
- (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
-
- /// Allows rustc to inject a default alloc_error_handler
- (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
-
- /// Allows argument and return position `impl Trait` in a `const fn`.
- (active, const_impl_trait, "1.48.0", Some(77463), None),
-
- /// Allows `#[instruction_set(_)]` attribute
- (active, isa_attribute, "1.48.0", Some(74727), None),
-
- /// Allow anonymous constants from an inline `const` block
- (incomplete, inline_const, "1.49.0", Some(76001), None),
-
- /// Allows unsized fn parameters.
- (active, unsized_fn_params, "1.49.0", Some(48055), None),
-
- /// Allows the use of destructuring assignments.
- (active, destructuring_assignment, "1.49.0", Some(71126), None),
-
- /// Enables `#[cfg(panic = "...")]` config key.
- (active, cfg_panic, "1.49.0", Some(77443), None),
-
- /// Allows capturing disjoint fields in a closure/generator (RFC 2229).
- (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None),
-
- /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
- (active, const_generics_defaults, "1.51.0", Some(44580), None),
-
- /// Allows references to types with interior mutability within constants
- (active, const_refs_to_cell, "1.51.0", Some(80384), None),
-
- /// Allows using `pointer` and `reference` in intra-doc links
- (active, intra_doc_pointers, "1.51.0", Some(80896), None),
-
- /// Allows `extern "C-cmse-nonsecure-call" fn()`.
- (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
-
- /// Lessens the requirements for structs to implement `Unsize`.
- (active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
-
- /// Allows associated types in inherent impls.
- (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
-
- // Allows setting the threshold for the `large_assignments` lint.
- (active, large_assignments, "1.52.0", Some(83518), None),
-
- /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
- (active, c_unwind, "1.52.0", Some(74990), None),
-
- /// Allows using `#[repr(align(...))]` on function items
- (active, fn_align, "1.53.0", Some(82232), None),
-
/// Allows `extern "wasm" fn`
(active, wasm_abi, "1.53.0", Some(83788), None),
-
- /// Allows function attribute `#[no_coverage]`, to bypass coverage
- /// instrumentation of that function.
- (active, no_coverage, "1.53.0", Some(84605), None),
-
- /// Allows trait bounds in `const fn`.
- (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
-
- /// Allows `async {}` expressions in const contexts.
- (active, const_async_blocks, "1.53.0", Some(85368), None),
-
- /// Allows using imported `main` function
- (active, imported_main, "1.53.0", Some(28937), None),
-
- /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
- (active, native_link_modifiers, "1.53.0", Some(81490), None),
-
- /// Allows specifying the bundle link modifier
- (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
-
- /// Allows specifying the verbatim link modifier
- (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
-
- /// Allows specifying the whole-archive link modifier
- (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None),
-
- /// Allows specifying the as-needed link modifier
- (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
-
- /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
- (active, more_qualified_paths, "1.54.0", Some(86935), None),
-
- /// Allows `cfg(target_abi = "...")`.
- (active, cfg_target_abi, "1.55.0", Some(80970), None),
-
- /// Infer generic args for both consts and types.
- (active, generic_arg_infer, "1.55.0", Some(85077), None),
-
- /// Allows `#[derive(Default)]` and `#[default]` on enums.
- (active, derive_default_enum, "1.56.0", Some(86985), None),
-
- /// Allows `for _ in _` loops in const contexts.
- (active, const_for, "1.56.0", Some(87575), None),
-
- /// Allows the `?` operator in const contexts.
- (active, const_try, "1.56.0", Some(74935), None),
-
- /// Allows upcasting trait objects via supertraits.
- /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
- (incomplete, trait_upcasting, "1.56.0", Some(65991), None),
-
- /// Allows explicit generic arguments specification with `impl Trait` present.
- (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None),
-
- /// Allows using doc(primitive) without a future-incompat warning
- (active, doc_primitive, "1.56.0", Some(88070), None),
-
- /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
- (incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
-
- /// Allows additional const parameter types, such as `&'static str` or user defined types
- (incomplete, adt_const_params, "1.56.0", Some(44580), None),
-
- /// Allows `let...else` statements.
- (active, let_else, "1.56.0", Some(87335), None),
-
- /// Allows the `#[must_not_suspend]` attribute.
- (active, must_not_suspend, "1.57.0", Some(83310), None),
-
- /// Allows `#[track_caller]` on closures and generators.
- (active, closure_track_caller, "1.57.0", Some(87417), None),
-
- /// Allows `#[doc(cfg_hide(...))]`.
- (active, doc_cfg_hide, "1.57.0", Some(43781), None),
-
- /// Allows using the `non_exhaustive_omitted_patterns` lint.
- (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
-
- /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
- (active, doc_auto_cfg, "1.57.0", Some(43781), None),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 85b0db4..f25b2d8 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1,5 +1,6 @@
//! Built-in attributes and `cfg` flag gating.
+use AttributeDuplicates::*;
use AttributeGate::*;
use AttributeType::*;
@@ -88,11 +89,66 @@
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
#[derive(Clone, Copy, Default)]
pub struct AttributeTemplate {
+ /// If `true`, the attribute is allowed to be a bare word like `#[test]`.
pub word: bool,
+ /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
pub list: Option<&'static str>,
+ /// If `Some`, the attribute is allowed to be a name/value pair where the
+ /// value is a string, like `#[must_use = "reason"]`.
pub name_value_str: Option<&'static str>,
}
+/// How to handle multiple duplicate attributes on the same item.
+#[derive(Clone, Copy, Default)]
+pub enum AttributeDuplicates {
+ /// Duplicates of this attribute are allowed.
+ ///
+ /// This should only be used with attributes where duplicates have semantic
+ /// meaning, or some kind of "additive" behavior. For example, `#[warn(..)]`
+ /// can be specified multiple times, and it combines all the entries. Or use
+ /// this if there is validation done elsewhere.
+ #[default]
+ DuplicatesOk,
+ /// Duplicates after the first attribute will be an unused_attribute warning.
+ ///
+ /// This is usually used for "word" attributes, where they are used as a
+ /// boolean marker, like `#[used]`. It is not necessarily wrong that there
+ /// are duplicates, but the others should probably be removed.
+ WarnFollowing,
+ /// Same as `WarnFollowing`, but only issues warnings for word-style attributes.
+ ///
+ /// This is only for special cases, for example multiple `#[macro_use]` can
+ /// be warned, but multiple `#[macro_use(...)]` should not because the list
+ /// form has different meaning from the word form.
+ WarnFollowingWordOnly,
+ /// Duplicates after the first attribute will be an error.
+ ///
+ /// This should be used where duplicates would be ignored, but carry extra
+ /// meaning that could cause confusion. For example, `#[stable(since="1.0")]
+ /// #[stable(since="2.0")]`, which version should be used for `stable`?
+ ErrorFollowing,
+ /// Duplicates preceding the last instance of the attribute will be an error.
+ ///
+ /// This is the same as `ErrorFollowing`, except the last attribute is the
+ /// one that is "used". This is typically used in cases like codegen
+ /// attributes which usually only honor the last attribute.
+ ErrorPreceding,
+ /// Duplicates after the first attribute will be an unused_attribute warning
+ /// with a note that this will be an error in the future.
+ ///
+ /// This should be used for attributes that should be `ErrorFollowing`, but
+ /// because older versions of rustc silently accepted (and ignored) the
+ /// attributes, this is used to transition.
+ FutureWarnFollowing,
+ /// Duplicates preceding the last instance of the attribute will be a
+ /// warning, with a note that this will be an error in the future.
+ ///
+ /// This is the same as `FutureWarnFollowing`, except the last attribute is
+ /// the one that is "used". Ideally these can eventually migrate to
+ /// `ErrorPreceding`.
+ FutureWarnPreceding,
+}
+
/// A convenience macro for constructing attribute templates.
/// E.g., `template!(Word, List: "description")` means that the attribute
/// supports forms `#[attr]` and `#[attr(description)]`.
@@ -114,26 +170,45 @@
}
macro_rules! ungated {
- ($attr:ident, $typ:expr, $tpl:expr $(,)?) => {
- (sym::$attr, $typ, $tpl, Ungated)
+ ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(,)?) => {
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ gate: Ungated,
+ duplicates: $duplicates,
+ }
};
}
macro_rules! gated {
- ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => {
- (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)))
+ ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $gate:ident, $msg:expr $(,)?) => {
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ duplicates: $duplicates,
+ gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+ }
};
- ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
- (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)))
+ ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => {
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ duplicates: $duplicates,
+ gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+ }
};
}
macro_rules! rustc_attr {
- (TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => {
+ (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(,)?) => {
rustc_attr!(
$attr,
$typ,
$tpl,
+ $duplicate,
concat!(
"the `#[",
stringify!($attr),
@@ -142,13 +217,14 @@
),
)
};
- ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
- (
- sym::$attr,
- $typ,
- $tpl,
- Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
- )
+ ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => {
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ duplicates: $duplicates,
+ gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
+ }
};
}
@@ -161,7 +237,13 @@
const IMPL_DETAIL: &str = "internal implementation detail";
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
-pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
+pub struct BuiltinAttribute {
+ pub name: Symbol,
+ pub type_: AttributeType,
+ pub template: AttributeTemplate,
+ pub duplicates: AttributeDuplicates,
+ pub gate: AttributeGate,
+}
/// Attributes that have a special meaning to rustc or rustdoc.
#[rustfmt::skip]
@@ -171,42 +253,48 @@
// ==========================================================================
// Conditional compilation:
- ungated!(cfg, Normal, template!(List: "predicate")),
- ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")),
+ ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk),
+ ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk),
// Testing:
- ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")),
+ ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing),
ungated!(
should_panic, Normal,
- template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
+ template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), FutureWarnFollowing,
),
// FIXME(Centril): This can be used on stable but shouldn't.
- ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name")),
+ ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing),
// Macros:
- ungated!(automatically_derived, Normal, template!(Word)),
- // FIXME(#14407)
- ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
- ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`.
- ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")),
- ungated!(proc_macro, Normal, template!(Word)),
+ ungated!(automatically_derived, Normal, template!(Word), WarnFollowing),
+ ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly),
+ ungated!(macro_escape, Normal, template!(Word), WarnFollowing), // Deprecated synonym for `macro_use`.
+ ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros"), WarnFollowing),
+ ungated!(proc_macro, Normal, template!(Word), ErrorFollowing),
ungated!(
proc_macro_derive, Normal,
- template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"),
+ template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
),
- ungated!(proc_macro_attribute, Normal, template!(Word)),
+ ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing),
// Lints:
- ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
- ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
- ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
- ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
- ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
- gated!(
- must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend,
- experimental!(must_not_suspend)
+ ungated!(
+ warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
),
- // FIXME(#14407)
+ ungated!(
+ allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ ),
+ ungated!(
+ forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ ),
+ ungated!(
+ deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ ),
+ ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
+ gated!(
+ must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
+ must_not_suspend, experimental!(must_not_suspend)
+ ),
ungated!(
deprecated, Normal,
template!(
@@ -214,85 +302,96 @@
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
NameValueStr: "reason"
),
+ // This has special duplicate handling in E0550 to handle duplicates with rustc_deprecated
+ DuplicatesOk
),
// Crate properties:
- ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")),
- ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")),
- ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")),
+ ungated!(crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing),
+ ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), FutureWarnFollowing),
+ // crate_id is deprecated
+ ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing),
// ABI, linking, symbols, and FFI
ungated!(
link, Normal,
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
+ DuplicatesOk,
),
- ungated!(link_name, Normal, template!(NameValueStr: "name")),
- ungated!(no_link, Normal, template!(Word)),
- ungated!(repr, Normal, template!(List: "C")),
- ungated!(export_name, Normal, template!(NameValueStr: "name")),
- ungated!(link_section, Normal, template!(NameValueStr: "name")),
- ungated!(no_mangle, Normal, template!(Word)),
- ungated!(used, Normal, template!(Word)),
+ ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
+ ungated!(no_link, Normal, template!(Word), WarnFollowing),
+ ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
+ 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),
// Limits:
- ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")),
- ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")),
+ ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
+ ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
gated!(
- const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit,
- experimental!(const_eval_limit)
+ const_eval_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
+ const_eval_limit, experimental!(const_eval_limit)
),
gated!(
- move_size_limit, CrateLevel, template!(NameValueStr: "N"), large_assignments,
- experimental!(move_size_limit)
+ move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
+ large_assignments, experimental!(move_size_limit)
),
// Entry point:
- ungated!(main, Normal, template!(Word)),
- ungated!(start, Normal, template!(Word)),
- ungated!(no_start, CrateLevel, template!(Word)),
- ungated!(no_main, CrateLevel, template!(Word)),
+ ungated!(main, Normal, template!(Word), WarnFollowing),
+ ungated!(start, Normal, template!(Word), WarnFollowing),
+ ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
+ ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
// Modules, prelude, and resolution:
- ungated!(path, Normal, template!(NameValueStr: "file")),
- ungated!(no_std, CrateLevel, template!(Word)),
- ungated!(no_implicit_prelude, Normal, template!(Word)),
- ungated!(non_exhaustive, Normal, template!(Word)),
+ ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing),
+ ungated!(no_std, CrateLevel, template!(Word), WarnFollowing),
+ ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing),
+ ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing),
// Runtime
- ungated!(windows_subsystem, Normal, template!(NameValueStr: "windows|console")),
- ungated!(panic_handler, Normal, template!(Word)), // RFC 2070
+ ungated!(
+ windows_subsystem, Normal,
+ template!(NameValueStr: "windows|console"), FutureWarnFollowing
+ ),
+ ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
// Code generation:
- ungated!(inline, Normal, template!(Word, List: "always|never")),
- ungated!(cold, Normal, template!(Word)),
- ungated!(no_builtins, Normal, template!(Word)),
- ungated!(target_feature, Normal, template!(List: r#"enable = "name""#)),
- ungated!(track_caller, Normal, template!(Word)),
+ ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
+ ungated!(cold, Normal, template!(Word), WarnFollowing),
+ ungated!(no_builtins, Normal, template!(Word), WarnFollowing),
+ ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
+ ungated!(track_caller, Normal, template!(Word), WarnFollowing),
gated!(
no_sanitize, Normal,
- template!(List: "address, memory, thread"),
+ template!(List: "address, memory, thread"), DuplicatesOk,
experimental!(no_sanitize)
),
- gated!(no_coverage, Normal, template!(Word), experimental!(no_coverage)),
+ gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)),
- // FIXME: #14408 assume docs are used since rustdoc looks at them.
- ungated!(doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string")),
+ ungated!(
+ doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
+ ),
// ==========================================================================
// Unstable attributes:
// ==========================================================================
// Linking:
- gated!(naked, Normal, template!(Word), naked_functions, experimental!(naked)),
+ gated!(naked, Normal, template!(Word), WarnFollowing, naked_functions, experimental!(naked)),
gated!(
- link_ordinal, Normal, template!(List: "ordinal"), raw_dylib,
+ link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib,
experimental!(link_ordinal)
),
// Plugins:
- (
- sym::plugin, CrateLevel, template!(List: "name"),
- Gated(
+ BuiltinAttribute {
+ name: sym::plugin,
+ type_: CrateLevel,
+ template: template!(List: "name"),
+ duplicates: DuplicatesOk,
+ gate: Gated(
Stability::Deprecated(
"https://github.com/rust-lang/rust/pull/64675",
Some("may be removed in a future compiler version"),
@@ -300,46 +399,56 @@
sym::plugin,
"compiler plugins are deprecated",
cfg_fn!(plugin)
- )
- ),
+ ),
+ },
// Testing:
- gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)),
+ gated!(allow_fail, Normal, template!(Word), WarnFollowing, experimental!(allow_fail)),
gated!(
- test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks,
+ test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks,
"custom test frameworks are an unstable feature",
),
// RFC #1268
- gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
gated!(
- thread_local, Normal, template!(Word),
+ marker, Normal, template!(Word), WarnFollowing, marker_trait_attr, experimental!(marker)
+ ),
+ gated!(
+ thread_local, Normal, template!(Word), WarnFollowing,
"`#[thread_local]` is an experimental feature, and does not currently handle destructors",
),
- gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)),
+ gated!(no_core, CrateLevel, template!(Word), WarnFollowing, experimental!(no_core)),
// RFC 2412
gated!(
- optimize, Normal, template!(List: "size|speed"), optimize_attribute,
+ optimize, Normal, template!(List: "size|speed"), ErrorPreceding, optimize_attribute,
experimental!(optimize),
),
// RFC 2867
- gated!(instruction_set, Normal, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
-
- gated!(ffi_returns_twice, Normal, template!(Word), experimental!(ffi_returns_twice)),
- gated!(ffi_pure, Normal, template!(Word), experimental!(ffi_pure)),
- gated!(ffi_const, Normal, template!(Word), experimental!(ffi_const)),
gated!(
- register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
+ instruction_set, Normal, template!(List: "set"), ErrorPreceding,
+ isa_attribute, experimental!(instruction_set)
+ ),
+
+ gated!(
+ ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice)
+ ),
+ gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)),
+ gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)),
+ gated!(
+ register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), DuplicatesOk,
experimental!(register_attr),
),
gated!(
- register_tool, CrateLevel, template!(List: "tool1, tool2, ..."),
+ register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk,
experimental!(register_tool),
),
- gated!(cmse_nonsecure_entry, Normal, template!(Word), experimental!(cmse_nonsecure_entry)),
+ gated!(
+ cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing,
+ experimental!(cmse_nonsecure_entry)
+ ),
// RFC 2632
gated!(
- default_method_body_is_const, Normal, template!(Word), const_trait_impl,
+ default_method_body_is_const, Normal, template!(Word), WarnFollowing, const_trait_impl,
"`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
as `const`, which may be removed or renamed in the future."
),
@@ -348,34 +457,33 @@
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
- ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")),
- // FIXME(#14407) -- only looked at on-demand so we can't
- // guarantee they'll have already been checked.
+ ungated!(feature, CrateLevel, template!(List: "name1, name1, ..."), DuplicatesOk),
+ // DuplicatesOk since it has its own validation
ungated!(
rustc_deprecated, Normal,
- template!(List: r#"since = "version", reason = "...""#)
+ template!(List: r#"since = "version", reason = "...""#), DuplicatesOk // See E0550
),
- // FIXME(#14407)
- ungated!(stable, Normal, template!(List: r#"feature = "name", since = "version""#)),
- // FIXME(#14407)
+ // DuplicatesOk since it has its own validation
+ ungated!(
+ stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk
+ ),
ungated!(
unstable, Normal,
- template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+ template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
),
- // FIXME(#14407)
- ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#)),
- // FIXME(#14407)
- ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#)),
+ ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
+ ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
gated!(
- allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
+ allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"allow_internal_unstable side-steps feature gating and stability checks",
),
gated!(
- rustc_allow_const_fn_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
+ rustc_allow_const_fn_unstable, Normal,
+ template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
),
gated!(
- allow_internal_unsafe, Normal, template!(Word),
+ allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
"allow_internal_unsafe side-steps the unsafe_code lint",
),
@@ -383,9 +491,9 @@
// Internal attributes: Type system related:
// ==========================================================================
- gated!(fundamental, Normal, template!(Word), experimental!(fundamental)),
+ gated!(fundamental, Normal, template!(Word), WarnFollowing, experimental!(fundamental)),
gated!(
- may_dangle, Normal, template!(Word), dropck_eyepatch,
+ may_dangle, Normal, template!(Word), WarnFollowing, dropck_eyepatch,
"`may_dangle` has unstable semantics and may be removed in the future",
),
@@ -393,26 +501,32 @@
// Internal attributes: Runtime related:
// ==========================================================================
- rustc_attr!(rustc_allocator, Normal, template!(Word), IMPL_DETAIL),
- rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), IMPL_DETAIL),
- gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)),
+ rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
gated!(
- default_lib_allocator, Normal, template!(Word), allocator_internals,
+ alloc_error_handler, Normal, template!(Word), WarnFollowing,
+ experimental!(alloc_error_handler)
+ ),
+ gated!(
+ default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
experimental!(default_lib_allocator),
),
gated!(
- needs_allocator, Normal, template!(Word), allocator_internals,
+ needs_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
experimental!(needs_allocator),
),
- gated!(panic_runtime, Normal, template!(Word), experimental!(panic_runtime)),
- gated!(needs_panic_runtime, Normal, template!(Word), experimental!(needs_panic_runtime)),
+ gated!(panic_runtime, Normal, template!(Word), WarnFollowing, experimental!(panic_runtime)),
gated!(
- compiler_builtins, Normal, template!(Word),
+ needs_panic_runtime, Normal, template!(Word), WarnFollowing,
+ experimental!(needs_panic_runtime)
+ ),
+ gated!(
+ compiler_builtins, Normal, template!(Word), WarnFollowing,
"the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
which contains compiler-rt intrinsics and will never be stable",
),
gated!(
- profiler_runtime, Normal, template!(Word),
+ profiler_runtime, Normal, template!(Word), WarnFollowing,
"the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
which contains the profiler runtime and will never be stable",
),
@@ -422,10 +536,12 @@
// ==========================================================================
gated!(
- linkage, Normal, template!(NameValueStr: "external|internal|..."),
+ linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding,
"the `linkage` attribute is experimental and not portable across platforms",
),
- rustc_attr!(rustc_std_internal_symbol, Normal, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(
+ rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+ ),
// ==========================================================================
// Internal attributes, Macro related:
@@ -433,13 +549,13 @@
rustc_attr!(
rustc_builtin_macro, Normal,
- template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
+ template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
IMPL_DETAIL,
),
- rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
rustc_attr!(
rustc_macro_transparency, Normal,
- template!(NameValueStr: "transparent|semitransparent|opaque"),
+ template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing,
"used internally for testing macro hygiene",
),
@@ -453,39 +569,49 @@
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
NameValueStr: "message"
),
+ ErrorFollowing,
INTERNAL_UNSTABLE
),
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
- rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(
+ rustc_conversion_suggestion, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+ ),
// Prevents field reads in the marked trait or method to be considered
// during dead code analysis.
- rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(
+ rustc_trivial_field_reads, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+ ),
// ==========================================================================
// Internal attributes, Const related:
// ==========================================================================
- rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL),
- rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE),
+ rustc_attr!(rustc_promotable, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(
+ rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
+ INTERNAL_UNSTABLE
+ ),
// Do not const-check this function's body. It will always get replaced during CTFE.
- rustc_attr!(rustc_do_not_const_check, Normal, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(
+ rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+ ),
// ==========================================================================
// Internal attributes, Layout related:
// ==========================================================================
rustc_attr!(
- rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"),
+ rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in libcore and will never be stable",
),
rustc_attr!(
- rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"),
+ rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in libcore and will never be stable",
),
rustc_attr!(
- rustc_nonnull_optimization_guaranteed, Normal, template!(Word),
+ rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
niche optimizations in libcore and will never be stable",
),
@@ -494,57 +620,60 @@
// Internal attributes, Misc:
// ==========================================================================
gated!(
- lang, Normal, template!(NameValueStr: "name"), lang_items,
+ lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
"language items are subject to change",
),
- (
- sym::rustc_diagnostic_item,
- Normal,
- template!(NameValueStr: "name"),
- Gated(
+ BuiltinAttribute {
+ name: sym::rustc_diagnostic_item,
+ type_: Normal,
+ template: template!(NameValueStr: "name"),
+ duplicates: ErrorFollowing,
+ gate: Gated(
Stability::Unstable,
sym::rustc_attrs,
"diagnostic items compiler internal support for linting",
cfg_fn!(rustc_attrs),
),
- ),
+ },
gated!(
// Used in resolve:
- prelude_import, Normal, template!(Word),
+ prelude_import, Normal, template!(Word), WarnFollowing,
"`#[prelude_import]` is for use by rustc only",
),
gated!(
- rustc_paren_sugar, Normal, template!(Word), unboxed_closures,
+ rustc_paren_sugar, Normal, template!(Word), WarnFollowing, unboxed_closures,
"unboxed_closures are still evolving",
),
rustc_attr!(
- rustc_inherit_overflow_checks, Normal, template!(Word),
+ rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing,
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several libcore functions that are inlined \
across crates and will never be stable",
),
- rustc_attr!(rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"),
- "the `#[rustc_reservation_impl]` attribute is internally used \
- for reserving for `for<T> From<!> for T` impl"
+ rustc_attr!(
+ rustc_reservation_impl, Normal,
+ template!(NameValueStr: "reservation message"), ErrorFollowing,
+ "the `#[rustc_reservation_impl]` attribute is internally used \
+ for reserving for `for<T> From<!> for T` impl"
),
rustc_attr!(
- rustc_test_marker, Normal, template!(Word),
+ rustc_test_marker, Normal, template!(Word), WarnFollowing,
"the `#[rustc_test_marker]` attribute is used internally to track tests",
),
rustc_attr!(
- rustc_unsafe_specialization_marker, Normal, template!(Word),
+ rustc_unsafe_specialization_marker, Normal, template!(Word), WarnFollowing,
"the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
),
rustc_attr!(
- rustc_specialization_trait, Normal, template!(Word),
+ rustc_specialization_trait, Normal, template!(Word), WarnFollowing,
"the `#[rustc_specialization_trait]` attribute is used to check specializations"
),
rustc_attr!(
- rustc_main, Normal, template!(Word),
+ rustc_main, Normal, template!(Word), WarnFollowing,
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
),
rustc_attr!(
- rustc_skip_array_during_method_dispatch, Normal, template!(Word),
+ rustc_skip_array_during_method_dispatch, Normal, template!(Word), WarnFollowing,
"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."
),
@@ -553,54 +682,59 @@
// Internal attributes, Testing:
// ==========================================================================
- rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
- rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
+ rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
rustc_attr!(
TEST, rustc_error, Normal,
- template!(Word, List: "delay_span_bug_from_inside_query")
+ template!(Word, List: "delay_span_bug_from_inside_query"), WarnFollowingWordOnly
),
- rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode")),
- rustc_attr!(TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode")),
+ rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(
+ TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk
+ ),
+ rustc_attr!(
+ TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk
+ ),
rustc_attr!(
TEST, rustc_clean, Normal,
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
+ DuplicatesOk,
),
rustc_attr!(
TEST, rustc_partition_reused, Normal,
- template!(List: r#"cfg = "...", module = "...""#),
+ template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk,
),
rustc_attr!(
TEST, rustc_partition_codegened, Normal,
- template!(List: r#"cfg = "...", module = "...""#),
+ template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk,
),
rustc_attr!(
TEST, rustc_expected_cgu_reuse, Normal,
- template!(List: r#"cfg = "...", module = "...", kind = "...""#),
+ template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
),
- rustc_attr!(TEST, rustc_synthetic, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_def_path, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ...")),
- rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word)),
- rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
+ rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
+ rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk),
gated!(
- omit_gdb_pretty_printer_section, Normal, template!(Word),
+ omit_gdb_pretty_printer_section, Normal, template!(Word), WarnFollowing,
"the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
),
];
pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
- BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
+ BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
}
pub fn is_builtin_attr_name(name: Symbol) -> bool {
@@ -611,8 +745,8 @@
SyncLazy::new(|| {
let mut map = FxHashMap::default();
for attr in BUILTIN_ATTRIBUTES.iter() {
- if map.insert(attr.0, attr).is_some() {
- panic!("duplicate builtin attribute `{}`", attr.0);
+ if map.insert(attr.name, attr).is_some() {
+ panic!("duplicate builtin attribute `{}`", attr.name);
}
}
map
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index b25aab2..bfc537c 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -11,6 +11,7 @@
//! even if it is stabilized or removed, *do not remove it*. Instead, move the
//! symbol to the `accepted` or `removed` modules respectively.
+#![feature(derive_default_enum)]
#![feature(once_cell)]
mod accepted;
@@ -146,6 +147,7 @@
pub use accepted::ACCEPTED_FEATURES;
pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES};
+pub use builtin_attrs::AttributeDuplicates;
pub use builtin_attrs::{
deprecated_attributes, find_gated_cfg, is_builtin_attr_name, AttributeGate, AttributeTemplate,
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 7b9b682..b9f3b5a 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -45,132 +45,136 @@
// feature-group-start: removed features
// -------------------------------------------------------------------------
- (removed, import_shadowing, "1.0.0", None, None, None),
- (removed, managed_boxes, "1.0.0", None, None, None),
- /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
- (removed, negate_unsigned, "1.0.0", Some(29645), None, None),
- (removed, reflect, "1.0.0", Some(27749), None, None),
- /// A way to temporarily opt out of opt in copy. This will *never* be accepted.
- (removed, opt_out_copy, "1.0.0", None, None, None),
- (removed, quad_precision_float, "1.0.0", None, None, None),
- (removed, struct_inherit, "1.0.0", None, None, None),
- (removed, test_removed_feature, "1.0.0", None, None, None),
- (removed, visible_private_types, "1.0.0", None, None, None),
- (removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
- /// Allows using items which are missing stability attributes
- (removed, unmarked_api, "1.0.0", None, None, None),
- (removed, allocator, "1.0.0", None, None, None),
- (removed, simd, "1.0.0", Some(27731), None,
- Some("removed in favor of `#[repr(simd)]`")),
(removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
Some("merged into `#![feature(slice_patterns)]`")),
- (removed, macro_reexport, "1.0.0", Some(29638), None,
- Some("subsumed by `pub use`")),
- /// Allows using custom attributes (RFC 572).
- (removed, custom_attribute, "1.0.0", Some(29642), None,
- Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
- /// Allows features specific to OIBIT (now called auto traits).
- /// Renamed to `auto_traits`.
- (removed, optin_builtin_traits, "1.0.0", Some(13231), None,
- Some("renamed to `auto_traits`")),
- (removed, pushpop_unsafe, "1.2.0", None, None, None),
- (removed, needs_allocator, "1.4.0", Some(27389), None,
- Some("subsumed by `#![feature(allocator_internals)]`")),
- /// Allows identifying crates that contain sanitizer runtimes.
- (removed, sanitizer_runtime, "1.17.0", None, None, None),
- /// Allows `#[doc(spotlight)]`.
- /// The attribute was renamed to `#[doc(notable_trait)]`
- /// and the feature to `doc_notable_trait`.
- (removed, doc_spotlight, "1.22.0", Some(45040), None,
- Some("renamed to `doc_notable_trait`")),
- (removed, proc_macro_mod, "1.27.0", Some(54727), None,
- Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
- (removed, proc_macro_expr, "1.27.0", Some(54727), None,
- Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
- (removed, proc_macro_non_items, "1.27.0", Some(54727), None,
- Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
- (removed, proc_macro_gen, "1.27.0", Some(54727), None,
- Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
- (removed, panic_implementation, "1.28.0", Some(44489), None,
- Some("subsumed by `#[panic_handler]`")),
- /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
- (removed, custom_derive, "1.32.0", Some(29644), None,
- Some("subsumed by `#[proc_macro_derive]`")),
- /// Paths of the form: `extern::foo::bar`
- (removed, extern_in_paths, "1.33.0", Some(55600), None,
- Some("subsumed by `::foo::bar` paths")),
- (removed, quote, "1.33.0", Some(29601), None, None),
+ (removed, allocator, "1.0.0", None, None, None),
+ (removed, await_macro, "1.38.0", Some(50547), None,
+ Some("subsumed by `.await` syntax")),
+ /// Allows comparing raw pointers during const eval.
+ (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
+ Some("cannot be allowed in const eval in any meaningful way")),
+ /// Allows non-trivial generic constants which have to be manually propagated upwards.
+ (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
+ /// Allows the definition of `const` functions with some advanced features.
+ (removed, const_fn, "1.54.0", Some(57563), None,
+ Some("split into finer-grained feature gates")),
/// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
(removed, const_generics, "1.34.0", Some(44580), None,
Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")),
/// Allows `[x; N]` where `x` is a constant (RFC 2203).
(removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), None,
Some("removed due to causing promotable bugs")),
+ /// Allows casting raw pointers to `usize` during const eval.
+ (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None,
+ Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),
+ /// Allows `T: ?const Trait` syntax in bounds.
+ (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
+ Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
+ /// Allows using custom attributes (RFC 572).
+ (removed, custom_attribute, "1.0.0", Some(29642), None,
+ Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
+ /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
+ (removed, custom_derive, "1.32.0", Some(29644), None,
+ Some("subsumed by `#[proc_macro_derive]`")),
+ /// Allows using `#[doc(keyword = "...")]`.
+ (removed, doc_keyword, "1.28.0", Some(51315), None,
+ Some("merged into `#![feature(rustdoc_internals)]`")),
+ /// Allows using `doc(primitive)` without a future-incompat warning.
+ (removed, doc_primitive, "1.56.0", Some(88070), None,
+ Some("merged into `#![feature(rustdoc_internals)]`")),
+ /// Allows `#[doc(spotlight)]`.
+ /// The attribute was renamed to `#[doc(notable_trait)]`
+ /// and the feature to `doc_notable_trait`.
+ (removed, doc_spotlight, "1.22.0", Some(45040), None,
+ Some("renamed to `doc_notable_trait`")),
/// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
(removed, dropck_parametricity, "1.38.0", Some(28498), None, None),
- (removed, await_macro, "1.38.0", Some(50547), None,
- Some("subsumed by `.await` syntax")),
/// Allows defining `existential type`s.
(removed, existential_type, "1.38.0", Some(63063), None,
Some("removed in favor of `#![feature(type_alias_impl_trait)]`")),
+ /// Paths of the form: `extern::foo::bar`
+ (removed, extern_in_paths, "1.33.0", Some(55600), None,
+ Some("subsumed by `::foo::bar` paths")),
+ /// Allows `#[doc(include = "some-file")]`.
+ (removed, external_doc, "1.54.0", Some(44732), None,
+ Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+ /// Allows `impl Trait` in bindings (`let`, `const`, `static`).
+ (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None,
+ Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),
+ (removed, import_shadowing, "1.0.0", None, None, None),
+ /// Lazily evaluate constants. This allows constants to depend on type parameters.
+ (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
+ /// Allows using the `#[link_args]` attribute.
+ (removed, link_args, "1.53.0", Some(29596), None,
+ Some("removed in favor of using `-C link-arg=ARG` on command line, \
+ which is available from cargo build scripts with `cargo:rustc-link-arg` now")),
+ (removed, macro_reexport, "1.0.0", Some(29638), None,
+ Some("subsumed by `pub use`")),
+ /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls.
+ (removed, main, "1.53.0", Some(29634), None, None),
+ (removed, managed_boxes, "1.0.0", None, None, None),
+ /// Allows the use of type alias impl trait in function return positions
+ (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None,
+ Some("removed in favor of full type_alias_impl_trait")),
+ (removed, needs_allocator, "1.4.0", Some(27389), None,
+ Some("subsumed by `#![feature(allocator_internals)]`")),
+ /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
+ (removed, negate_unsigned, "1.0.0", Some(29645), None, None),
+ /// Allows `#[no_debug]`.
+ (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+ /// Allows using `#[on_unimplemented(..)]` on traits.
+ /// (Moved to `rustc_attrs`.)
+ (removed, on_unimplemented, "1.40.0", None, None, None),
+ /// A way to temporarily opt out of opt in copy. This will *never* be accepted.
+ (removed, opt_out_copy, "1.0.0", None, None, None),
+ /// Allows features specific to OIBIT (now called auto traits).
+ /// Renamed to `auto_traits`.
+ (removed, optin_builtin_traits, "1.0.0", Some(13231), None,
+ Some("renamed to `auto_traits`")),
+ /// Allows overlapping impls of marker traits.
+ (removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
+ Some("removed in favor of `#![feature(marker_trait_attr)]`")),
+ (removed, panic_implementation, "1.28.0", Some(44489), None,
+ Some("subsumed by `#[panic_handler]`")),
+ /// Allows using `#[plugin_registrar]` on functions.
+ (removed, plugin_registrar, "1.54.0", Some(29597), None,
+ Some("a __rustc_plugin_registrar symbol must now be defined instead")),
+ (removed, proc_macro_expr, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, proc_macro_gen, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, proc_macro_mod, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, proc_macro_non_items, "1.27.0", Some(54727), None,
+ Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, pub_macro_rules, "1.53.0", Some(78855), None,
+ Some("removed due to being incomplete, in particular it does not work across crates")),
+ (removed, pushpop_unsafe, "1.2.0", None, None, None),
+ (removed, quad_precision_float, "1.0.0", None, None, None),
+ (removed, quote, "1.33.0", Some(29601), None, None),
+ (removed, reflect, "1.0.0", Some(27749), None, None),
/// Allows using the macros:
/// + `__diagnostic_used`
/// + `__register_diagnostic`
/// +`__build_diagnostic_array`
(removed, rustc_diagnostic_macros, "1.38.0", None, None, None),
- /// Allows using `#[on_unimplemented(..)]` on traits.
- /// (Moved to `rustc_attrs`.)
- (removed, on_unimplemented, "1.40.0", None, None, None),
- /// Allows overlapping impls of marker traits.
- (removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
- Some("removed in favor of `#![feature(marker_trait_attr)]`")),
- /// Allows `T: ?const Trait` syntax in bounds.
- (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
- Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
- /// Allows `#[no_debug]`.
- (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
- /// Lazily evaluate constants. This allows constants to depend on type parameters.
- (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
- /// Allows comparing raw pointers during const eval.
- (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
- Some("cannot be allowed in const eval in any meaningful way")),
- /// Allows non-trivial generic constants which have to be manually propagated upwards.
- (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
- /// Allows using the `#[link_args]` attribute.
- (removed, link_args, "1.53.0", Some(29596), None,
- Some("removed in favor of using `-C link-arg=ARG` on command line, \
- which is available from cargo build scripts with `cargo:rustc-link-arg` now")),
- /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls.
- (removed, main, "1.53.0", Some(29634), None, None),
- (removed, pub_macro_rules, "1.53.0", Some(78855), None,
- Some("removed due to being incomplete, in particular it does not work across crates")),
- /// Allows the definition of `const` functions with some advanced features.
- (removed, const_fn, "1.54.0", Some(57563), None,
- Some("split into finer-grained feature gates")),
- /// Allows using `#[plugin_registrar]` on functions.
- (removed, plugin_registrar, "1.54.0", Some(29597), None,
- Some("a __rustc_plugin_registrar symbol must now be defined instead")),
-
- /// Allows `#[doc(include = "some-file")]`.
- (removed, external_doc, "1.54.0", Some(44732), None,
- Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
-
- /// Allows casting raw pointers to `usize` during const eval.
- (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None,
- Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),
-
- /// Allows `impl Trait` in bindings (`let`, `const`, `static`).
- (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None,
- Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),
-
- /// Allows the use of type alias impl trait in function return positions
- (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None,
- Some("removed in favor of full type_alias_impl_trait")),
-
+ /// Allows identifying crates that contain sanitizer runtimes.
+ (removed, sanitizer_runtime, "1.17.0", None, None, None),
+ (removed, simd, "1.0.0", Some(27731), None,
+ Some("removed in favor of `#[repr(simd)]`")),
+ (removed, struct_inherit, "1.0.0", None, None, None),
+ (removed, test_removed_feature, "1.0.0", None, None, None),
+ /// Allows using items which are missing stability attributes
+ (removed, unmarked_api, "1.0.0", None, None, None),
+ (removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
/// Allows `#[unwind(..)]`.
///
/// Permits specifying whether a function should permit unwinding or abort on unwind.
(removed, unwind_attributes, "1.56.0", Some(58760), None, Some("use the C-unwind ABI instead")),
+ (removed, visible_private_types, "1.0.0", None, None, None),
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
+ // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
+ // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
// -------------------------------------------------------------------------
// feature-group-end: removed features
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index e69289b..27390fd 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -512,7 +512,7 @@
pub fn to_dot_string(&self) -> String {
match *self {
LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
- EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
+ EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)),
HtmlStr(ref s) => format!("<{}>", s),
}
}
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index f07e52e..f19ca49 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -1,55 +1,52 @@
-/// This declares a list of types which can be allocated by `Arena`.
-///
-/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
-/// This is faster and more memory efficient if there's only a few allocations of the type.
-/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
-/// faster and more memory efficient if there is lots of allocations.
+/// This higher-order macro declares a list of types which can be allocated by `Arena`.
///
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]`,
/// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
- ($macro:path, $tcx:lifetime) => (
+ ($macro:path) => (
$macro!([
// HIR types
- [few] hir_krate: rustc_hir::Crate<$tcx>,
- [] arm: rustc_hir::Arm<$tcx>,
- [] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span),
+ [] hir_krate: rustc_hir::Crate<'tcx>,
+ [] arm: rustc_hir::Arm<'tcx>,
+ [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, Span),
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
[] attribute: rustc_ast::Attribute,
- [] block: rustc_hir::Block<$tcx>,
- [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
- [] generic_arg: rustc_hir::GenericArg<$tcx>,
- [] generic_args: rustc_hir::GenericArgs<$tcx>,
- [] generic_bound: rustc_hir::GenericBound<$tcx>,
- [] generic_param: rustc_hir::GenericParam<$tcx>,
- [] expr: rustc_hir::Expr<$tcx>,
- [] expr_field: rustc_hir::ExprField<$tcx>,
- [] pat_field: rustc_hir::PatField<$tcx>,
- [] fn_decl: rustc_hir::FnDecl<$tcx>,
- [] foreign_item: rustc_hir::ForeignItem<$tcx>,
- [few] foreign_item_ref: rustc_hir::ForeignItemRef,
- [] impl_item: rustc_hir::ImplItem<$tcx>,
+ [] block: rustc_hir::Block<'tcx>,
+ [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
+ [] body: rustc_hir::Body<'tcx>,
+ [] generic_arg: rustc_hir::GenericArg<'tcx>,
+ [] generic_args: rustc_hir::GenericArgs<'tcx>,
+ [] generic_bound: rustc_hir::GenericBound<'tcx>,
+ [] generic_param: rustc_hir::GenericParam<'tcx>,
+ [] expr: rustc_hir::Expr<'tcx>,
+ [] expr_field: rustc_hir::ExprField<'tcx>,
+ [] pat_field: rustc_hir::PatField<'tcx>,
+ [] fn_decl: rustc_hir::FnDecl<'tcx>,
+ [] foreign_item: rustc_hir::ForeignItem<'tcx>,
+ [] foreign_item_ref: rustc_hir::ForeignItemRef,
+ [] impl_item: rustc_hir::ImplItem<'tcx>,
[] impl_item_ref: rustc_hir::ImplItemRef,
- [] item: rustc_hir::Item<$tcx>,
- [few] inline_asm: rustc_hir::InlineAsm<$tcx>,
- [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
- [] local: rustc_hir::Local<$tcx>,
- [few] mod_: rustc_hir::Mod<$tcx>,
- [] param: rustc_hir::Param<$tcx>,
- [] pat: rustc_hir::Pat<$tcx>,
- [] path: rustc_hir::Path<$tcx>,
- [] path_segment: rustc_hir::PathSegment<$tcx>,
- [] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>,
- [] qpath: rustc_hir::QPath<$tcx>,
- [] stmt: rustc_hir::Stmt<$tcx>,
- [] field_def: rustc_hir::FieldDef<$tcx>,
- [] trait_item: rustc_hir::TraitItem<$tcx>,
+ [] 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>,
+ [] param: rustc_hir::Param<'tcx>,
+ [] pat: rustc_hir::Pat<'tcx>,
+ [] path: rustc_hir::Path<'tcx>,
+ [] path_segment: rustc_hir::PathSegment<'tcx>,
+ [] poly_trait_ref: rustc_hir::PolyTraitRef<'tcx>,
+ [] qpath: rustc_hir::QPath<'tcx>,
+ [] stmt: rustc_hir::Stmt<'tcx>,
+ [] field_def: rustc_hir::FieldDef<'tcx>,
+ [] trait_item: rustc_hir::TraitItem<'tcx>,
[] trait_item_ref: rustc_hir::TraitItemRef,
- [] ty: rustc_hir::Ty<$tcx>,
- [] type_binding: rustc_hir::TypeBinding<$tcx>,
- [] variant: rustc_hir::Variant<$tcx>,
- [] where_predicate: rustc_hir::WherePredicate<$tcx>,
- ], $tcx);
+ [] ty: rustc_hir::Ty<'tcx>,
+ [] type_binding: rustc_hir::TypeBinding<'tcx>,
+ [] variant: rustc_hir::Variant<'tcx>,
+ [] where_predicate: rustc_hir::WherePredicate<'tcx>,
+ ]);
)
}
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index cb668eb..60761a0 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -104,8 +104,10 @@
Use,
/// An `extern` block.
ForeignMod,
- /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
+ /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
AnonConst,
+ /// An inline constant, e.g. `const { 1 + 2 }`
+ InlineConst,
/// Opaque type, aka `impl Trait`.
OpaqueTy,
Field,
@@ -155,6 +157,7 @@
DefKind::Use => "import",
DefKind::ForeignMod => "foreign module",
DefKind::AnonConst => "constant expression",
+ DefKind::InlineConst => "inline constant",
DefKind::Field => "field",
DefKind::Impl => "implementation",
DefKind::Closure => "closure",
@@ -174,6 +177,7 @@
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Use
+ | DefKind::InlineConst
| DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a",
@@ -207,6 +211,7 @@
// Not namespaced.
DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::ExternCrate
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 11d0178..c67d3df 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,7 @@
use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::{DefId, CRATE_DEF_ID};
+use crate::def_id::DefId;
crate use crate::hir_id::{HirId, ItemLocalId};
+use crate::intravisit::FnKind;
use crate::LangItem;
use rustc_ast::util::parser::ExprPrecedence;
@@ -9,7 +10,9 @@
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
@@ -20,7 +23,6 @@
use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
-use std::collections::BTreeMap;
use std::fmt;
#[derive(Copy, Clone, Encodable, HashStable_Generic)]
@@ -121,7 +123,7 @@
match *self {
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit
- | LifetimeName::Error => Ident::invalid(),
+ | LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
LifetimeName::Param(param_name) => param_name.ident(),
@@ -233,7 +235,7 @@
}
pub fn invalid() -> Self {
- Self::from_ident(Ident::invalid())
+ Self::from_ident(Ident::empty())
}
pub fn args(&self) -> &GenericArgs<'hir> {
@@ -310,7 +312,7 @@
}
pub fn is_synthetic(&self) -> bool {
- matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::invalid())
+ matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
}
pub fn descr(&self) -> &'static str {
@@ -502,7 +504,7 @@
},
Type {
default: Option<&'hir Ty<'hir>>,
- synthetic: Option<SyntheticTyParamKind>,
+ synthetic: bool,
},
Const {
ty: &'hir Ty<'hir>,
@@ -575,16 +577,6 @@
}
}
-/// Synthetic type parameters are converted to another form during lowering; this allows
-/// us to track the original form they had, and is useful for error messages.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
-#[derive(HashStable_Generic)]
-pub enum SyntheticTyParamKind {
- ImplTrait,
- // Created by the `#[rustc_synthetic]` attribute.
- FromAttr,
-}
-
/// A where-clause in a definition.
#[derive(Debug, HashStable_Generic)]
pub struct WhereClause<'hir> {
@@ -645,6 +637,22 @@
pub bounds: GenericBounds<'hir>,
}
+impl WhereBoundPredicate<'hir> {
+ /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
+ pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
+ let path = match self.bounded_ty.kind {
+ TyKind::Path(QPath::Resolved(None, path)) => path,
+ _ => return false,
+ };
+ match path.res {
+ Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => {
+ def_id == param_def_id
+ }
+ _ => false,
+ }
+ }
+}
+
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
#[derive(Debug, HashStable_Generic)]
pub struct WhereRegionPredicate<'hir> {
@@ -662,6 +670,74 @@
pub rhs_ty: &'hir Ty<'hir>,
}
+/// HIR node coupled with its parent's id in the same HIR owner.
+///
+/// The parent is trash when the node is a HIR owner.
+#[derive(Clone, Debug)]
+pub struct ParentedNode<'tcx> {
+ pub parent: ItemLocalId,
+ pub node: Node<'tcx>,
+}
+
+/// Attributes owned by a HIR owner.
+#[derive(Debug)]
+pub struct AttributeMap<'tcx> {
+ pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
+ pub hash: Fingerprint,
+}
+
+impl<'tcx> AttributeMap<'tcx> {
+ pub const EMPTY: &'static AttributeMap<'static> =
+ &AttributeMap { map: SortedMap::new(), hash: Fingerprint::ZERO };
+
+ #[inline]
+ pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
+ self.map.get(&id).copied().unwrap_or(&[])
+ }
+}
+
+/// Map of all HIR nodes inside the current owner.
+/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node.
+/// The HIR tree, including bodies, is pre-hashed.
+#[derive(Debug)]
+pub struct OwnerNodes<'tcx> {
+ /// Pre-computed hash of the full HIR.
+ pub hash_including_bodies: Fingerprint,
+ /// Pre-computed hash of the item signature, sithout recursing into the body.
+ pub hash_without_bodies: Fingerprint,
+ /// Full HIR for the current owner.
+ // The zeroth node's parent should never be accessed: the owner's parent is computed by the
+ // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally
+ // used.
+ pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
+ /// Content of local bodies.
+ pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
+}
+
+/// Full information resulting from lowering an AST node.
+#[derive(Debug, HashStable_Generic)]
+pub struct OwnerInfo<'hir> {
+ /// Contents of the HIR.
+ pub nodes: OwnerNodes<'hir>,
+ /// Map from each nested owner to its parent's local id.
+ pub parenting: FxHashMap<LocalDefId, ItemLocalId>,
+ /// Collected attributes of the HIR nodes.
+ pub attrs: AttributeMap<'hir>,
+ /// Map indicating what traits are in scope for places where this
+ /// is relevant; generated by resolve.
+ pub trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
+}
+
+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
+ }
+}
+
/// The top-level data structure that stores the entire contents of
/// the crate currently being compiled.
///
@@ -670,41 +746,8 @@
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
- pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
- pub bodies: BTreeMap<BodyId, Body<'hir>>,
-
- /// Map indicating what traits are in scope for places where this
- /// is relevant; generated by resolve.
- pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
-
- /// Collected attributes from HIR nodes.
- pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
-}
-
-impl Crate<'hir> {
- pub fn module(&self) -> &'hir Mod<'hir> {
- if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() }
- }
-
- pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_item()
- }
-
- pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_trait_item()
- }
-
- pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_impl_item()
- }
-
- pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_foreign_item()
- }
-
- pub fn body(&self, id: BodyId) -> &Body<'hir> {
- &self.bodies[&id]
- }
+ pub owners: IndexVec<LocalDefId, Option<OwnerInfo<'hir>>>,
+ pub hir_hash: Fingerprint,
}
/// A block of statements `{ .. }`, which may have a label (in this case the
@@ -1778,8 +1821,6 @@
pub enum LocalSource {
/// A `match _ { .. }`.
Normal,
- /// A desugared `for _ in _ { .. }` loop.
- ForLoopDesugar,
/// When lowering async functions, we create locals within the `async move` so that
/// all parameters are dropped after the future is polled.
///
@@ -3222,6 +3263,32 @@
_ => None,
}
}
+
+ pub fn fn_kind(self) -> Option<FnKind<'hir>> {
+ match self {
+ Node::Item(i) => match i.kind {
+ ItemKind::Fn(ref sig, ref generics, _) => {
+ Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis))
+ }
+ _ => None,
+ },
+ Node::TraitItem(ti) => match ti.kind {
+ TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => {
+ Some(FnKind::Method(ti.ident, sig, None))
+ }
+ _ => None,
+ },
+ Node::ImplItem(ii) => match ii.kind {
+ ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))),
+ _ => None,
+ },
+ Node::Expr(e) => match e.kind {
+ ExprKind::Closure(..) => Some(FnKind::Closure),
+ _ => None,
+ },
+ _ => None,
+ }
+ }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 0b25ebc..39552eb 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,5 +1,4 @@
use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
-use rustc_index::vec::IndexVec;
use std::fmt;
/// Uniquely identifies a node in the HIR of the current crate. It is
@@ -56,76 +55,13 @@
pub struct ItemLocalId { .. }
}
rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+impl ItemLocalId {
+ /// Signal local id which should never be used.
+ pub const INVALID: ItemLocalId = ItemLocalId::MAX;
+}
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
pub const CRATE_HIR_ID: HirId = HirId {
owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
local_id: ItemLocalId::from_u32(0),
};
-
-/// N.B. This collection is currently unused, but will be used by #72015 and future PRs.
-#[derive(Clone, Default, Debug, Encodable, Decodable)]
-pub struct HirIdVec<T> {
- map: IndexVec<LocalDefId, IndexVec<ItemLocalId, T>>,
-}
-
-impl<T> HirIdVec<T> {
- pub fn push_owner(&mut self, id: LocalDefId) {
- self.map.ensure_contains_elem(id, IndexVec::new);
- }
-
- pub fn push(&mut self, id: HirId, value: T) {
- if id.local_id == ItemLocalId::from_u32(0) {
- self.push_owner(id.owner);
- }
- let submap = &mut self.map[id.owner];
- let _ret_id = submap.push(value);
- debug_assert_eq!(_ret_id, id.local_id);
- }
-
- pub fn push_sparse(&mut self, id: HirId, value: T)
- where
- T: Default,
- {
- self.map.ensure_contains_elem(id.owner, IndexVec::new);
- let submap = &mut self.map[id.owner];
- let i = id.local_id.index();
- let len = submap.len();
- if i >= len {
- submap.extend(std::iter::repeat_with(T::default).take(i - len + 1));
- }
- submap[id.local_id] = value;
- }
-
- pub fn get(&self, id: HirId) -> Option<&T> {
- self.map.get(id.owner)?.get(id.local_id)
- }
-
- pub fn get_owner(&self, id: LocalDefId) -> &IndexVec<ItemLocalId, T> {
- &self.map[id]
- }
-
- pub fn iter(&self) -> impl Iterator<Item = &T> {
- self.map.iter().flat_map(|la| la.iter())
- }
-
- pub fn iter_enumerated(&self) -> impl Iterator<Item = (HirId, &T)> {
- self.map.iter_enumerated().flat_map(|(owner, la)| {
- la.iter_enumerated().map(move |(local_id, attr)| (HirId { owner, local_id }, attr))
- })
- }
-}
-
-impl<T> std::ops::Index<HirId> for HirIdVec<T> {
- type Output = T;
-
- fn index(&self, id: HirId) -> &T {
- &self.map[id.owner][id.local_id]
- }
-}
-
-impl<T> std::ops::IndexMut<HirId> for HirIdVec<T> {
- fn index_mut(&mut self, id: HirId) -> &mut T {
- &mut self.map[id.owner][id.local_id]
- }
-}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 1ac2625..cff5437 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -117,6 +117,14 @@
FnKind::Closure => None,
}
}
+
+ pub fn constness(self) -> Constness {
+ self.header().map_or(Constness::NotConst, |header| header.constness)
+ }
+
+ pub fn asyncness(self) -> IsAsync {
+ self.header().map_or(IsAsync::NotAsync, |header| header.asyncness)
+ }
}
/// An abstract representation of the HIR `rustc_middle::hir::map::Map`.
@@ -130,6 +138,28 @@
fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
}
+// Used when no map is actually available, forcing manual implementation of nested visitors.
+impl Map<'hir> for ! {
+ fn find(&self, _: HirId) -> Option<Node<'hir>> {
+ unreachable!()
+ }
+ fn body(&self, _: BodyId) -> &'hir Body<'hir> {
+ unreachable!()
+ }
+ fn item(&self, _: ItemId) -> &'hir Item<'hir> {
+ unreachable!()
+ }
+ fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
+ unreachable!()
+ }
+ fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
+ unreachable!()
+ }
+ fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ unreachable!()
+ }
+}
+
/// 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>);
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index f35353d..05659e9 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -268,6 +268,7 @@
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None;
Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1);
+ GeneratorReturn, sym::generator_return, generator_return, Target::AssocTy, GenericRequirement::None;
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
@@ -281,18 +282,17 @@
// in the sense that a crate is not required to have it defined to use it, but a final product
// is required to define it somewhere. Additionally, there are restrictions on crates that use
// a weak lang item, but do not have it defined.
- Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::None;
+ Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
- PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::None;
+ PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
/// libstd panic entry point. Necessary for const eval to be able to catch it
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
- BeginPanicFmt, sym::begin_panic_fmt, begin_panic_fmt, Target::Fn, GenericRequirement::None;
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1);
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index f5ea044..93224d3 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -2,10 +2,12 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+#![feature(const_btree_new)]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(once_cell)]
#![feature(min_specialization)]
+#![feature(never_type)]
#![recursion_limit = "256"]
#[macro_use]
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index b1f78a8..b300761 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -2,6 +2,7 @@
use crate::def_id::DefId;
use crate::hir::{self, HirId, PatKind};
use rustc_data_structures::stable_set::FxHashSet;
+use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -143,4 +144,14 @@
});
result
}
+
+ /// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
+ pub fn for_loop_some(&self) -> Option<&Self> {
+ if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+ if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
+ return Some(pat_field.pat);
+ }
+ }
+ None
+ }
}
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 9d5ef27..6e7b765 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,8 +1,8 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use crate::hir::{
- BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem,
- TraitItemId, Ty, VisibilityKind,
+ AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item,
+ ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
};
use crate::hir_id::{HirId, ItemLocalId};
use rustc_span::def_id::DefPathHash;
@@ -21,6 +21,7 @@
fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
+ fn hash_hir_trait_candidate(&mut self, _: &TraitCandidate, hasher: &mut StableHasher);
}
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
@@ -209,3 +210,35 @@
});
}
}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
+ 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;
+ hash_including_bodies.hash_stable(hcx, hasher);
+ }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ // We ignore the `map` since it refers to information included in `hash` which is hashed in
+ // the collector and used for the crate hash.
+ let AttributeMap { hash, map: _ } = *self;
+ hash.hash_stable(hcx, hasher);
+ }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ let Crate { owners: _, hir_hash } = self;
+ hir_hash.hash_stable(hcx, hasher)
+ }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitCandidate {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ hcx.hash_hir_trait_candidate(self, hasher)
+ }
+}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 9196344..9c29271 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -15,7 +15,6 @@
use std::borrow::Cow;
use std::cell::Cell;
-use std::collections::BTreeMap;
use std::vec;
pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String {
@@ -69,7 +68,7 @@
pub struct State<'a> {
pub s: pp::Printer,
comments: Option<Comments<'a>>,
- attrs: &'a BTreeMap<hir::HirId, &'a [ast::Attribute]>,
+ attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a (dyn PpAnn + 'a),
}
@@ -146,17 +145,18 @@
/// it can scan the input text for comments to copy forward.
pub fn print_crate<'a>(
sm: &'a SourceMap,
- krate: &hir::Crate<'_>,
+ krate: &hir::Mod<'_>,
filename: FileName,
input: String,
+ attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a dyn PpAnn,
) -> String {
- let mut s = State::new_from_input(sm, filename, input, &krate.attrs, ann);
+ let mut s = State::new_from_input(sm, filename, input, attrs, ann);
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
- s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID));
+ s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID));
s.print_remaining_comments();
s.s.eof()
}
@@ -166,7 +166,7 @@
sm: &'a SourceMap,
filename: FileName,
input: String,
- attrs: &'a BTreeMap<hir::HirId, &[ast::Attribute]>,
+ attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a dyn PpAnn,
) -> State<'a> {
State {
@@ -178,7 +178,7 @@
}
fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
- self.attrs.get(&id).map_or(&[], |la| *la)
+ (self.attrs)(id)
}
}
@@ -186,8 +186,7 @@
where
F: FnOnce(&mut State<'_>),
{
- let mut printer =
- State { s: pp::mk_printer(), comments: None, attrs: &BTreeMap::default(), ann };
+ let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann };
f(&mut printer);
printer.s.eof()
}
@@ -1168,7 +1167,7 @@
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
}
- // Does `expr` need parenthesis when printed in a condition position?
+ // 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) {}`.
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index d42e2f7..571337a 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -126,30 +126,36 @@
if attr.has_name(sym::rustc_if_this_changed) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
- None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
- Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
- Ok(n) => n,
- Err(()) => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unrecognized DepNode variant {:?}", n),
- );
+ None => {
+ DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
+ }
+ Some(n) => {
+ match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) {
+ Ok(n) => n,
+ Err(()) => {
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("unrecognized DepNode variant {:?}", n),
+ );
+ }
}
- },
+ }
};
self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
} else if attr.has_name(sym::rustc_then_this_would_need) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
- Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
- Ok(n) => n,
- Err(()) => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unrecognized DepNode variant {:?}", n),
- );
+ Some(n) => {
+ match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) {
+ Ok(n) => n,
+ Err(()) => {
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("unrecognized DepNode variant {:?}", n),
+ );
+ }
}
- },
+ }
None => {
self.tcx.sess.span_fatal(attr.span, "missing DepNode variant");
}
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index f089cbc..dd3f8c9 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -2,6 +2,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 5528638..b2eaf61 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -15,7 +15,7 @@
use rustc_ast::{self as ast, Attribute, NestedMetaItem};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::Node as HirNode;
@@ -302,18 +302,6 @@
out
}
- fn dep_nodes<'l>(
- &self,
- labels: &'l Labels,
- def_id: DefId,
- ) -> impl Iterator<Item = DepNode> + 'l {
- let def_path_hash = self.tcx.def_path_hash(def_id);
- labels.iter().map(move |label| match DepNode::from_label_string(label, def_path_hash) {
- Ok(dep_node) => dep_node,
- Err(()) => unreachable!("label: {}", label),
- })
- }
-
fn dep_node_str(&self, dep_node: &DepNode) -> String {
if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
@@ -345,16 +333,19 @@
}
fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
+ let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
let assertion = match self.assertion_maybe(item_id, attr) {
Some(a) => a,
None => continue,
};
self.checked_attrs.insert(attr.id);
- for dep_node in self.dep_nodes(&assertion.clean, item_id.to_def_id()) {
+ for label in assertion.clean {
+ let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
self.assert_clean(item_span, dep_node);
}
- for dep_node in self.dep_nodes(&assertion.dirty, item_id.to_def_id()) {
+ for label in assertion.dirty {
+ let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
self.assert_dirty(item_span, dep_node);
}
}
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 572a4fc..392c5bd 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -95,6 +95,12 @@
return;
}
+ sess.prof.artifact_size(
+ &name.replace(' ', "_"),
+ path_buf.file_name().unwrap().to_string_lossy(),
+ encoder.position() as u64,
+ );
+
debug!("save: data written to disk successfully");
}
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 2ed0539..c0137fc 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -139,9 +139,6 @@
pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
}
-pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf {
- in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME)
-}
pub fn work_products_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
@@ -241,9 +238,7 @@
// have already tried before.
let source_directory = find_source_directory(&crate_dir, &source_directories_already_tried);
- let source_directory = if let Some(dir) = source_directory {
- dir
- } else {
+ let Some(source_directory) = source_directory else {
// There's nowhere to copy from, we're done
debug!(
"no source directory found. Continuing with empty session \
@@ -397,15 +392,14 @@
// We acquire a shared lock on the lock file of the directory, so that
// nobody deletes it out from under us while we are reading from it.
let lock_file_path = lock_file_path(source_dir);
- let _lock = if let Ok(lock) = flock::Lock::new(
+
+ // not exclusive
+ let Ok(_lock) = flock::Lock::new(
&lock_file_path,
false, // don't wait,
false, // don't create
false,
- ) {
- // not exclusive
- lock
- } else {
+ ) else {
// Could not acquire the lock, don't try to copy from here
return Err(());
};
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 4d38556..9c6e2ae 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -6,6 +6,7 @@
use rustc_middle::ty::OnDiskCache;
use rustc_serialize::opaque::Decoder;
use rustc_serialize::Decodable;
+use rustc_session::config::IncrementalStateAssertion;
use rustc_session::Session;
use std::path::Path;
@@ -16,6 +17,7 @@
type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
+#[derive(Debug)]
pub enum LoadResult<T> {
Ok { data: T },
DataOutOfDate,
@@ -24,6 +26,26 @@
impl<T: Default> LoadResult<T> {
pub fn open(self, sess: &Session) -> T {
+ // Check for errors when using `-Zassert-incremental-state`
+ match (sess.opts.assert_incr_state, &self) {
+ (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
+ sess.fatal(
+ "We asserted that the incremental cache should not be loaded, \
+ but it was loaded.",
+ );
+ }
+ (
+ Some(IncrementalStateAssertion::Loaded),
+ LoadResult::Error { .. } | LoadResult::DataOutOfDate,
+ ) => {
+ sess.fatal(
+ "We asserted that an existing incremental cache directory should \
+ be successfully loaded, but it was not.",
+ );
+ }
+ _ => {}
+ };
+
match self {
LoadResult::Error { message } => {
sess.warn(&message);
@@ -33,7 +55,7 @@
if let Err(err) = delete_all_session_dir_contents(sess) {
sess.err(&format!(
"Failed to delete invalidated or incompatible \
- incremental compilation session directory contents `{}`: {}.",
+ incremental compilation session directory contents `{}`: {}.",
dep_graph_path(sess).display(),
err
));
@@ -105,7 +127,7 @@
// Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
// Fortunately, we just checked that this isn't the case.
- let path = dep_graph_path_from(&sess.incr_comp_session_dir());
+ let path = dep_graph_path(&sess);
let report_incremental_info = sess.opts.debugging_opts.incremental_info;
let expected_hash = sess.opts.dep_tracking_hash(false);
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 573124c..08f13d4 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -4,7 +4,7 @@
use std::iter;
use std::marker::PhantomData;
use std::mem;
-use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
+use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl};
use std::slice;
use rustc_macros::{Decodable, Encodable};
@@ -22,6 +22,29 @@
fn intersect(&mut self, other: &Rhs) -> bool;
}
+#[inline]
+fn inclusive_start_end<T: Idx>(
+ range: impl RangeBounds<T>,
+ domain: usize,
+) -> Option<(usize, usize)> {
+ // Both start and end are inclusive.
+ let start = match range.start_bound().cloned() {
+ Bound::Included(start) => start.index(),
+ Bound::Excluded(start) => start.index() + 1,
+ Bound::Unbounded => 0,
+ };
+ let end = match range.end_bound().cloned() {
+ Bound::Included(end) => end.index(),
+ Bound::Excluded(end) => end.index().checked_sub(1)?,
+ Bound::Unbounded => domain - 1,
+ };
+ assert!(end < domain);
+ if start > end {
+ return None;
+ }
+ Some((start, end))
+}
+
macro_rules! bit_relations_inherent_impls {
() => {
/// Sets `self = self | other` and returns `true` if `self` changed
@@ -151,6 +174,33 @@
new_word != word
}
+ #[inline]
+ pub fn insert_range(&mut self, elems: impl RangeBounds<T>) {
+ let Some((start, end)) = inclusive_start_end(elems, self.domain_size) else {
+ return;
+ };
+
+ let (start_word_index, start_mask) = word_index_and_mask(start);
+ let (end_word_index, end_mask) = word_index_and_mask(end);
+
+ // Set all words in between start and end (exclusively of both).
+ for word_index in (start_word_index + 1)..end_word_index {
+ self.words[word_index] = !0;
+ }
+
+ if start_word_index != end_word_index {
+ // Start and end are in different words, so we handle each in turn.
+ //
+ // We set all leading bits. This includes the start_mask bit.
+ self.words[start_word_index] |= !(start_mask - 1);
+ // And all trailing bits (i.e. from 0..=end) in the end word,
+ // including the end.
+ self.words[end_word_index] |= end_mask | end_mask - 1;
+ } else {
+ self.words[start_word_index] |= end_mask | (end_mask - start_mask);
+ }
+ }
+
/// Sets all bits to true.
pub fn insert_all(&mut self) {
for word in &mut self.words {
@@ -227,6 +277,36 @@
not_already
}
+ fn last_set_in(&self, range: impl RangeBounds<T>) -> Option<T> {
+ let (start, end) = inclusive_start_end(range, self.domain_size)?;
+ let (start_word_index, _) = word_index_and_mask(start);
+ let (end_word_index, end_mask) = word_index_and_mask(end);
+
+ let end_word = self.words[end_word_index] & (end_mask | (end_mask - 1));
+ if end_word != 0 {
+ let pos = max_bit(end_word) + WORD_BITS * end_word_index;
+ if start <= pos {
+ return Some(T::new(pos));
+ }
+ }
+
+ // We exclude end_word_index from the range here, because we don't want
+ // to limit ourselves to *just* the last word: the bits set it in may be
+ // after `end`, so it may not work out.
+ if let Some(offset) =
+ self.words[start_word_index..end_word_index].iter().rposition(|&w| w != 0)
+ {
+ let word_idx = start_word_index + offset;
+ let start_word = self.words[word_idx];
+ let pos = max_bit(start_word) + WORD_BITS * word_idx;
+ if start <= pos {
+ return Some(T::new(pos));
+ }
+ }
+
+ None
+ }
+
bit_relations_inherent_impls! {}
}
@@ -635,6 +715,16 @@
self.elems.iter()
}
+ fn last_set_in(&self, range: impl RangeBounds<T>) -> Option<T> {
+ let mut last_leq = None;
+ for e in self.iter() {
+ if range.contains(e) {
+ last_leq = Some(*e);
+ }
+ }
+ last_leq
+ }
+
bit_relations_inherent_impls! {}
}
@@ -709,6 +799,16 @@
}
}
+ /// Returns the previous element present in the bitset from `elem`,
+ /// inclusively of elem. That is, will return `Some(elem)` if elem is in the
+ /// bitset.
+ pub fn last_set_in(&self, range: impl RangeBounds<T>) -> Option<T> {
+ match self {
+ HybridBitSet::Sparse(sparse) => sparse.last_set_in(range),
+ HybridBitSet::Dense(dense) => dense.last_set_in(range),
+ }
+ }
+
pub fn insert(&mut self, elem: T) -> bool {
// No need to check `elem` against `self.domain_size` here because all
// the match cases check it, one way or another.
@@ -734,6 +834,41 @@
}
}
+ pub fn insert_range(&mut self, elems: impl RangeBounds<T>) {
+ // No need to check `elem` against `self.domain_size` here because all
+ // the match cases check it, one way or another.
+ let start = match elems.start_bound().cloned() {
+ Bound::Included(start) => start.index(),
+ Bound::Excluded(start) => start.index() + 1,
+ Bound::Unbounded => 0,
+ };
+ let end = match elems.end_bound().cloned() {
+ Bound::Included(end) => end.index() + 1,
+ Bound::Excluded(end) => end.index(),
+ Bound::Unbounded => self.domain_size() - 1,
+ };
+ let len = if let Some(l) = end.checked_sub(start) {
+ l
+ } else {
+ return;
+ };
+ match self {
+ HybridBitSet::Sparse(sparse) if sparse.len() + len < SPARSE_MAX => {
+ // The set is sparse and has space for `elems`.
+ for elem in start..end {
+ sparse.insert(T::new(elem));
+ }
+ }
+ HybridBitSet::Sparse(sparse) => {
+ // The set is sparse and full. Convert to a dense set.
+ let mut dense = sparse.to_dense();
+ dense.insert_range(elems);
+ *self = HybridBitSet::Dense(dense);
+ }
+ HybridBitSet::Dense(dense) => dense.insert_range(elems),
+ }
+ }
+
pub fn insert_all(&mut self) {
let domain_size = self.domain_size();
match self {
@@ -990,8 +1125,9 @@
pub fn insert_all_into_row(&mut self, row: R) {
assert!(row.index() < self.num_rows);
let (start, end) = self.range(row);
- for word in self.words[start..end].iter_mut() {
- *word = !0;
+ let words = &mut self.words[..];
+ for index in start..end {
+ words[index] = !0;
}
self.clear_excess_bits(row);
}
@@ -1143,7 +1279,7 @@
/// Iterates through all the columns set to true in a given row of
/// the matrix.
- pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ {
+ pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
self.row(row).into_iter().flat_map(|r| r.iter())
}
@@ -1204,6 +1340,11 @@
(word_index, mask)
}
+#[inline]
+fn max_bit(word: Word) -> usize {
+ WORD_BITS - 1 - word.leading_zeros() as usize
+}
+
/// Integral type used to represent the bit set.
pub trait FiniteBitSetTy:
BitAnd<Output = Self>
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index aebc6d0..e2b0730 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -370,6 +370,101 @@
}
}
+#[test]
+fn dense_insert_range() {
+ #[track_caller]
+ fn check<R>(domain: usize, range: R)
+ where
+ R: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug,
+ {
+ let mut set = BitSet::new_empty(domain);
+ set.insert_range(range.clone());
+ for i in set.iter() {
+ assert!(range.contains(&i));
+ }
+ for i in range.clone() {
+ assert!(set.contains(i), "{} in {:?}, inserted {:?}", i, set, range);
+ }
+ }
+ check(300, 10..10);
+ check(300, WORD_BITS..WORD_BITS * 2);
+ check(300, WORD_BITS - 1..WORD_BITS * 2);
+ check(300, WORD_BITS - 1..WORD_BITS);
+ check(300, 10..100);
+ check(300, 10..30);
+ check(300, 0..5);
+ check(300, 0..250);
+ check(300, 200..250);
+
+ check(300, 10..=10);
+ check(300, WORD_BITS..=WORD_BITS * 2);
+ check(300, WORD_BITS - 1..=WORD_BITS * 2);
+ check(300, WORD_BITS - 1..=WORD_BITS);
+ check(300, 10..=100);
+ check(300, 10..=30);
+ check(300, 0..=5);
+ check(300, 0..=250);
+ check(300, 200..=250);
+
+ for i in 0..WORD_BITS * 2 {
+ for j in i..WORD_BITS * 2 {
+ check(WORD_BITS * 2, i..j);
+ check(WORD_BITS * 2, i..=j);
+ check(300, i..j);
+ check(300, i..=j);
+ }
+ }
+}
+
+#[test]
+fn dense_last_set_before() {
+ fn easy(set: &BitSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> {
+ let mut last_leq = None;
+ for e in set.iter() {
+ if needle.contains(&e) {
+ last_leq = Some(e);
+ }
+ }
+ last_leq
+ }
+
+ #[track_caller]
+ fn cmp(set: &BitSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) {
+ assert_eq!(
+ set.last_set_in(needle.clone()),
+ easy(set, needle.clone()),
+ "{:?} in {:?}",
+ needle,
+ set
+ );
+ }
+ let mut set = BitSet::new_empty(300);
+ cmp(&set, 50..=50);
+ set.insert(WORD_BITS);
+ cmp(&set, WORD_BITS..=WORD_BITS);
+ set.insert(WORD_BITS - 1);
+ cmp(&set, 0..=WORD_BITS - 1);
+ cmp(&set, 0..=5);
+ cmp(&set, 10..100);
+ set.insert(100);
+ cmp(&set, 100..110);
+ cmp(&set, 99..100);
+ cmp(&set, 99..=100);
+
+ for i in 0..=WORD_BITS * 2 {
+ for j in i..=WORD_BITS * 2 {
+ for k in 0..WORD_BITS * 2 {
+ let mut set = BitSet::new_empty(300);
+ cmp(&set, i..j);
+ cmp(&set, i..=j);
+ set.insert(k);
+ cmp(&set, i..j);
+ cmp(&set, i..=j);
+ }
+ }
+ }
+}
+
/// Merge dense hybrid set into empty sparse hybrid set.
#[bench]
fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) {
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index a72a27e..5149322 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -3,7 +3,9 @@
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(min_specialization)]
+#![feature(step_trait)]
#![feature(test)]
+#![feature(let_else)]
pub mod bit_set;
pub mod vec;
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 69578e8..55ccfd0 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -118,38 +118,54 @@
}
impl $type {
+ /// Maximum value the index can take, as a `u32`.
$v const MAX_AS_U32: u32 = $max;
+ /// Maximum value the index can take.
$v const MAX: Self = Self::from_u32($max);
+ /// Creates a new index from a given `usize`.
+ ///
+ /// # Panics
+ ///
+ /// Will panic if `value` exceeds `MAX`.
#[inline]
$v const fn from_usize(value: usize) -> Self {
- #[cfg(not(bootstrap))]
assert!(value <= ($max as usize));
- #[cfg(bootstrap)]
- [()][(value > ($max as usize)) as usize];
+ // SAFETY: We just checked that `value <= max`.
unsafe {
Self::from_u32_unchecked(value as u32)
}
}
+ /// Creates a new index from a given `u32`.
+ ///
+ /// # Panics
+ ///
+ /// Will panic if `value` exceeds `MAX`.
#[inline]
$v const fn from_u32(value: u32) -> Self {
- #[cfg(not(bootstrap))]
assert!(value <= $max);
- #[cfg(bootstrap)]
- [()][(value > $max) as usize];
+ // SAFETY: We just checked that `value <= max`.
unsafe {
Self::from_u32_unchecked(value)
}
}
+ /// Creates a new index from a given `u32`.
+ ///
+ /// # Safety
+ ///
+ /// The provided value must be less than or equal to the maximum value for the newtype.
+ /// Providing a value outside this range is undefined due to layout restrictions.
+ ///
+ /// Prefer using `from_u32`.
#[inline]
$v const unsafe fn from_u32_unchecked(value: u32) -> Self {
Self { private: value }
}
- /// Extracts the value of this index as an integer.
+ /// Extracts the value of this index as a `usize`.
#[inline]
$v const fn index(self) -> usize {
self.as_usize()
@@ -634,15 +650,18 @@
}
#[inline]
- pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ {
+ pub fn drain<'a, R: RangeBounds<usize>>(
+ &'a mut self,
+ range: R,
+ ) -> impl Iterator<Item = T> + 'a {
self.raw.drain(range)
}
#[inline]
- pub fn drain_enumerated<R: RangeBounds<usize>>(
- &mut self,
+ pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
+ &'a mut self,
range: R,
- ) -> impl Iterator<Item = (I, T)> + '_ {
+ ) -> impl Iterator<Item = (I, T)> + 'a {
self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
}
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 2296cc6..5b4a9d9 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -108,7 +108,7 @@
let tcx = self.tcx;
// Select everything, returning errors.
- let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
+ let true_errors = fulfill_cx.select_where_possible(self);
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() {
@@ -118,7 +118,7 @@
}
// Anything left unselected *now* must be an ambiguity.
- let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
+ let ambig_errors = fulfill_cx.select_all_or_error(self);
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations();
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 3f54247..09bfb32 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -866,6 +866,7 @@
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
}
+ #[tracing::instrument(level = "debug", skip(self))]
fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug_assert_eq!(t, _t);
debug!("ConstInferUnifier: t={:?}", t);
@@ -941,6 +942,7 @@
}
}
+ #[tracing::instrument(level = "debug", skip(self))]
fn consts(
&mut self,
c: &'tcx ty::Const<'tcx>,
@@ -951,29 +953,38 @@
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();
-
// Check if the current unification would end up
// unifying `target_vid` with a const which contains
// an inference variable which is unioned with `target_vid`.
//
// Not doing so can easily result in stack overflows.
- if variable_table.unioned(self.target_vid, vid) {
+ if self
+ .infcx
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .unioned(self.target_vid, vid)
+ {
return Err(TypeError::CyclicConst(c));
}
- let var_value = variable_table.probe_value(vid);
+ let var_value =
+ self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
match var_value.val {
ConstVariableValue::Known { value: u } => self.consts(u, u),
ConstVariableValue::Unknown { universe } => {
if self.for_universe.can_name(universe) {
Ok(c)
} else {
- let new_var_id = variable_table.new_key(ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown { universe: self.for_universe },
- });
+ let new_var_id =
+ self.infcx.inner.borrow_mut().const_unification_table().new_key(
+ ConstVarValue {
+ origin: var_value.origin,
+ val: ConstVariableValue::Unknown {
+ universe: self.for_universe,
+ },
+ },
+ );
Ok(self.tcx().mk_const_var(new_var_id, c.ty))
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 126c25f..85226e6 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -310,6 +310,34 @@
err
}
+/// Structurally compares two types, modulo any inference variables.
+///
+/// Returns `true` if two types are equal, or if one type is an inference variable compatible
+/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
+/// FloatVar inference type are compatible with themselves or their concrete types (Int and
+/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
+pub fn same_type_modulo_infer(a: Ty<'tcx>, b: Ty<'ctx>) -> bool {
+ match (&a.kind(), &b.kind()) {
+ (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
+ if did_a != did_b {
+ return false;
+ }
+
+ substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b))
+ }
+ (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
+ | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)))
+ | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
+ | (
+ &ty::Infer(ty::InferTy::FloatVar(_)),
+ &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
+ )
+ | (&ty::Infer(ty::InferTy::TyVar(_)), _)
+ | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
+ _ => a == b,
+ }
+}
+
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
debug!("report_region_errors(): {} errors to start", errors.len());
@@ -386,21 +414,6 @@
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
}
-
- RegionResolutionError::MemberConstraintFailure {
- hidden_ty,
- member_region,
- span,
- } => {
- let hidden_ty = self.resolve_vars_if_possible(hidden_ty);
- unexpected_hidden_region_diagnostic(
- self.tcx,
- span,
- hidden_ty,
- member_region,
- )
- .emit();
- }
}
}
}
@@ -438,8 +451,7 @@
RegionResolutionError::GenericBoundFailure(..) => true,
RegionResolutionError::ConcreteFailure(..)
| RegionResolutionError::SubSupConflict(..)
- | RegionResolutionError::UpperBoundUniverseConflict(..)
- | RegionResolutionError::MemberConstraintFailure { .. } => false,
+ | RegionResolutionError::UpperBoundUniverseConflict(..) => false,
};
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
@@ -454,7 +466,6 @@
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
- RegionResolutionError::MemberConstraintFailure { span, .. } => span,
});
errors
}
@@ -1483,7 +1494,7 @@
let mut returned_async_output_error = false;
for &sp in values {
if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
- if &[sp] != err.span.primary_spans() {
+ if [sp] != err.span.primary_spans() {
let mut span: MultiSpan = sp.into();
span.push_span_label(
sp,
@@ -1684,11 +1695,23 @@
}
_ => exp_found,
};
- debug!("exp_found {:?} terr {:?}", exp_found, terr);
+ debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code);
if let Some(exp_found) = exp_found {
- self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
- self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
- self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+ let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
+ &cause.code
+ {
+ // Skip if the root_ty of the pattern is not the same as the expected_ty.
+ // If these types aren't equal then we've probably peeled off a layer of arrays.
+ same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected)
+ } else {
+ true
+ };
+
+ if should_suggest_fixes {
+ self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
+ self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
+ self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+ }
}
// In some (most?) cases cause.body_id points to actual body, but in some cases
@@ -1721,13 +1744,7 @@
if let ty::Opaque(def_id, substs) = ty.kind() {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
// Future::Output
- let item_def_id = self
- .tcx
- .associated_items(future_trait)
- .in_definition_order()
- .next()
- .unwrap()
- .def_id;
+ let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
let bounds = self.tcx.explicit_item_bounds(*def_id);
@@ -1784,7 +1801,7 @@
self.get_impl_future_output_ty(exp_found.expected),
self.get_impl_future_output_ty(exp_found.found),
) {
- (Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
+ (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code {
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
diag.multipart_suggestion(
"consider `await`ing on both `Future`s",
@@ -1816,32 +1833,39 @@
diag.help("consider `await`ing on both `Future`s");
}
},
- (_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
- let span = match cause.code {
- // scrutinee's span
- ObligationCauseCode::Pattern { span: Some(span), .. } => span,
- _ => exp_span,
- };
+ (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => {
diag.span_suggestion_verbose(
- span.shrink_to_hi(),
+ exp_span.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await".to_string(),
Applicability::MaybeIncorrect,
);
}
- (Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => {
- let span = match cause.code {
- // scrutinee's span
- ObligationCauseCode::Pattern { span: Some(span), .. } => span,
- _ => exp_span,
- };
- diag.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider `await`ing on the `Future`",
- ".await".to_string(),
- Applicability::MaybeIncorrect,
- );
- }
+ (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code {
+ ObligationCauseCode::Pattern { span: Some(span), .. }
+ | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
+ diag.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "consider `await`ing on the `Future`",
+ ".await".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+ ref prior_arms,
+ ..
+ }) => {
+ diag.multipart_suggestion_verbose(
+ "consider `await`ing on the `Future`",
+ prior_arms
+ .iter()
+ .map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
+ .collect(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ },
_ => {}
}
}
@@ -1867,7 +1891,7 @@
.iter()
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
.map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
- .find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
+ .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) {
@@ -1932,7 +1956,7 @@
| (_, ty::Infer(_))
| (ty::Param(_), _)
| (ty::Infer(_), _) => {}
- _ if ty::TyS::same_type(exp_ty, found_ty) => {}
+ _ if same_type_modulo_infer(exp_ty, found_ty) => {}
_ => show_suggestion = false,
};
}
@@ -2129,10 +2153,19 @@
None
},
self.tcx.generics_of(owner.to_def_id()),
+ hir.span(hir_id),
)
});
+
+ let span = match generics {
+ // This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal
+ // for other diagnostics, so we need to recover it here.
+ Some((_, _, node)) if span.is_dummy() => node,
+ _ => span,
+ };
+
let type_param_span = match (generics, bound_kind) {
- (Some((_, ref generics)), GenericKind::Param(ref param)) => {
+ (Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
// Account for the case where `param` corresponds to `Self`,
// which doesn't have the expected type argument.
if !(generics.has_self && param.index == 0) {
@@ -2169,7 +2202,7 @@
};
let new_lt = generics
.as_ref()
- .and_then(|(parent_g, g)| {
+ .and_then(|(parent_g, g, _)| {
let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char));
let mut lts_names = g
.params
@@ -2191,7 +2224,7 @@
.unwrap_or("'lt".to_string());
let add_lt_sugg = generics
.as_ref()
- .and_then(|(_, g)| g.params.first())
+ .and_then(|(_, g, _)| g.params.first())
.and_then(|param| param.def_id.as_local())
.map(|def_id| {
(
@@ -2207,14 +2240,12 @@
if let Some(SubregionOrigin::CompareImplMethodObligation {
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
}) = origin
{
return self.report_extra_impl_obligation(
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
&format!("`{}: {}`", bound_kind, sub),
@@ -2547,7 +2578,7 @@
infer::MiscVariable(_) => String::new(),
infer::PatternRegion(_) => " for pattern".to_string(),
infer::AddrOfRegion(_) => " for borrow expression".to_string(),
- infer::Autoref(_, _) => " for autoref".to_string(),
+ infer::Autoref(_) => " for autoref".to_string(),
infer::Coercion(_) => " for automatic coercion".to_string(),
infer::LateBoundRegion(_, br, infer::FnCall) => {
format!(" for lifetime parameter {}in function call", br_string(br))
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 e00003f..a7e019a 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
@@ -5,13 +5,12 @@
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
use rustc_middle::hir::map::Map;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::kw;
use rustc_span::Span;
use std::borrow::Cow;
@@ -26,6 +25,7 @@
found_closure: Option<&'tcx Expr<'tcx>>,
found_method_call: Option<&'tcx Expr<'tcx>>,
found_exact_method_call: Option<&'tcx Expr<'tcx>>,
+ found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
}
@@ -41,6 +41,7 @@
found_closure: None,
found_method_call: None,
found_exact_method_call: None,
+ found_for_loop_iter: None,
found_use_diagnostic: None,
}
}
@@ -111,6 +112,15 @@
}
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind {
+ if let Some(pat) = arm.pat.for_loop_some() {
+ if let Some(ty) = self.node_ty_contains_target(pat.hir_id) {
+ self.found_for_loop_iter = Some(scrutinee);
+ self.found_node_ty = Some(ty);
+ return;
+ }
+ }
+ }
if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
if call_span == self.target_span
&& Some(self.target)
@@ -643,10 +653,7 @@
let msg = if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.desugaring_kind() {
None => format!("consider giving `{}` {}", simple_ident, suffix),
- Some(DesugaringKind::ForLoop(_)) => {
- "the element type for this iterator is not specified".to_string()
- }
- _ => format!("this needs {}", suffix),
+ Some(_) => format!("this needs {}", suffix),
}
} else {
format!("consider giving this pattern {}", suffix)
@@ -719,6 +726,11 @@
// = note: type must be known at this point
self.annotate_method_call(segment, e, &mut err);
}
+ } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
+ err.span_label(
+ scrutinee.span,
+ "the element type for this iterator is not specified".to_string(),
+ );
}
// Instead of the following:
// error[E0282]: type annotations needed
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 1b35c40..ac57796 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
@@ -7,7 +7,10 @@
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
-use rustc_errors::{struct_span_err, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
+use rustc_hir::{GenericParamKind, Ty};
+use rustc_middle::ty::Region;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -160,11 +163,13 @@
}
};
- let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
+ let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
- e.span_label(span_1, main_label);
- e.span_label(span_2, String::new());
- e.span_label(span, span_label);
+ err.span_label(span_1, main_label);
+ err.span_label(span_2, String::new());
+ err.span_label(span, span_label);
+
+ self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
if let Some(t) = future_return_type {
let snip = self
@@ -178,14 +183,87 @@
(_, "") => None,
_ => Some(s),
})
- .unwrap_or("{unnamed_type}".to_string());
+ .unwrap_or_else(|| "{unnamed_type}".to_string());
- e.span_label(
+ err.span_label(
t.span,
&format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
);
}
- e.emit();
+ err.emit();
Some(ErrorReported)
}
+
+ fn suggest_adding_lifetime_params(
+ &self,
+ sub: Region<'tcx>,
+ ty_sup: &Ty<'_>,
+ ty_sub: &Ty<'_>,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ if let (
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+ ) = (ty_sub, ty_sup)
+ {
+ if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
+ if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
+ let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
+ if let hir::Node::Item(&hir::Item {
+ kind: hir::ItemKind::Fn(_, ref generics, ..),
+ ..
+ }) = self.tcx().hir().get(hir_id)
+ {
+ let (suggestion_param_name, introduce_new) = generics
+ .params
+ .iter()
+ .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+ .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
+ .map(|name| (name, false))
+ .unwrap_or_else(|| ("'a".to_string(), true));
+
+ let mut suggestions = vec![
+ if let hir::LifetimeName::Underscore = lifetime_sub.name {
+ (lifetime_sub.span, suggestion_param_name.clone())
+ } else {
+ (
+ lifetime_sub.span.shrink_to_hi(),
+ suggestion_param_name.clone() + " ",
+ )
+ },
+ if let hir::LifetimeName::Underscore = lifetime_sup.name {
+ (lifetime_sup.span, suggestion_param_name.clone())
+ } else {
+ (
+ lifetime_sup.span.shrink_to_hi(),
+ suggestion_param_name.clone() + " ",
+ )
+ },
+ ];
+
+ if introduce_new {
+ let new_param_suggestion = match &generics.params {
+ [] => (generics.span, format!("<{}>", suggestion_param_name)),
+ [first, ..] => (
+ first.span.shrink_to_lo(),
+ format!("{}, ", suggestion_param_name),
+ ),
+ };
+
+ suggestions.push(new_param_suggestion);
+ }
+
+ err.multipart_suggestion(
+ "consider introducing a named lifetime parameter",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ err.note(
+ "each elided lifetime in input position becomes a distinct lifetime",
+ );
+ }
+ }
+ }
+ }
+ }
}
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 0878f85..eb1c80e 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
@@ -3,8 +3,6 @@
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_hir::intravisit::Visitor;
-use rustc_hir::FnRetTy;
use rustc_middle::ty;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -48,19 +46,24 @@
return None; // inapplicable
};
+ // 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 {
+ return None;
+ }
+
debug!("try_report_named_anon_conflict: named = {:?}", named);
debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info);
debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
- let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = (
- anon_param_info.param,
- anon_param_info.param_ty,
- anon_param_info.param_ty_span,
- anon_param_info.bound_region,
- anon_param_info.is_first,
- region_info.def_id,
- region_info.is_impl_item,
- );
+ let param = anon_param_info.param;
+ let new_ty = anon_param_info.param_ty;
+ let new_ty_span = anon_param_info.param_ty_span;
+ let br = anon_param_info.bound_region;
+ let is_first = anon_param_info.is_first;
+ let scope_def_id = region_info.def_id;
+ let is_impl_item = region_info.is_impl_item;
+
match br {
ty::BrAnon(_) => {}
_ => {
@@ -75,26 +78,10 @@
return None;
}
- if let Some((_, fndecl)) = find_anon_type(self.tcx(), anon, &br) {
- if self.is_self_anon(is_first, scope_def_id) {
- return None;
- }
-
- if let FnRetTy::Return(ty) = &fndecl.output {
- let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
- v.visit_ty(ty);
-
- debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
- if sub == &ty::ReStatic
- && v.0.into_iter().any(|t| t.span.desugaring_kind().is_none())
- {
- // If the failure is due to a `'static` requirement coming from a `dyn` or
- // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
- // better in `static_impl_trait`.
- debug!("try_report_named_anon_conflict: impl Trait + 'static");
- return None;
- }
- }
+ if find_anon_type(self.tcx(), anon, &br).is_some()
+ && self.is_self_anon(is_first, scope_def_id)
+ {
+ return None;
}
let (error_var, span_label_var) = match param.pat.simple_ident() {
@@ -114,16 +101,12 @@
);
diag.span_label(span, format!("lifetime `{}` required", named));
- // Suggesting `'static` is nearly always incorrect, and can steer users
- // down the wrong path.
- if *named != ty::ReStatic {
- diag.span_suggestion(
- new_ty_span,
- &format!("add explicit lifetime `{}` to {}", named, span_label_var),
- new_ty.to_string(),
- Applicability::Unspecified,
- );
- }
+ diag.span_suggestion(
+ new_ty_span,
+ &format!("add explicit lifetime `{}` to {}", named, span_label_var),
+ new_ty.to_string(),
+ Applicability::Unspecified,
+ );
Some(diag)
}
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 7fba6a8..2aaebed 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
@@ -192,14 +192,16 @@
ObligationCauseCode::MatchImpl(parent, ..) => &parent.code,
_ => &cause.code,
};
- if let ObligationCauseCode::ItemObligation(item_def_id) = *code {
+ if let (ObligationCauseCode::ItemObligation(item_def_id), None) =
+ (code, override_error_code)
+ {
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
// lifetime as above, but called using a fully-qualified path to the method:
// `Foo::qux(bar)`.
let mut v = TraitObjectVisitor(FxHashSet::default());
v.visit_ty(param.param_ty);
if let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+ 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);
@@ -263,9 +265,7 @@
match fn_return.kind {
TyKind::OpaqueDef(item_id, _) => {
let item = tcx.hir().item(item_id);
- let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
- opaque
- } else {
+ let ItemKind::OpaqueTy(opaque) = &item.kind else {
return;
};
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 ea9d0ea..cfa7921 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
@@ -9,10 +9,13 @@
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::print::RegionHighlightMode;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+
use rustc_span::{MultiSpan, Span, Symbol};
+use std::ops::ControlFlow;
+
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
@@ -51,12 +54,16 @@
{
if let SubregionOrigin::CompareImplTypeObligation {
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
} = origin
{
- self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id);
+ self.emit_associated_type_err(
+ span,
+ self.infcx.tcx.item_name(impl_item_def_id),
+ impl_item_def_id,
+ trait_item_def_id,
+ );
return Some(ErrorReported);
}
}
@@ -69,6 +76,47 @@
.tcx()
.sess
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
+
+ // 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>,
+ counter: usize,
+ }
+
+ impl HighlightBuilder<'tcx> {
+ fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+ let mut builder =
+ HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+ 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);
+ self.counter += 1;
+ }
+ r.super_visit_with(self)
+ }
+ }
+
+ let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+ let expected = self
+ .infcx
+ .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
+ .name;
+ let found_highlight = HighlightBuilder::build(self.tcx(), found);
+ let found =
+ self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
@@ -96,15 +144,8 @@
);
}
- if let Some((expected, found)) =
- self.infcx.expected_found_str_ty(ExpectedFound { expected, found })
- {
- // Highlighted the differences when showing the "expected/found" note.
- err.note_expected_found(&"", expected, &"", found);
- } else {
- // This fallback shouldn't be necessary, but let's keep it in just in case.
- err.note(&format!("expected `{}`\n found `{}`", expected, found));
- }
+ err.note(&format!("expected `{}`\n found `{}`", expected, found));
+
err.span_help(
type_param_span,
"the lifetime requirements from the `impl` do not correspond to the requirements in \
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 8dcdd4b..90bc5b3 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
@@ -143,9 +143,8 @@
// 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_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?;
-
- Some(fn_like.asyncness())
+ let fn_kind = node.fn_kind()?;
+ Some(fn_kind.asyncness())
}
// Here, we check for the case where the anonymous region
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 5f99a23..6600c18 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -53,9 +53,6 @@
infer::RelateObjectBound(span) => {
label_or_note(span, "...so that it can be closed over into an object");
}
- infer::CallReturn(span) => {
- label_or_note(span, "...so that return value is valid for the call");
- }
infer::DataBorrowed(ty, span) => {
label_or_note(
span,
@@ -281,23 +278,6 @@
);
err
}
- infer::CallReturn(span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0482,
- "lifetime of return value does not outlive the function call"
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the return value is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
infer::DataBorrowed(ty, span) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -350,30 +330,21 @@
);
err
}
- infer::CompareImplMethodObligation {
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- } => self.report_extra_impl_obligation(
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- ),
- infer::CompareImplTypeObligation {
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- } => self.report_extra_impl_obligation(
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- ),
+ infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => {
+ self.report_extra_impl_obligation(
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ &format!("`{}: {}`", sup, sub),
+ )
+ }
+ infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self
+ .report_extra_impl_obligation(
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ &format!("`{}: {}`", sup, sub),
+ ),
}
}
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 728dc2d..4814b65 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -66,8 +66,6 @@
/// follows. If we know that `r_b: 'static`, then this function
/// will return true, even though we don't know anything that
/// directly relates `r_a` and `r_b`.
- ///
- /// Also available through the `FreeRegionRelations` trait below.
pub fn sub_free_regions(
&self,
tcx: TyCtxt<'tcx>,
@@ -131,27 +129,6 @@
}
}
-/// The NLL region handling code represents free region relations in a
-/// slightly different way; this trait allows functions to be abstract
-/// over which version is in use.
-pub trait FreeRegionRelations<'tcx> {
- /// Tests whether `r_a <= r_b`. Both must be free regions or
- /// `'static`.
- fn sub_free_regions(
- &self,
- tcx: TyCtxt<'tcx>,
- shorter: ty::Region<'tcx>,
- longer: ty::Region<'tcx>,
- ) -> bool;
-}
-
-impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
- fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
- // invoke the "inherent method"
- self.sub_free_regions(tcx, r_a, r_b)
- }
-}
-
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
type Lifted = FreeRegionMap<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
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 869fd22..4c9dcab 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -2,7 +2,6 @@
use crate::infer::region_constraints::Constraint;
use crate::infer::region_constraints::GenericKind;
-use crate::infer::region_constraints::MemberConstraint;
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::VarInfos;
use crate::infer::region_constraints::VerifyBound;
@@ -20,7 +19,6 @@
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
-use rustc_span::Span;
use std::fmt;
/// This function performs lexical region resolution given a complete
@@ -28,13 +26,13 @@
/// iteration to find region values which satisfy all constraints,
/// assuming such values can be found. It returns the final values of
/// all the variables as well as a set of errors that must be reported.
+#[instrument(level = "debug", skip(region_rels, var_infos, data))]
pub fn resolve<'tcx>(
region_rels: &RegionRelations<'_, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
mode: RegionckMode,
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
- debug!("RegionConstraintData: resolve_regions()");
let mut errors = vec![];
let mut resolver = LexicalResolver { region_rels, var_infos, data };
match mode {
@@ -109,11 +107,6 @@
SubregionOrigin<'tcx>, // cause of the constraint
Region<'tcx>, // the placeholder `'b`
),
-
- /// Indicates a failure of a `MemberConstraint`. These arise during
- /// impl trait processing explicitly -- basically, the impl trait's hidden type
- /// included some region that it was not supposed to.
- MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> },
}
struct RegionAndOrigin<'tcx> {
@@ -150,12 +143,7 @@
let graph = self.construct_graph();
self.expand_givens(&graph);
- loop {
- self.expansion(&mut var_data);
- if !self.enforce_member_constraints(&graph, &mut var_data) {
- break;
- }
- }
+ self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
var_data
@@ -233,120 +221,6 @@
}
}
- /// Enforce all member constraints and return true if anything
- /// changed. See `enforce_member_constraint` for more details.
- fn enforce_member_constraints(
- &self,
- graph: &RegionGraph<'tcx>,
- var_values: &mut LexicalRegionResolutions<'tcx>,
- ) -> bool {
- // Note: we don't use the `any` combinator because we don't
- // want to stop at the first constraint that makes a change.
- let mut any_changed = false;
- for member_constraint in &self.data.member_constraints {
- any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values);
- }
- any_changed
- }
-
- /// Enforce a constraint like
- ///
- /// ```
- /// 'r member of ['c...]
- /// ```
- ///
- /// We look for all choice regions from the list `'c...` that:
- ///
- /// (a) are greater than the current value of `'r` (which is a lower bound)
- ///
- /// and
- ///
- /// (b) are compatible with the upper bounds of `'r` that we can
- /// find by traversing the graph.
- ///
- /// From that list, we look for a *minimal* option `'c_min`. If we
- /// find one, then we can enforce that `'r: 'c_min`.
- fn enforce_member_constraint(
- &self,
- graph: &RegionGraph<'tcx>,
- member_constraint: &MemberConstraint<'tcx>,
- var_values: &mut LexicalRegionResolutions<'tcx>,
- ) -> bool {
- debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint);
-
- // The constraint is some inference variable (`vid`) which
- // must be equal to one of the options.
- let member_vid = match member_constraint.member_region {
- ty::ReVar(vid) => *vid,
- _ => return false,
- };
-
- // The current value of `vid` is a lower bound LB -- i.e., we
- // know that `LB <= vid` must be true.
- let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
- VarValue::ErrorValue => return false,
- VarValue::Value(r) => r,
- };
-
- // Find all the "upper bounds" -- that is, each region `b` such that
- // `r0 <= b` must hold.
- let (member_upper_bounds, ..) =
- self.collect_bounding_regions(graph, member_vid, OUTGOING, None);
-
- // Get an iterator over the *available choice* -- that is,
- // each choice region `c` where `lb <= c` and `c <= ub` for all the
- // upper bounds `ub`.
- debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
- let mut options = member_constraint.choice_regions.iter().filter(|option| {
- self.sub_concrete_regions(member_lower_bound, option)
- && member_upper_bounds
- .iter()
- .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
- });
-
- // If there is more than one option, we only make a choice if
- // there is a single *least* choice -- i.e., some available
- // region that is `<=` all the others.
- let mut least_choice: ty::Region<'tcx> = match options.next() {
- Some(&r) => r,
- None => return false,
- };
- debug!("enforce_member_constraint: least_choice={:?}", least_choice);
- for &option in options {
- debug!("enforce_member_constraint: option={:?}", option);
- if !self.sub_concrete_regions(least_choice, option) {
- if self.sub_concrete_regions(option, least_choice) {
- debug!("enforce_member_constraint: new least choice");
- least_choice = option;
- } else {
- debug!("enforce_member_constraint: no least choice");
- return false;
- }
- }
- }
-
- // (#72087) Different `ty::Regions` can be known to be equal, for
- // example, we know that `'a` and `'static` are equal in a function
- // with a parameter of type `&'static &'a ()`.
- //
- // When we have two equal regions like this `expansion` will use
- // `lub_concrete_regions` to pick a canonical representative. The same
- // choice is needed here so that we don't end up in a cycle of
- // `expansion` changing the region one way and the code here changing
- // it back.
- let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
- debug!(
- "enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
- least_choice, lub
- );
- if lub != member_lower_bound {
- *var_values.value_mut(member_vid) = VarValue::Value(least_choice);
- true
- } else {
- false
- }
- }
-
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
let mut changes = Vec::new();
@@ -461,6 +335,7 @@
}
/// True if `a <= b`, but not defined over inference variables.
+ #[instrument(level = "trace", skip(self))]
fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
let tcx = self.tcx();
let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);
@@ -492,6 +367,7 @@
///
/// Neither `a` nor `b` may be an inference variable (hence the
/// 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) => {
@@ -562,13 +438,14 @@
/// After expansion is complete, go and check upper bounds (i.e.,
/// cases where the region cannot grow larger than a fixed point)
/// and check that they are satisfied.
+ #[instrument(skip(self, var_data, errors))]
fn collect_errors(
&self,
var_data: &mut LexicalRegionResolutions<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
for (constraint, origin) in &self.data.constraints {
- debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin);
+ debug!(?constraint, ?origin);
match *constraint {
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
// Expansion will ensure that these constraints hold. Ignore.
@@ -580,7 +457,7 @@
}
debug!(
- "collect_errors: region error at {:?}: \
+ "region error at {:?}: \
cannot verify that {:?} <= {:?}",
origin, sub, sup
);
@@ -606,7 +483,7 @@
// collect them later.
if !self.sub_concrete_regions(a_region, b_region) {
debug!(
- "collect_errors: region error at {:?}: \
+ "region error at {:?}: \
cannot verify that {:?}={:?} <= {:?}",
origin, a_vid, a_region, b_region
);
@@ -616,23 +493,6 @@
}
}
- // Check that all member constraints are satisfied.
- for member_constraint in &self.data.member_constraints {
- let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
- let choice_regions = member_constraint
- .choice_regions
- .iter()
- .map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
- if !choice_regions.clone().any(|choice_region| member_region == choice_region) {
- let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
- errors.push(RegionResolutionError::MemberConstraintFailure {
- span,
- hidden_ty: member_constraint.hidden_ty,
- member_region,
- });
- }
- }
-
for verify in &self.data.verifys {
debug!("collect_errors: verify={:?}", verify);
let sub = var_data.normalize(self.tcx(), verify.region);
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 18836d5..2fd01c2 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -95,9 +95,10 @@
/// This is used so that the region values inferred by HIR region solving are
/// not exposed, and so that we can avoid doing work in HIR typeck that MIR
/// typeck will also do.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Default)]
pub enum RegionckMode {
/// The default mode: report region errors, don't erase regions.
+ #[default]
Solve,
/// Erase the results of region after solving.
Erase {
@@ -108,12 +109,6 @@
},
}
-impl Default for RegionckMode {
- fn default() -> Self {
- RegionckMode::Solve
- }
-}
-
impl RegionckMode {
/// Indicates that the MIR borrowck will repeat these region
/// checks, so we should ignore errors if NLL is (unconditionally)
@@ -417,26 +412,13 @@
/// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
- /// Region in return type of invoked fn must enclose call
- CallReturn(Span),
-
/// Comparing the signature and requirements of an impl method against
/// the containing trait.
- CompareImplMethodObligation {
- span: Span,
- item_name: Symbol,
- impl_item_def_id: DefId,
- trait_item_def_id: DefId,
- },
+ CompareImplMethodObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
/// Comparing the signature and requirements of an impl associated type
/// against the containing trait
- CompareImplTypeObligation {
- span: Span,
- item_name: Symbol,
- impl_item_def_id: DefId,
- trait_item_def_id: DefId,
- },
+ CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
}
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -472,7 +454,7 @@
AddrOfRegion(Span),
/// Regions created as part of an autoref of a method receiver
- Autoref(Span, ty::AssocItem),
+ Autoref(Span),
/// Regions created as part of an automatic coercion
Coercion(Span),
@@ -1255,16 +1237,16 @@
self.tainted_by_errors_flag.set(true)
}
- /// Process the region constraints and report any errors that
+ /// Process the region constraints and return any any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
- pub fn resolve_regions_and_report_errors(
+ pub fn resolve_regions(
&self,
region_context: DefId,
outlives_env: &OutlivesEnvironment<'tcx>,
mode: RegionckMode,
- ) {
+ ) -> Vec<RegionResolutionError<'tcx>> {
let (var_infos, data) = {
let mut inner = self.inner.borrow_mut();
let inner = &mut *inner;
@@ -1290,6 +1272,21 @@
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
assert!(old_value.is_none());
+ errors
+ }
+
+ /// Process the region constraints and report any errors that
+ /// result. After this, no more unification operations should be
+ /// done -- or the compiler will panic -- but it is legal to use
+ /// `resolve_vars_if_possible` as well as `fully_resolve`.
+ pub fn resolve_regions_and_report_errors(
+ &self,
+ region_context: DefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ mode: RegionckMode,
+ ) {
+ let errors = self.resolve_regions(region_context, outlives_env, mode);
+
if !self.is_tainted_by_errors() {
// As a heuristic, just skip reporting region errors
// altogether if other errors have been reported while
@@ -1803,7 +1800,6 @@
ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
- CallReturn(a) => a,
CompareImplMethodObligation { span, .. } => span,
CompareImplTypeObligation { span, .. } => span,
}
@@ -1819,23 +1815,19 @@
}
traits::ObligationCauseCode::CompareImplMethodObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
} => SubregionOrigin::CompareImplMethodObligation {
span: cause.span,
- item_name,
impl_item_def_id,
trait_item_def_id,
},
traits::ObligationCauseCode::CompareImplTypeObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
} => SubregionOrigin::CompareImplTypeObligation {
span: cause.span,
- item_name,
impl_item_def_id,
trait_item_def_id,
},
@@ -1851,7 +1843,7 @@
MiscVariable(a)
| PatternRegion(a)
| AddrOfRegion(a)
- | Autoref(a, _)
+ | Autoref(a)
| Coercion(a)
| EarlyBoundRegion(a, ..)
| LateBoundRegion(a, ..)
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index d0883f2..e2e07f2 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,8 +1,17 @@
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits;
+use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
-use rustc_middle::ty::{OpaqueTypeKey, Ty};
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
+use std::ops::ControlFlow;
+
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
/// Information about the opaque types whose values we
@@ -45,3 +54,584 @@
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
}
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+ /// Replaces all opaque types in `value` with fresh inference variables
+ /// and creates appropriate obligations. For example, given the input:
+ ///
+ /// impl Iterator<Item = impl Debug>
+ ///
+ /// this method would create two type variables, `?0` and `?1`. It would
+ /// return the type `?0` but also the obligations:
+ ///
+ /// ?0: Iterator<Item = ?1>
+ /// ?1: Debug
+ ///
+ /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
+ /// info about the `impl Iterator<..>` type and `?1` to info about
+ /// the `impl Debug` type.
+ ///
+ /// # Parameters
+ ///
+ /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
+ /// is defined
+ /// - `body_id` -- the body-id with which the resulting obligations should
+ /// be associated
+ /// - `param_env` -- the in-scope parameter environment to be used for
+ /// obligations
+ /// - `value` -- the value within which we are instantiating opaque types
+ /// - `value_span` -- the span where the value came from, used in error reporting
+ pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
+ &self,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ value_span: Span,
+ ) -> InferOk<'tcx, T> {
+ debug!(
+ "instantiate_opaque_types(value={:?}, body_id={:?}, \
+ param_env={:?}, value_span={:?})",
+ value, body_id, param_env, value_span,
+ );
+ let mut instantiator =
+ Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
+ let value = instantiator.instantiate_opaque_types_in_map(value);
+ InferOk { value, obligations: instantiator.obligations }
+ }
+
+ /// Given the map `opaque_types` containing the opaque
+ /// `impl Trait` types whose underlying, hidden types are being
+ /// inferred, this method adds constraints to the regions
+ /// appearing in those underlying hidden types to ensure that they
+ /// at least do not refer to random scopes within the current
+ /// function. These constraints are not (quite) sufficient to
+ /// guarantee that the regions are actually legal values; that
+ /// final condition is imposed after region inference is done.
+ ///
+ /// # The Problem
+ ///
+ /// Let's work through an example to explain how it works. Assume
+ /// the current function is as follows:
+ ///
+ /// ```text
+ /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
+ /// ```
+ ///
+ /// Here, we have two `impl Trait` types whose values are being
+ /// inferred (the `impl Bar<'a>` and the `impl
+ /// Bar<'b>`). Conceptually, this is sugar for a setup where we
+ /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
+ /// the return type of `foo`, we *reference* those definitions:
+ ///
+ /// ```text
+ /// type Foo1<'x> = impl Bar<'x>;
+ /// type Foo2<'x> = impl Bar<'x>;
+ /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
+ /// // ^^^^ ^^
+ /// // | |
+ /// // | substs
+ /// // def_id
+ /// ```
+ ///
+ /// As indicating in the comments above, each of those references
+ /// is (in the compiler) basically a substitution (`substs`)
+ /// applied to the type of a suitable `def_id` (which identifies
+ /// `Foo1` or `Foo2`).
+ ///
+ /// Now, at this point in compilation, what we have done is to
+ /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
+ /// fresh inference variables C1 and C2. We wish to use the values
+ /// of these variables to infer the underlying types of `Foo1` and
+ /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
+ /// constraints like:
+ ///
+ /// ```text
+ /// for<'a> (Foo1<'a> = C1)
+ /// for<'b> (Foo1<'b> = C2)
+ /// ```
+ ///
+ /// For these equation to be satisfiable, the types `C1` and `C2`
+ /// can only refer to a limited set of regions. For example, `C1`
+ /// can only refer to `'static` and `'a`, and `C2` can only refer
+ /// to `'static` and `'b`. The job of this function is to impose that
+ /// constraint.
+ ///
+ /// Up to this point, C1 and C2 are basically just random type
+ /// inference variables, and hence they may contain arbitrary
+ /// regions. In fact, it is fairly likely that they do! Consider
+ /// this possible definition of `foo`:
+ ///
+ /// ```text
+ /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
+ /// (&*x, &*y)
+ /// }
+ /// ```
+ ///
+ /// Here, the values for the concrete types of the two impl
+ /// traits will include inference variables:
+ ///
+ /// ```text
+ /// &'0 i32
+ /// &'1 i32
+ /// ```
+ ///
+ /// Ordinarily, the subtyping rules would ensure that these are
+ /// sufficiently large. But since `impl Bar<'a>` isn't a specific
+ /// type per se, we don't get such constraints by default. This
+ /// is where this function comes into play. It adds extra
+ /// constraints to ensure that all the regions which appear in the
+ /// inferred type are regions that could validly appear.
+ ///
+ /// This is actually a bit of a tricky constraint in general. We
+ /// want to say that each variable (e.g., `'0`) can only take on
+ /// values that were supplied as arguments to the opaque type
+ /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
+ /// scope. We don't have a constraint quite of this kind in the current
+ /// region checker.
+ ///
+ /// # The Solution
+ ///
+ /// We generally prefer to make `<=` constraints, since they
+ /// integrate best into the region solver. To do that, we find the
+ /// "minimum" of all the arguments that appear in the substs: that
+ /// is, some region which is less than all the others. In the case
+ /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
+ /// all). Then we apply that as a least bound to the variables
+ /// (e.g., `'a <= '0`).
+ ///
+ /// In some cases, there is no minimum. Consider this example:
+ ///
+ /// ```text
+ /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
+ /// ```
+ ///
+ /// Here we would report a more complex "in constraint", like `'r
+ /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
+ /// the hidden type).
+ ///
+ /// # Constrain regions, not the hidden concrete type
+ ///
+ /// Note that generating constraints on each region `Rc` is *not*
+ /// the same as generating an outlives constraint on `Tc` iself.
+ /// For example, if we had a function like this:
+ ///
+ /// ```rust
+ /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
+ /// (x, y)
+ /// }
+ ///
+ /// // Equivalent to:
+ /// type FooReturn<'a, T> = impl Foo<'a>;
+ /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
+ /// ```
+ ///
+ /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
+ /// is an inference variable). If we generated a constraint that
+ /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
+ /// but this is not necessary, because the opaque type we
+ /// create will be allowed to reference `T`. So we only generate a
+ /// constraint that `'0: 'a`.
+ ///
+ /// # The `free_region_relations` parameter
+ ///
+ /// The `free_region_relations` argument is used to find the
+ /// "minimum" of the regions supplied to a given opaque type.
+ /// It must be a relation that can answer whether `'a <= 'b`,
+ /// where `'a` and `'b` are regions that appear in the "substs"
+ /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
+ ///
+ /// Note that we do not impose the constraints based on the
+ /// generic regions from the `Foo1` definition (e.g., `'x`). This
+ /// is because the constraints we are imposing here is basically
+ /// the concern of the one generating the constraining type C1,
+ /// which is the current function. It also means that we can
+ /// take "implied bounds" into account in some cases:
+ ///
+ /// ```text
+ /// trait SomeTrait<'a, 'b> { }
+ /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
+ /// ```
+ ///
+ /// Here, the fact that `'b: 'a` is known only because of the
+ /// implied bounds from the `&'a &'b u32` parameter, and is not
+ /// "inherent" to the opaque type definition.
+ ///
+ /// # Parameters
+ ///
+ /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
+ /// - `free_region_relations` -- something that can be used to relate
+ /// the free regions (`'a`) that appear in the impl trait.
+ #[instrument(level = "debug", skip(self))]
+ pub fn constrain_opaque_type(
+ &self,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ opaque_defn: &OpaqueTypeDecl<'tcx>,
+ ) {
+ let def_id = opaque_type_key.def_id;
+
+ let tcx = self.tcx;
+
+ let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
+
+ debug!(?concrete_ty);
+
+ let first_own_region = match opaque_defn.origin {
+ hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
+ // We lower
+ //
+ // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+ //
+ // into
+ //
+ // type foo::<'p0..'pn>::Foo<'q0..'qm>
+ // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+ //
+ // For these types we only iterate over `'l0..lm` below.
+ tcx.generics_of(def_id).parent_count
+ }
+ // These opaque type inherit all lifetime parameters from their
+ // parent, so we have to check them all.
+ hir::OpaqueTyOrigin::TyAlias => 0,
+ };
+
+ // For a case like `impl Foo<'a, 'b>`, we would generate a constraint
+ // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
+ // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`).
+ //
+ // `conflict1` and `conflict2` are the two region bounds that we
+ // detected which were unrelated. They are used for diagnostics.
+
+ // Create the set of choice regions: each region in the hidden
+ // type can be equal to any of the region parameters of the
+ // opaque type definition.
+ let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
+ opaque_type_key.substs[first_own_region..]
+ .iter()
+ .filter_map(|arg| match arg.unpack() {
+ GenericArgKind::Lifetime(r) => Some(r),
+ GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
+ })
+ .chain(std::iter::once(self.tcx.lifetimes.re_static))
+ .collect(),
+ );
+
+ concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx: self.tcx,
+ op: |r| {
+ self.member_constraint(
+ opaque_type_key.def_id,
+ opaque_defn.definition_span,
+ concrete_ty,
+ r,
+ &choice_regions,
+ )
+ },
+ });
+ }
+}
+
+// Visitor that requires that (almost) all regions in the type visited outlive
+// `least_region`. We cannot use `push_outlives_components` because regions in
+// closure signatures are not included in their outlives components. We need to
+// ensure all regions outlive the given bound so that we don't end up with,
+// say, `ReVar` appearing in a return type and causing ICEs when other
+// functions end up with region constraints involving regions from other
+// functions.
+//
+// We also cannot use `for_each_free_region` because for closures it includes
+// the regions parameters from the enclosing item.
+//
+// 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>,
+ op: OP,
+}
+
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+where
+ OP: FnMut(ty::Region<'tcx>),
+{
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
+ fn visit_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ t.as_ref().skip_binder().visit_with(self);
+ ControlFlow::CONTINUE
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ // ignore bound regions, keep visiting
+ ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
+ _ => {
+ (self.op)(r);
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+
+ 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) {
+ return ControlFlow::CONTINUE;
+ }
+
+ match ty.kind() {
+ ty::Closure(_, ref substs) => {
+ // Skip lifetime parameters of the enclosing item(s)
+
+ substs.as_closure().tupled_upvars_ty().visit_with(self);
+ substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
+ }
+
+ ty::Generator(_, ref substs, _) => {
+ // Skip lifetime parameters of the enclosing item(s)
+ // Also skip the witness type, because that has no free regions.
+
+ substs.as_generator().tupled_upvars_ty().visit_with(self);
+ substs.as_generator().return_ty().visit_with(self);
+ substs.as_generator().yield_ty().visit_with(self);
+ substs.as_generator().resume_ty().visit_with(self);
+ }
+ _ => {
+ ty.super_visit_with(self);
+ }
+ }
+
+ ControlFlow::CONTINUE
+ }
+}
+
+struct Instantiator<'a, 'tcx> {
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ value_span: Span,
+ obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+impl<'a, 'tcx> Instantiator<'a, 'tcx> {
+ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ let tcx = self.infcx.tcx;
+ value.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| {
+ if ty.references_error() {
+ return tcx.ty_error();
+ } else if let ty::Opaque(def_id, substs) = ty.kind() {
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ 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 def_scope_default = || {
+ let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
+ parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
+ };
+ let (in_definition_scope, origin) =
+ match tcx.hir().expect_item(opaque_hir_id).kind {
+ // Anonymous `impl Trait`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: Some(parent),
+ origin,
+ ..
+ }) => (parent == parent_def_id.to_def_id(), origin),
+ // Named `type Foo = impl Bar;`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: None,
+ origin,
+ ..
+ }) => (
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
+ origin,
+ ),
+ _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+ };
+ if in_definition_scope {
+ let opaque_type_key =
+ OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ }
+
+ debug!(
+ "instantiate_opaque_types_in_map: \
+ encountered opaque outside its definition scope \
+ def_id={:?}",
+ def_id,
+ );
+ }
+ }
+
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn fold_opaque_ty(
+ &mut self,
+ ty: Ty<'tcx>,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ origin: hir::OpaqueTyOrigin,
+ ) -> Ty<'tcx> {
+ let infcx = self.infcx;
+ let tcx = infcx.tcx;
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+ // Use the same type variable if the exact same opaque type appears more
+ // than once in the return type (e.g., if it's passed to a type alias).
+ if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
+ debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
+ return opaque_defn.concrete_ty;
+ }
+
+ let ty_var = infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span: self.value_span,
+ });
+
+ // Ideally, we'd get the span where *this specific `ty` came
+ // from*, but right now we just use the span from the overall
+ // value being folded. In simple cases like `-> impl Foo`,
+ // these are the same span, but not in cases like `-> (impl
+ // Foo, impl Bar)`.
+ let definition_span = self.value_span;
+
+ {
+ let mut infcx = self.infcx.inner.borrow_mut();
+ infcx.opaque_types.insert(
+ OpaqueTypeKey { def_id, substs },
+ OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
+ );
+ infcx.opaque_types_vars.insert(ty_var, ty);
+ }
+
+ debug!("generated new type inference var {:?}", ty_var.kind());
+
+ let item_bounds = tcx.explicit_item_bounds(def_id);
+
+ self.obligations.reserve(item_bounds.len());
+ for (predicate, _) in item_bounds {
+ debug!(?predicate);
+ let predicate = predicate.subst(tcx, substs);
+ debug!(?predicate);
+
+ // 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,
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ });
+ 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.
+ 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);
+
+ // Require that the predicate holds for the concrete type.
+ debug!(?predicate);
+ self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
+ }
+
+ ty_var
+ }
+}
+
+/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
+///
+/// Example:
+/// ```rust
+/// pub mod foo {
+/// pub mod bar {
+/// pub trait Bar { .. }
+///
+/// pub type Baz = impl Bar;
+///
+/// fn f1() -> Baz { .. }
+/// }
+///
+/// fn f2() -> bar::Baz { .. }
+/// }
+/// ```
+///
+/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
+/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
+/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
+fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
+ let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ // Named opaque types can be defined by any siblings or children of siblings.
+ 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);
+ }
+ // Syntactically, we are allowed to define the concrete type if:
+ let res = hir_id == scope;
+ trace!(
+ "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
+ tcx.hir().find(hir_id),
+ tcx.hir().get(opaque_hir_id),
+ res
+ );
+ res
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 9e04773..3947282 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -99,7 +99,7 @@
/// function. We can then add implied bounds and the like from the
/// closure arguments into the environment -- these should only
/// apply in the closure body, so once we exit, we invoke
- /// `pop_snapshot_post_closure` to remove them.
+ /// `pop_snapshot_post_typeck_child` to remove them.
///
/// Example:
///
@@ -129,12 +129,12 @@
/// seems like it'd be readily fixed if we wanted. There are
/// similar leaks around givens that seem equally suspicious, to
/// be honest. --nmatsakis
- pub fn push_snapshot_pre_closure(&self) -> usize {
+ pub fn push_snapshot_pre_typeck_child(&self) -> usize {
self.region_bound_pairs_accum.len()
}
- /// See `push_snapshot_pre_closure`.
- pub fn pop_snapshot_post_closure(&mut self, len: usize) {
+ /// See `push_snapshot_pre_typeck_child`.
+ pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
self.region_bound_pairs_accum.truncate(len);
}
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index a4cfadd..e4b407e 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -15,8 +15,10 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
+#![feature(derive_default_enum)]
#![feature(extend_one)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(in_band_lifetimes)]
#![feature(control_flow_enum)]
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index dce4a87..152a395 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -46,30 +46,25 @@
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_all_or_error(infcx)
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
+ -> Vec<FulfillmentError<'tcx>>;
// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
fn select_with_constness_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)
}
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 9dbfa3a..c1f302e 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -6,7 +6,6 @@
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::Symbol;
use rustc_span::{MultiSpan, Span};
use std::fmt;
use std::iter;
@@ -15,8 +14,7 @@
pub fn report_extra_impl_obligation(
&self,
error_span: Span,
- item_name: Symbol,
- _impl_item_def_id: DefId,
+ impl_item_def_id: DefId,
trait_item_def_id: DefId,
requirement: &dyn fmt::Display,
) -> DiagnosticBuilder<'tcx> {
@@ -27,6 +25,7 @@
if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
let span = self.tcx.sess.source_map().guess_head_span(trait_item_span);
+ let item_name = self.tcx.item_name(impl_item_def_id);
err.span_label(span, format!("definition of `{}` from trait", item_name));
}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index e1d6982..e8622b3 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -10,7 +10,7 @@
use rustc_hir as hir;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, Ty};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_span::Span;
pub use self::FulfillmentErrorCode::*;
@@ -55,6 +55,20 @@
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
+impl PredicateObligation<'tcx> {
+ /// Flips the polarity of the inner 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<PredicateObligation<'tcx>> {
+ Some(PredicateObligation {
+ cause: self.cause.clone(),
+ param_env: self.param_env,
+ predicate: self.predicate.flip_polarity(tcx)?,
+ recursion_depth: self.recursion_depth,
+ })
+ }
+}
+
// `PredicateObligation` 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!(PredicateObligation<'_>, 32);
@@ -129,6 +143,10 @@
}
impl<'tcx> TraitObligation<'tcx> {
+ pub fn polarity(&self) -> ty::ImplPolarity {
+ self.predicate.skip_binder().polarity
+ }
+
pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
self.predicate.map_bound(|p| p.self_ty())
}
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index c4a2ece..b48ca3b 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -70,6 +70,7 @@
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.predicate.visit_with(visitor)
+ self.predicate.visit_with(visitor)?;
+ self.param_env.visit_with(visitor)
}
}
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index c839f82..92f74af 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -5,6 +5,7 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
use rustc_span::symbol::Ident;
+use rustc_span::Span;
pub fn anonymize_predicate<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -97,6 +98,22 @@
elaborate_obligations(tcx, obligations)
}
+pub fn elaborate_predicates_with_span<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ predicates: impl Iterator<Item = (ty::Predicate<'tcx>, Span)>,
+) -> Elaborator<'tcx> {
+ let obligations = predicates
+ .map(|(predicate, span)| {
+ predicate_obligation(
+ predicate,
+ ty::ParamEnv::empty(),
+ ObligationCause::dummy_with_span(span),
+ )
+ })
+ .collect();
+ elaborate_obligations(tcx, obligations)
+}
+
pub fn elaborate_obligations<'tcx>(
tcx: TyCtxt<'tcx>,
mut obligations: Vec<PredicateObligation<'tcx>>,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 0861bd2..2904b3f 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -36,9 +36,10 @@
pub(crate) input_path: Option<PathBuf>,
pub(crate) output_dir: Option<PathBuf>,
pub(crate) output_file: Option<PathBuf>,
+ pub(crate) temps_dir: Option<PathBuf>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
pub(crate) override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+ Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
}
impl Compiler {
@@ -57,6 +58,9 @@
pub fn output_file(&self) -> &Option<PathBuf> {
&self.output_file
}
+ pub fn temps_dir(&self) -> &Option<PathBuf> {
+ &self.temps_dir
+ }
pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
&self.register_lints
}
@@ -65,7 +69,14 @@
sess: &Session,
attrs: &[ast::Attribute],
) -> OutputFilenames {
- util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess)
+ util::build_output_filenames(
+ &self.input,
+ &self.output_dir,
+ &self.output_file,
+ &self.temps_dir,
+ attrs,
+ sess,
+ )
}
}
@@ -75,7 +86,10 @@
let cfg = cfgspecs
.into_iter()
.map(|s| {
- let sess = ParseSess::with_silent_emitter();
+ let sess = ParseSess::with_silent_emitter(Some(format!(
+ "this error occurred on the command line: `--cfg={}`",
+ s
+ )));
let filename = FileName::cfg_spec_source_code(&s);
let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
@@ -152,7 +166,7 @@
///
/// The second parameter is local providers and the third parameter is external providers.
pub override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+ Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
/// This is a callback from the driver that is called to create a codegen backend.
pub make_codegen_backend:
@@ -183,6 +197,8 @@
);
}
+ let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+
let compiler = Compiler {
sess,
codegen_backend,
@@ -190,6 +206,7 @@
input_path: config.input_path,
output_dir: config.output_dir,
output_file: config.output_file,
+ temps_dir,
register_lints: config.register_lints,
override_queries: config.override_queries,
};
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index bcfa0ef..d3917df 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -19,7 +19,7 @@
use rustc_metadata::{encode_metadata, EncodedMetadata};
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
@@ -35,7 +35,7 @@
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::FileName;
+use rustc_span::{FileName, MultiSpan};
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
use tempfile::Builder as TempFileBuilder;
@@ -47,7 +47,7 @@
use std::io::{self, BufWriter, Write};
use std::lazy::SyncLazy;
use std::marker::PhantomPinned;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::rc::Rc;
use std::{env, fs, iter};
@@ -450,6 +450,19 @@
});
}
+ // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
+ sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| {
+ let mut identifiers: Vec<_> = identifiers.drain().collect();
+ identifiers.sort_by_key(|&(key, _)| key);
+ for (ident, mut spans) in identifiers.into_iter() {
+ spans.sort();
+ sess.diagnostic().span_err(
+ MultiSpan::from(spans),
+ &format!("identifiers cannot contain emoji: `{}`", ident),
+ );
+ }
+ });
+
Ok(krate)
}
@@ -536,7 +549,7 @@
None
}
-fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool {
+fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
let input_path = input_path.canonicalize().ok();
if input_path.is_none() {
return false;
@@ -552,7 +565,7 @@
check_output(output_paths, check)
}
-fn escape_dep_filename(filename: &String) -> String {
+fn escape_dep_filename(filename: &str) -> String {
// Apparently clang and gcc *only* escape spaces:
// https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
filename.replace(" ", "\\ ")
@@ -692,6 +705,7 @@
&compiler.input,
&compiler.output_dir,
&compiler.output_file,
+ &compiler.temps_dir,
&krate.attrs,
sess,
);
@@ -722,6 +736,13 @@
}
}
+ if let Some(ref dir) = compiler.temps_dir {
+ if fs::create_dir_all(dir).is_err() {
+ sess.err("failed to find or create the directory specified by `--temps-dir`");
+ return Err(ErrorReported);
+ }
+ }
+
write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
@@ -764,8 +785,8 @@
*providers
});
-pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
- let mut extern_providers = *DEFAULT_QUERY_PROVIDERS;
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| {
+ let mut extern_providers = ExternProviders::default();
rustc_metadata::provide_extern(&mut extern_providers);
rustc_codegen_ssa::provide_extern(&mut extern_providers);
extern_providers
@@ -816,7 +837,6 @@
codegen_backend.provide(&mut local_providers);
let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS;
- codegen_backend.provide(&mut extern_providers);
codegen_backend.provide_extern(&mut extern_providers);
if let Some(callback) = compiler.override_queries {
@@ -838,6 +858,7 @@
dep_graph,
queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
queries.as_dyn(),
+ rustc_query_impl::query_callbacks(arena),
crate_name,
outputs,
)
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 844e5ab..6147311 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -5,7 +5,9 @@
use rustc_session::config::InstrumentCoverage;
use rustc_session::config::Strip;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
-use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
+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,
@@ -18,7 +20,9 @@
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel};
+use rustc_target::spec::{
+ RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
+};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
@@ -549,6 +553,7 @@
untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")]));
untracked!(rpath, true);
untracked!(save_temps, true);
+ untracked!(strip, Strip::Debuginfo);
macro_rules! tracked {
($name: ident, $non_default_value: expr) => {
@@ -633,6 +638,7 @@
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
// This list is in alphabetical order.
+ untracked!(assert_incr_state, Some(String::from("loaded")));
untracked!(ast_json, true);
untracked!(ast_json_noexpand, true);
untracked!(borrowck, String::from("other"));
@@ -682,7 +688,7 @@
untracked!(self_profile_events, Some(vec![String::new()]));
untracked!(span_debug, true);
untracked!(span_free_formats, true);
- untracked!(strip, Strip::Debuginfo);
+ untracked!(temps_dir, Some(String::from("abc")));
untracked!(terminal_width, Some(80));
untracked!(threads, 99);
untracked!(time, true);
@@ -709,8 +715,8 @@
// This list is in alphabetical order.
tracked!(allow_features, Some(vec![String::from("lang_items")]));
tracked!(always_encode_mir, true);
- tracked!(assume_incomplete_release, true);
tracked!(asm_comments, true);
+ tracked!(assume_incomplete_release, true);
tracked!(binary_dep_depinfo, true);
tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
@@ -720,19 +726,19 @@
tracked!(dep_info_omit_d_target, true);
tracked!(dual_proc_macros, true);
tracked!(fewer_names, Some(true));
- tracked!(force_overflow_checks, Some(true));
tracked!(force_unstable_if_unmarked, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(function_sections, Some(false));
tracked!(human_readable_cgu_names, true);
tracked!(inline_in_all_cgus, Some(true));
tracked!(inline_mir, Some(true));
- tracked!(inline_mir_threshold, Some(123));
tracked!(inline_mir_hint_threshold, Some(123));
+ tracked!(inline_mir_threshold, Some(123));
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
tracked!(instrument_mcount, true);
tracked!(link_only, true);
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
+ tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
tracked!(mir_opt_level, Some(4));
@@ -741,11 +747,13 @@
tracked!(new_llvm_pass_manager, Some(true));
tracked!(no_generate_arange_section, true);
tracked!(no_link, true);
+ tracked!(no_unique_section_names, true);
tracked!(no_profiler_runtime, true);
tracked!(osx_rpath_install_name, true);
tracked!(panic_abort_tests, true);
tracked!(panic_in_drop, PanicStrategy::Abort);
tracked!(partially_uninit_const_threshold, Some(123));
+ tracked!(pick_stable_methods_before_any_unstable, false);
tracked!(plt, Some(true));
tracked!(polonius, true);
tracked!(precise_enum_drop_elaboration, false);
@@ -757,7 +765,6 @@
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
- tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
tracked!(report_delayed_bugs, true);
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_memory_track_origins, 2);
@@ -765,15 +772,17 @@
tracked!(saturating_float_casts, Some(true));
tracked!(share_generics, Some(true));
tracked!(show_span, Some(String::from("abc")));
+ tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
+ tracked!(stack_protector, StackProtector::All);
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, true);
- tracked!(tune_cpu, Some(String::from("abc")));
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
tracked!(trap_unreachable, Some(false));
tracked!(treat_err_as_bug, NonZeroUsize::new(1));
+ tracked!(tune_cpu, Some(String::from("abc")));
tracked!(unleash_the_miri_inside_of_you, true);
tracked!(use_ctors_section, Some(true));
tracked!(verify_llvm_ir, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index cffb087..04e183a 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -604,6 +604,7 @@
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
+ temps_dir: &Option<PathBuf>,
attrs: &[ast::Attribute],
sess: &Session,
) -> OutputFilenames {
@@ -626,6 +627,7 @@
dirpath,
stem,
None,
+ temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),
sess.opts.output_types.clone(),
)
@@ -654,6 +656,7 @@
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
ofile,
+ temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),
sess.opts.output_types.clone(),
)
@@ -776,7 +779,7 @@
fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
let is_const = match i {
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
- ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
+ ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_visit_item_kind(i, s))
@@ -785,7 +788,7 @@
fn flat_map_trait_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let is_const = match i.kind {
ast::AssocItemKind::Const(..) => true,
- ast::AssocItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
+ ast::AssocItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index 60c146f..35af110 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -17,6 +17,7 @@
# Note that this crate purposefully does not depend on other rustc crates
[dependencies]
unicode-xid = "0.2.0"
+unic-emoji-char = "0.9.0"
[dev-dependencies]
expect-test = "1.0"
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b64a891c..44b002f 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -64,6 +64,8 @@
/// "ident" or "continue"
/// At this step keywords are also considered identifiers.
Ident,
+ /// Like the above, but containing invalid unicode codepoints.
+ InvalidIdent,
/// "r#ident"
RawIdent,
/// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the
@@ -411,6 +413,10 @@
let kind = Str { terminated };
Literal { kind, suffix_start }
}
+ // Identifier starting with an emoji. Only lexed for graceful error recovery.
+ c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
+ self.fake_ident_or_unknown_prefix()
+ }
_ => Unknown,
};
Token::new(token_kind, self.len_consumed())
@@ -492,10 +498,28 @@
// we see a prefix here, it is definitely an unknown prefix.
match self.first() {
'#' | '"' | '\'' => UnknownPrefix,
+ c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
+ self.fake_ident_or_unknown_prefix()
+ }
_ => Ident,
}
}
+ fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind {
+ // Start is already eaten, eat the rest of identifier.
+ self.eat_while(|c| {
+ unicode_xid::UnicodeXID::is_xid_continue(c)
+ || (!c.is_ascii() && unic_emoji_char::is_emoji(c))
+ || c == '\u{200d}'
+ });
+ // Known prefixes must have been handled earlier. So if
+ // we see a prefix here, it is definitely an unknown prefix.
+ match self.first() {
+ '#' | '"' | '\'' => UnknownPrefix,
+ _ => InvalidIdent,
+ }
+ }
+
fn number(&mut self, first_digit: char) -> LiteralKind {
debug_assert!('0' <= self.prev() && self.prev() <= '9');
let mut base = Base::Decimal;
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index 804dc65..d789237 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -329,7 +329,7 @@
callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
}
let tail = &tail[first_non_space..];
- if let Some(c) = tail.chars().next() {
+ if let Some(c) = tail.chars().nth(0) {
// For error reporting, we would like the span to contain the character that was not
// skipped. The +1 is necessary to account for the leading \ that started the escape.
let end = start + first_non_space + c.len_utf8() + 1;
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index d147148..d8883b0 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -134,9 +134,8 @@
Applicability::MachineApplicable,
);
if self.for_expr_span == expr.span {
- let expr_span = expr.span.ctxt().outer_expn_data().call_site;
diag.span_suggestion(
- receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
+ receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
"or remove `.into_iter()` to iterate by value",
String::new(),
Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 57c1c8f..f2e4e70 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -32,8 +32,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
-use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
-use rustc_feature::{GateIssue, Stability};
+use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
@@ -369,12 +368,12 @@
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind {
- ast::ItemKind::Trait(box ast::TraitKind(_, ast::Unsafe::Yes(_), ..)) => self
+ ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| {
lint.build("declaration of an `unsafe` trait").emit()
}),
- ast::ItemKind::Impl(box ast::ImplKind { unsafety: ast::Unsafe::Yes(_), .. }) => self
+ ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| {
lint.build("implementation of an `unsafe` trait").emit()
}),
@@ -657,6 +656,24 @@
return;
}
+ // 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 impl_ty = cx.tcx.type_of(parent);
+ let outerdef = match impl_ty.kind() {
+ ty::Adt(def, _) => Some(def.did),
+ ty::Foreign(def_id) => Some(*def_id),
+ _ => None,
+ };
+ let is_hidden = match outerdef {
+ Some(id) => cx.tcx.is_doc_hidden(id),
+ None => false,
+ };
+ if is_hidden {
+ return;
+ }
+ }
+
let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc);
}
@@ -903,7 +920,7 @@
// This is a hard error in future editions; avoid linting and erroring
return;
}
- if let ast::AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) = it.kind {
+ if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
@@ -941,7 +958,7 @@
pub struct DeprecatedAttr {
// This is not free to compute, so we want to keep it around, rather than
// compute it for every attribute.
- depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>,
+ depr_attrs: Vec<&'static BuiltinAttribute>,
}
impl_lint_pass!(DeprecatedAttr => []);
@@ -972,14 +989,14 @@
impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
- for &&(n, _, _, ref g) in &self.depr_attrs {
- if attr.ident().map(|ident| ident.name) == Some(n) {
+ for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
+ if attr.ident().map(|ident| ident.name) == Some(*name) {
if let &AttributeGate::Gated(
Stability::Deprecated(link, suggestion),
name,
reason,
_,
- ) = g
+ ) = gate
{
let msg =
format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link);
@@ -3112,18 +3129,13 @@
false
}
- if let rustc_hir::ExprKind::Unary(ref un_op, ref expr_deref) = expr.kind {
- if let rustc_hir::UnOp::Deref = un_op {
- if is_null_ptr(cx, expr_deref) {
- cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
- let mut err = lint.build("dereferencing a null pointer");
- err.span_label(
- expr.span,
- "this code causes undefined behavior when executed",
- );
- err.emit();
- });
- }
+ if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
+ if is_null_ptr(cx, expr_deref) {
+ cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
+ let mut err = lint.build("dereferencing a null pointer");
+ err.span_label(expr.span, "this code causes undefined behavior when executed");
+ err.emit();
+ });
}
}
}
@@ -3178,7 +3190,7 @@
let snippet = template_snippet.as_str();
if let Some(pos) = snippet.find(needle) {
let end = pos
- + &snippet[pos..]
+ + snippet[pos..]
.find(|c| c == ':')
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 6fd0a5b..4c936de 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -16,9 +16,9 @@
use self::TargetLint::*;
-use crate::hidden_unicode_codepoints::UNICODE_TEXT_FLOW_CHARS;
use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
+use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
@@ -602,7 +602,7 @@
let spans: Vec<_> = content
.char_indices()
.filter_map(|(i, c)| {
- UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| {
+ TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
let lo = span.lo() + BytePos(2 + i as u32);
(c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
})
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index 1bcdcb8..fde84be 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -1,4 +1,5 @@
use crate::{EarlyContext, EarlyLintPass, LintContext};
+use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
use rustc_ast as ast;
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_span::{BytePos, Span, Symbol};
@@ -37,11 +38,6 @@
declare_lint_pass!(HiddenUnicodeCodepoints => [TEXT_DIRECTION_CODEPOINT_IN_LITERAL]);
-crate const UNICODE_TEXT_FLOW_CHARS: &[char] = &[
- '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}',
- '\u{2069}',
-];
-
impl HiddenUnicodeCodepoints {
fn lint_text_direction_codepoint(
&self,
@@ -57,7 +53,7 @@
.as_str()
.char_indices()
.filter_map(|(i, c)| {
- UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| {
+ TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
let lo = span.lo() + BytePos(i as u32 + padding);
(c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
})
@@ -131,7 +127,7 @@
impl EarlyLintPass for HiddenUnicodeCodepoints {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if let ast::AttrKind::DocComment(_, comment) = attr.kind {
- if comment.as_str().contains(UNICODE_TEXT_FLOW_CHARS) {
+ if contains_text_flow_control_chars(&comment.as_str()) {
self.lint_text_direction_codepoint(cx, comment, attr.span, 0, false, "doc comment");
}
}
@@ -142,7 +138,7 @@
let (text, span, padding) = match &expr.kind {
ast::ExprKind::Lit(ast::Lit { token, kind, span }) => {
let text = token.symbol;
- if !text.as_str().contains(UNICODE_TEXT_FLOW_CHARS) {
+ if !contains_text_flow_control_chars(&text.as_str()) {
return;
}
let padding = match kind {
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 50a0d21..c64a67b 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -101,33 +101,31 @@
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
match &ty.kind {
- TyKind::Path(qpath) => {
- if let QPath::Resolved(_, path) = qpath {
- if let Some(last) = path.segments.iter().last() {
- if lint_ty_kind_usage(cx, last) {
- cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
- lint.build("usage of `ty::TyKind`")
- .help("try using `Ty` instead")
- .emit();
- })
- } else {
- if ty.span.from_expansion() {
- return;
- }
- if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
- if path.segments.len() > 1 {
- cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
- lint.build(&format!("usage of qualified `ty::{}`", t))
- .span_suggestion(
- path.span,
- "try using it unqualified",
- t,
- // The import probably needs to be changed
- Applicability::MaybeIncorrect,
- )
- .emit();
- })
- }
+ TyKind::Path(QPath::Resolved(_, path)) => {
+ if let Some(last) = path.segments.iter().last() {
+ if lint_ty_kind_usage(cx, last) {
+ cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+ lint.build("usage of `ty::TyKind`")
+ .help("try using `Ty` instead")
+ .emit();
+ })
+ } else {
+ if ty.span.from_expansion() {
+ return;
+ }
+ if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
+ if path.segments.len() > 1 {
+ cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
+ lint.build(&format!("usage of qualified `ty::{}`", t))
+ .span_suggestion(
+ path.span,
+ "try using it unqualified",
+ t,
+ // The import probably needs to be changed
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ })
}
}
}
@@ -169,37 +167,30 @@
}
fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
- if let TyKind::Path(qpath) = &ty.kind {
- if let QPath::Resolved(_, path) = qpath {
- match path.res {
- Res::Def(_, def_id) => {
- if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
- {
- return Some(format!(
- "{}{}",
- name,
- gen_args(path.segments.last().unwrap())
- ));
- }
+ if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
+ match path.res {
+ Res::Def(_, def_id) => {
+ if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
+ return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
}
- // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
- Res::SelfTy(None, 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)
- {
- // NOTE: This path is currently unreachable as `Ty<'tcx>` is
- // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
- // is not actually allowed.
- //
- // I(@lcnr) still kept this branch in so we don't miss this
- // if we ever change it in the future.
- return Some(format!("{}<{}>", name, substs[0]));
- }
- }
- }
- _ => (),
}
+ // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
+ Res::SelfTy(None, 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)
+ {
+ // NOTE: This path is currently unreachable as `Ty<'tcx>` is
+ // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
+ // is not actually allowed.
+ //
+ // I(@lcnr) still kept this branch in so we don't miss this
+ // if we ever change it in the future.
+ return Some(format!("{}<{}>", name, substs[0]));
+ }
+ }
+ }
+ _ => (),
}
}
@@ -238,8 +229,7 @@
impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
- if let ast::ItemKind::Impl(box ast::ImplKind { of_trait: Some(lint_pass), .. }) = &item.kind
- {
+ if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind {
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index f6514dd..507b442 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -30,7 +30,7 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_order_by)]
#![feature(iter_zip)]
#![feature(never_type)]
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 48b955e..da1edcf 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -670,7 +670,7 @@
///
/// ### Explanation
///
- /// The parenthesis are not needed, and should be removed. This is the
+ /// The parentheses are not needed, and should be removed. This is the
/// preferred style for writing these expressions.
pub(super) UNUSED_PARENS,
Warn,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 8f4f54d..c1a53c3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1959,7 +1959,7 @@
/// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
- Warn,
+ Deny,
"detects proc macro derives using inaccessible names from parent modules",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
@@ -3256,7 +3256,7 @@
/// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_BACK_COMPAT,
- Warn,
+ Deny,
"detects usage of old versions of certain proc-macro crates",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 36a6d2c..943ce58 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -288,7 +288,7 @@
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
- println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
+ println!("cargo:rustc-link-lib=static:-bundle={}", stdcppname);
} else {
println!("cargo:rustc-link-lib=static={}", stdcppname);
}
@@ -302,6 +302,6 @@
// Libstdc++ depends on pthread which Rust doesn't link on MinGW
// since nothing else requires it.
if target.contains("windows-gnu") {
- println!("cargo:rustc-link-lib=static-nobundle=pthread");
+ println!("cargo:rustc-link-lib=static:-bundle=pthread");
}
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 35cca04..8cd2bd1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -98,10 +98,7 @@
extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
RustStringRef Str) {
-#if LLVM_VERSION_GE(11, 0)
WriteSectionNameToString(M, IPSK_covfun, Str);
-// else do nothing; the `Version` check will abort codegen on the Rust side
-#endif
}
extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
@@ -111,9 +108,5 @@
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
-#if LLVM_VERSION_GE(11, 0)
return coverage::CovMapVersion::Version4;
-#else
- return coverage::CovMapVersion::Version3;
-#endif
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 0b1b68d..e2ce7da 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -18,7 +18,6 @@
#include "llvm/Support/Host.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
@@ -80,6 +79,9 @@
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
WillReturn = 29,
+ StackProtectReq = 30,
+ StackProtectStrong = 31,
+ StackProtect = 32,
};
typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 87f423f..4f77db8 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -21,6 +21,11 @@
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
+#if LLVM_VERSION_LT(14, 0)
+#include "llvm/Support/TargetRegistry.h"
+#else
+#include "llvm/MC/TargetRegistry.h"
+#endif
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
@@ -49,10 +54,6 @@
DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
-#if LLVM_VERSION_LT(11, 0)
-DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
- LLVMPassManagerBuilderRef)
-#endif
extern "C" void LLVMInitializePasses() {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
@@ -74,6 +75,10 @@
/* ProcName */ "rustc");
}
+extern "C" void LLVMTimeTraceProfilerFinishThread() {
+ timeTraceProfilerFinishThread();
+}
+
extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) {
StringRef FN(FileName);
std::error_code EC;
@@ -461,6 +466,7 @@
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
bool FunctionSections,
bool DataSections,
+ bool UniqueSectionNames,
bool TrapUnreachable,
bool Singlethread,
bool AsmComments,
@@ -490,6 +496,7 @@
}
Options.DataSections = DataSections;
Options.FunctionSections = FunctionSections;
+ Options.UniqueSectionNames = UniqueSectionNames;
Options.MCOptions.AsmVerbose = AsmComments;
Options.MCOptions.PreserveAsmComments = AsmComments;
Options.MCOptions.ABIName = ABIStr;
@@ -680,7 +687,6 @@
PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
-#if LLVM_VERSION_GE(12, 0)
PIC.registerBeforeNonSkippedPassCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
std::string PassName = Pass.str();
@@ -698,25 +704,6 @@
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) {
AfterPassCallback(LlvmSelfProfiler);
});
-#else
- PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback](
- StringRef Pass, llvm::Any Ir) {
- std::string PassName = Pass.str();
- std::string IrName = LLVMRustwrappedIrGetName(Ir);
- BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
- return true;
- });
-
- PIC.registerAfterPassCallback(
- [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
- AfterPassCallback(LlvmSelfProfiler);
- });
-
- PIC.registerAfterPassInvalidatedCallback(
- [LlvmSelfProfiler, AfterPassCallback](StringRef Pass) {
- AfterPassCallback(LlvmSelfProfiler);
- });
-#endif
PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
@@ -777,22 +764,13 @@
PTO.LoopInterleaving = UnrollLoops;
PTO.LoopVectorization = LoopVectorize;
PTO.SLPVectorization = SLPVectorize;
-#if LLVM_VERSION_GE(12, 0)
PTO.MergeFunctions = MergeFunctions;
-#else
- // MergeFunctions is not supported by NewPM in older LLVM versions.
- (void) MergeFunctions;
-#endif
// FIXME: We may want to expose this as an option.
bool DebugPassManager = false;
PassInstrumentationCallbacks PIC;
-#if LLVM_VERSION_GE(12, 0)
StandardInstrumentations SI(DebugPassManager);
-#else
- StandardInstrumentations SI;
-#endif
SI.registerCallbacks(PIC);
if (LlvmSelfProfiler){
@@ -816,18 +794,14 @@
PGOOptions::NoCSAction, DebugInfoForProfiling);
}
-#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0)
- PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
-#else
- PassBuilder PB(TM, PTO, PGOOpt, &PIC);
-#endif
-
#if LLVM_VERSION_GE(13, 0)
+ PassBuilder PB(TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
#else
+ PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM(DebugPassManager);
FunctionAnalysisManager FAM(DebugPassManager);
CGSCCAnalysisManager CGAM(DebugPassManager);
@@ -852,13 +826,8 @@
// PassBuilder does not create a pipeline.
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
PipelineStartEPCallbacks;
-#if LLVM_VERSION_GE(11, 0)
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
OptimizerLastEPCallbacks;
-#else
- std::vector<std::function<void(FunctionPassManager &, OptimizationLevel)>>
- OptimizerLastEPCallbacks;
-#endif
if (VerifyIR) {
PipelineStartEPCallbacks.push_back(
@@ -891,7 +860,6 @@
SanitizerOptions->SanitizeMemoryTrackOrigins,
SanitizerOptions->SanitizeMemoryRecover,
/*CompileKernel=*/false);
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[Options](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
@@ -902,22 +870,9 @@
MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [Options](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(MemorySanitizerPass(Options));
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [Options](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(MemorySanitizerPass(Options));
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeThread) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
@@ -928,63 +883,31 @@
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(ThreadSanitizerPass());
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(ThreadSanitizerPass());
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeAddress) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
+#if LLVM_VERSION_GE(14, 0)
+ AddressSanitizerOptions opts = AddressSanitizerOptions{
+ /*CompileKernel=*/false,
+ SanitizerOptions->SanitizeAddressRecover,
+ /*UseAfterScope=*/true,
+ AsanDetectStackUseAfterReturnMode::Runtime,
+ };
+ MPM.addPass(ModuleAddressSanitizerPass(opts));
+#else
MPM.addPass(ModuleAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
-#if LLVM_VERSION_GE(14, 0)
- AddressSanitizerOptions opts(/*CompileKernel=*/false,
- SanitizerOptions->SanitizeAddressRecover,
- /*UseAfterScope=*/true,
- AsanDetectStackUseAfterReturnMode::Runtime);
- MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts)));
-#else
MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true)));
#endif
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [&](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [SanitizerOptions](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(AddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
- /*UseAfterScope=*/true));
- }
- );
- PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(ModuleAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeHWAddress) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
@@ -998,14 +921,6 @@
#endif
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(HWAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
- }
- );
-#endif
}
}
@@ -1020,7 +935,6 @@
// At the same time, the LTO pipelines do support O0 and using them is required.
bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
-#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
for (const auto &C : OptimizerLastEPCallbacks)
@@ -1028,40 +942,9 @@
// Pass false as we manually schedule ThinLTOBufferPasses below.
MPM = PB.buildO0DefaultPipeline(OptLevel, /* PreLinkLTO */ false);
-#else
- for (const auto &C : PipelineStartEPCallbacks)
- C(MPM, OptLevel);
-
-# if LLVM_VERSION_GE(11, 0)
- for (const auto &C : OptimizerLastEPCallbacks)
- C(MPM, OptLevel);
-# else
- if (!OptimizerLastEPCallbacks.empty()) {
- FunctionPassManager FPM(DebugPassManager);
- for (const auto &C : OptimizerLastEPCallbacks)
- C(FPM, OptLevel);
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-# endif
-
- MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
-
- if (PGOOpt) {
- PB.addPGOInstrPassesForO0(
- MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr,
- /*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile);
- }
-#endif
} else {
-#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
-#else
- for (const auto &C : PipelineStartEPCallbacks)
- PB.registerPipelineStartEPCallback([C, OptLevel](ModulePassManager &MPM) {
- C(MPM, OptLevel);
- });
-#endif
if (OptStage != LLVMRustOptStage::PreLinkThinLTO) {
for (const auto &C : OptimizerLastEPCallbacks)
PB.registerOptimizerLastEPCallback(C);
@@ -1072,7 +955,6 @@
MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
break;
case LLVMRustOptStage::PreLinkThinLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel);
// The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback
// passes may still run afterwards. This means we need to run the buffer passes again.
@@ -1080,44 +962,20 @@
// before the RequiredLTOPreLinkPasses, in which case we can remove these hacks.
if (OptimizerLastEPCallbacks.empty())
NeedThinLTOBufferPasses = false;
-#else
- MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
-#if LLVM_VERSION_GE(11, 0)
for (const auto &C : OptimizerLastEPCallbacks)
C(MPM, OptLevel);
-#else
- if (!OptimizerLastEPCallbacks.empty()) {
- FunctionPassManager FPM(DebugPassManager);
- for (const auto &C : OptimizerLastEPCallbacks)
- C(FPM, OptLevel);
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-#endif
break;
case LLVMRustOptStage::PreLinkFatLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel);
NeedThinLTOBufferPasses = false;
-#else
- MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
break;
case LLVMRustOptStage::ThinLTO:
// FIXME: Does it make sense to pass the ModuleSummaryIndex?
// It only seems to be needed for C++ specific optimizations.
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr);
-#else
- MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
break;
case LLVMRustOptStage::FatLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr);
-#else
- MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
break;
}
}
@@ -1547,7 +1405,6 @@
// `ProcessThinLTOModule` function. Here they're split up into separate steps
// so rustc can save off the intermediate bytecode between each step.
-#if LLVM_VERSION_GE(11, 0)
static bool
clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
// When linking an ELF shared object, dso_local should be dropped. We
@@ -1558,7 +1415,6 @@
Mod.getPIELevel() == PIELevel::Default;
return ClearDSOLocalOnDeclarations;
}
-#endif
extern "C" bool
LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
@@ -1566,12 +1422,8 @@
Module &Mod = *unwrap(M);
TargetMachine &Target = *unwrap(TM);
-#if LLVM_VERSION_GE(11, 0)
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
-#else
- bool error = renameModuleForThinLTO(Mod, Data->Index);
-#endif
if (error) {
LLVMRustSetLastError("renameModuleForThinLTO failed");
@@ -1640,12 +1492,8 @@
return MOrErr;
};
-#if LLVM_VERSION_GE(11, 0)
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
-#else
- FunctionImporter Importer(Data->Index, Loader);
-#endif
Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
if (!Result) {
LLVMRustSetLastError(toString(Result.takeError()).c_str());
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b7b0524..bb6d42c 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -124,8 +124,18 @@
extern "C" LLVMValueRef
LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
+ Module *Mod = unwrap(M);
StringRef NameRef(Name, NameLen);
- return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
+
+ // We don't use Module::getOrInsertGlobal because that returns a Constant*,
+ // which may either be the real GlobalVariable*, or a constant bitcast of it
+ // if our type doesn't match the original declaration. We always want the
+ // GlobalVariable* so we can access linkage, visibility, etc.
+ GlobalVariable *GV = Mod->getGlobalVariable(NameRef, true);
+ if (!GV)
+ GV = new GlobalVariable(*Mod, unwrap(Ty), false,
+ GlobalValue::ExternalLinkage, nullptr, NameRef);
+ return wrap(GV);
}
extern "C" LLVMValueRef
@@ -203,6 +213,12 @@
return Attribute::SanitizeHWAddress;
case WillReturn:
return Attribute::WillReturn;
+ case StackProtectReq:
+ return Attribute::StackProtectReq;
+ case StackProtectStrong:
+ return Attribute::StackProtectStrong;
+ case StackProtect:
+ return Attribute::StackProtect;
}
report_fatal_error("bad AttributeKind");
}
@@ -263,11 +279,7 @@
extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index,
LLVMTypeRef Ty) {
CallBase *Call = unwrap<CallBase>(Instr);
-#if LLVM_VERSION_GE(12, 0)
Attribute Attr = Attribute::getWithStructRetType(Call->getContext(), unwrap(Ty));
-#else
- Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet);
-#endif
AddAttribute(Call, Index, Attr);
}
@@ -311,11 +323,7 @@
extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
LLVMTypeRef Ty) {
Function *F = unwrap<Function>(Fn);
-#if LLVM_VERSION_GE(12, 0)
Attribute Attr = Attribute::getWithStructRetType(F->getContext(), unwrap(Ty));
-#else
- Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet);
-#endif
AddAttribute(F, Index, Attr);
}
@@ -681,10 +689,8 @@
return DIFile::ChecksumKind::CSK_MD5;
case LLVMRustChecksumKind::SHA1:
return DIFile::ChecksumKind::CSK_SHA1;
-#if (LLVM_VERSION_MAJOR >= 11)
case LLVMRustChecksumKind::SHA256:
return DIFile::ChecksumKind::CSK_SHA256;
-#endif
default:
report_fatal_error("bad ChecksumKind.");
}
@@ -999,14 +1005,9 @@
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
-#if LLVM_VERSION_GE(11, 0)
bool IsDefault = false; // FIXME: should we ever set this true?
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
-#else
- return wrap(Builder->createTemplateTypeParameter(
- unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
-#endif
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
@@ -1031,17 +1032,11 @@
LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
LLVMMetadataRef ScopeRef,
LLVMMetadataRef InlinedAt) {
-#if LLVM_VERSION_GE(12, 0)
MDNode *Scope = unwrapDIPtr<MDNode>(ScopeRef);
DILocation *Loc = DILocation::get(
Scope->getContext(), Line, Column, Scope,
unwrapDIPtr<MDNode>(InlinedAt));
return wrap(Loc);
-#else
- DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(ScopeRef),
- unwrapDIPtr<MDNode>(InlinedAt));
- return wrap(debug_loc.getAsMDNode());
-#endif
}
extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
@@ -1246,27 +1241,18 @@
return LLVMArrayTypeKind;
case Type::PointerTyID:
return LLVMPointerTypeKind;
-#if LLVM_VERSION_GE(11, 0)
case Type::FixedVectorTyID:
return LLVMVectorTypeKind;
-#else
- case Type::VectorTyID:
- return LLVMVectorTypeKind;
-#endif
case Type::X86_MMXTyID:
return LLVMX86_MMXTypeKind;
case Type::TokenTyID:
return LLVMTokenTypeKind;
-#if LLVM_VERSION_GE(11, 0)
case Type::ScalableVectorTyID:
return LLVMScalableVectorTypeKind;
case Type::BFloatTyID:
return LLVMBFloatTypeKind;
-#endif
-#if LLVM_VERSION_GE(12, 0)
case Type::X86_AMXTyID:
return LLVMX86_AMXTypeKind;
-#endif
}
report_fatal_error("Unhandled TypeID.");
}
@@ -1724,23 +1710,15 @@
}
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
Instruction *I = unwrap(B)->CreateFPMinReduce(unwrap(Src));
I->setHasNoNaNs(NoNaN);
return wrap(I);
-#else
- return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Src), NoNaN));
-#endif
}
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
Instruction *I = unwrap(B)->CreateFPMaxReduce(unwrap(Src));
I->setHasNoNaNs(NoNaN);
return wrap(I);
-#else
- return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN));
-#endif
}
extern "C" LLVMValueRef
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 6493bd9..8476c2b 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -1,5 +1,5 @@
#![feature(nll)]
-#![feature(static_nobundle)]
+#![feature(native_link_modifiers)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
// NOTE: This crate only exists to allow linking on mingw targets.
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 00501718..6dbba27 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -36,7 +36,7 @@
Storage(Type),
/// Cache the query to disk if the `Expr` returns true.
- Cache(Option<(IdentOrWild, IdentOrWild)>, Block),
+ Cache(Option<IdentOrWild>, Block),
/// Custom code to load the query from disk.
LoadCached(Ident, Ident, Block),
@@ -55,6 +55,9 @@
/// Always evaluate the query, ignoring its dependencies
EvalAlways(Ident),
+
+ /// Use a separate query provider for local and extern crates
+ SeparateProvideExtern(Ident),
}
impl Parse for QueryModifier {
@@ -87,9 +90,7 @@
let args;
parenthesized!(args in input);
let tcx = args.parse()?;
- args.parse::<Token![,]>()?;
- let value = args.parse()?;
- Some((tcx, value))
+ Some(tcx)
} else {
None
};
@@ -120,6 +121,8 @@
Ok(QueryModifier::Anon(modifier))
} else if modifier == "eval_always" {
Ok(QueryModifier::EvalAlways(modifier))
+ } else if modifier == "separate_provide_extern" {
+ Ok(QueryModifier::SeparateProvideExtern(modifier))
} else {
Err(Error::new(modifier.span(), "unknown query modifier"))
}
@@ -197,7 +200,7 @@
storage: Option<Type>,
/// Cache the query to disk if the `Block` returns true.
- cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>,
+ cache: Option<(Option<IdentOrWild>, Block)>,
/// Custom code to load the query from disk.
load_cached: Option<(Ident, Ident, Block)>,
@@ -216,6 +219,9 @@
// Always evaluate the query, ignoring its dependencies
eval_always: Option<Ident>,
+
+ /// Use a separate query provider for local and extern crates
+ separate_provide_extern: Option<Ident>,
}
/// Process query modifiers into a struct, erroring on duplicates
@@ -229,6 +235,7 @@
let mut no_hash = None;
let mut anon = None;
let mut eval_always = None;
+ let mut separate_provide_extern = None;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
@@ -319,6 +326,15 @@
}
eval_always = Some(ident);
}
+ QueryModifier::SeparateProvideExtern(ident) => {
+ if separate_provide_extern.is_some() {
+ panic!(
+ "duplicate modifier `separate_provide_extern` for query `{}`",
+ query.name
+ );
+ }
+ separate_provide_extern = Some(ident);
+ }
}
}
let desc = desc.unwrap_or_else(|| {
@@ -334,6 +350,7 @@
no_hash,
anon,
eval_always,
+ separate_provide_extern,
}
}
@@ -351,51 +368,30 @@
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
// Use custom code to load the query from disk
quote! {
- #[inline]
- fn try_load_from_disk(
- #tcx: QueryCtxt<'tcx>,
- #id: SerializedDepNodeIndex
- ) -> Option<Self::Value> {
- #block
- }
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+ = Some(|#tcx, #id| { #block });
}
} else {
// Use the default code to load the query from disk
quote! {
- #[inline]
- fn try_load_from_disk(
- tcx: QueryCtxt<'tcx>,
- id: SerializedDepNodeIndex
- ) -> Option<Self::Value> {
- tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)
- }
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+ = Some(|tcx, id| tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id));
}
};
let tcx = args
.as_ref()
.map(|t| {
- let t = &(t.0).0;
- quote! { #t }
- })
- .unwrap_or_else(|| quote! { _ });
- let value = args
- .as_ref()
- .map(|t| {
- let t = &(t.1).0;
+ let t = &t.0;
quote! { #t }
})
.unwrap_or_else(|| quote! { _ });
// expr is a `Block`, meaning that `{ #expr }` gets expanded
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
quote! {
- #[inline]
#[allow(unused_variables, unused_braces)]
- fn cache_on_disk(
- #tcx: QueryCtxt<'tcx>,
- #key: &Self::Key,
- #value: Option<&Self::Value>
- ) -> bool {
+ #[inline]
+ fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool {
#expr
}
@@ -405,7 +401,14 @@
if modifiers.load_cached.is_some() {
panic!("load_cached modifier on query `{}` without a cache modifier", name);
}
- quote! {}
+ quote! {
+ #[inline]
+ fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool {
+ false
+ }
+
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> = None;
+ }
};
let (tcx, desc) = modifiers.desc;
@@ -413,17 +416,17 @@
let desc = quote! {
#[allow(unused_variables)]
- fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
+ fn describe(tcx: QueryCtxt<$tcx>, key: Self::Key) -> String {
let (#tcx, #key) = (*tcx, key);
::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into())
}
};
impls.extend(quote! {
- impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::#name<'tcx> {
+ (#name<$tcx:tt>) => {
#desc
#cache
- }
+ };
});
}
@@ -478,6 +481,10 @@
if let Some(eval_always) = &modifiers.eval_always {
attributes.push(quote! { (#eval_always) });
};
+ // Pass on the separate_provide_extern modifier
+ if let Some(separate_provide_extern) = &modifiers.separate_provide_extern {
+ attributes.push(quote! { (#separate_provide_extern) });
+ }
// This uses the span of the query definition for the commas,
// which can be important if we later encounter any ambiguity
@@ -531,7 +538,7 @@
}
#[macro_export]
macro_rules! rustc_query_description {
- () => { #query_description_stream }
+ #query_description_stream
}
})
}
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 7bc669f..66e6b57 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -247,13 +247,24 @@
})
.collect();
- let result = quote! { ::rustc_serialize::Encoder::emit_enum_variant(
- __encoder,
- #variant_name,
- #variant_idx,
- #field_idx,
- |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
- ) };
+ let result = if field_idx != 0 {
+ quote! {
+ ::rustc_serialize::Encoder::emit_enum_variant(
+ __encoder,
+ #variant_name,
+ #variant_idx,
+ #field_idx,
+ |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
+ )
+ }
+ } else {
+ quote! {
+ ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
+ __encoder,
+ #variant_name,
+ )
+ }
+ };
variant_idx += 1;
result
});
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs
index c8959dc..80dcf99 100644
--- a/compiler/rustc_macros/src/session_diagnostic.rs
+++ b/compiler/rustc_macros/src/session_diagnostic.rs
@@ -349,14 +349,14 @@
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
let field_binding = &info.binding.binding;
- let option_ty = option_inner_ty(info.ty);
+ let option_ty = option_inner_ty(&info.ty);
let generated_code = self.generate_non_option_field_code(
attr,
FieldInfo {
vis: info.vis,
binding: info.binding,
- ty: option_ty.unwrap_or(info.ty),
+ ty: option_ty.unwrap_or(&info.ty),
span: info.span,
},
)?;
@@ -388,7 +388,7 @@
let formatted_str = self.build_format(&s.value(), attr.span());
match name {
"message" => {
- if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+ if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
quote! {
#diag.set_span(*#field_binding);
#diag.set_primary_message(#formatted_str);
@@ -401,7 +401,7 @@
}
}
"label" => {
- if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+ if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
quote! {
#diag.span_label(*#field_binding, #formatted_str);
}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 95b74fd..eb0a693 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -29,6 +29,7 @@
use proc_macro::bridge::client::ProcMacro;
use std::collections::BTreeMap;
+use std::ops::Fn;
use std::path::Path;
use std::{cmp, env};
use tracing::{debug, info};
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 644b849..6cf0dd8 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![feature(once_cell)]
#![feature(proc_macro_internals)]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index bbd30c9..7cba16e 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -236,7 +236,7 @@
use std::io::{Read, Result as IoResult, Write};
use std::path::{Path, PathBuf};
use std::{cmp, fmt, fs};
-use tracing::{debug, info, warn};
+use tracing::{debug, info};
#[derive(Clone)]
crate struct CrateLocator<'a> {
@@ -350,6 +350,7 @@
self.crate_rejections.via_kind.clear();
self.crate_rejections.via_version.clear();
self.crate_rejections.via_filename.clear();
+ self.crate_rejections.via_invalid.clear();
}
crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
@@ -548,8 +549,18 @@
continue;
}
}
- Err(err) => {
- warn!("no metadata found: {}", err);
+ Err(MetadataError::LoadFailure(err)) => {
+ info!("no metadata found: {}", err);
+ // The file was present and created by the same compiler version, but we
+ // couldn't load it for some reason. Give a hard error instead of silently
+ // ignoring it, but only if we would have given an error anyway.
+ self.crate_rejections
+ .via_invalid
+ .push(CrateMismatch { path: lib, got: err });
+ continue;
+ }
+ Err(err @ MetadataError::NotPresent(_)) => {
+ info!("no metadata found: {}", err);
continue;
}
};
@@ -726,25 +737,28 @@
fn get_metadata_section(
target: &Target,
flavor: CrateFlavor,
- filename: &Path,
+ filename: &'p Path,
loader: &dyn MetadataLoader,
-) -> Result<MetadataBlob, String> {
+) -> Result<MetadataBlob, MetadataError<'p>> {
if !filename.exists() {
- return Err(format!("no such file: '{}'", filename.display()));
+ return Err(MetadataError::NotPresent(filename));
}
let raw_bytes: MetadataRef = match flavor {
- CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?,
+ CrateFlavor::Rlib => {
+ loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
+ }
CrateFlavor::Dylib => {
- let buf = loader.get_dylib_metadata(target, filename)?;
+ let buf =
+ loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
// The header is uncompressed
let header_len = METADATA_HEADER.len();
debug!("checking {} bytes of metadata-version stamp", header_len);
let header = &buf[..cmp::min(header_len, buf.len())];
if header != METADATA_HEADER {
- return Err(format!(
- "incompatible metadata version found: '{}'",
+ return Err(MetadataError::LoadFailure(format!(
+ "invalid metadata version found: {}",
filename.display()
- ));
+ )));
}
// Header is okay -> inflate the actual metadata
@@ -756,17 +770,28 @@
match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
Err(_) => {
- return Err(format!("failed to decompress metadata: {}", filename.display()));
+ return Err(MetadataError::LoadFailure(format!(
+ "failed to decompress metadata: {}",
+ filename.display()
+ )));
}
}
}
CrateFlavor::Rmeta => {
// mmap the file, because only a small fraction of it is read.
- let file = std::fs::File::open(filename)
- .map_err(|_| format!("failed to open rmeta metadata: '{}'", filename.display()))?;
+ let file = std::fs::File::open(filename).map_err(|_| {
+ MetadataError::LoadFailure(format!(
+ "failed to open rmeta metadata: '{}'",
+ filename.display()
+ ))
+ })?;
let mmap = unsafe { Mmap::map(file) };
- let mmap = mmap
- .map_err(|_| format!("failed to mmap rmeta metadata: '{}'", filename.display()))?;
+ let mmap = mmap.map_err(|_| {
+ MetadataError::LoadFailure(format!(
+ "failed to mmap rmeta metadata: '{}'",
+ filename.display()
+ ))
+ })?;
rustc_erase_owner!(OwningRef::new(mmap).map_owner_box())
}
@@ -775,7 +800,10 @@
if blob.is_compatible() {
Ok(blob)
} else {
- Err(format!("incompatible metadata version found: '{}'", filename.display()))
+ Err(MetadataError::LoadFailure(format!(
+ "invalid metadata version found: {}",
+ filename.display()
+ )))
}
}
@@ -854,6 +882,7 @@
via_kind: Vec<CrateMismatch>,
via_version: Vec<CrateMismatch>,
via_filename: Vec<CrateMismatch>,
+ via_invalid: Vec<CrateMismatch>,
}
/// Candidate rejection reasons collected during crate search.
@@ -883,6 +912,24 @@
NonDylibPlugin(Symbol),
}
+enum MetadataError<'a> {
+ /// The file was missing.
+ NotPresent(&'a Path),
+ /// The file was present and invalid.
+ LoadFailure(String),
+}
+
+impl fmt::Display for MetadataError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ MetadataError::NotPresent(filename) => {
+ f.write_str(&format!("no such file: '{}'", filename.display()))
+ }
+ MetadataError::LoadFailure(msg) => f.write_str(msg),
+ }
+ }
+}
+
impl CrateError {
crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
let mut err = match self {
@@ -1064,6 +1111,19 @@
}
err.note(&msg);
err
+ } else if !locator.crate_rejections.via_invalid.is_empty() {
+ let mut err = struct_span_err!(
+ sess,
+ span,
+ E0786,
+ "found invalid metadata files for crate `{}`{}",
+ crate_name,
+ add,
+ );
+ for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
+ err.note(&got);
+ }
+ err
} else {
let mut err = struct_span_err!(
sess,
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 2431b81..bd5cda1 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -309,7 +309,7 @@
.libs
.iter()
.filter_map(|lib| lib.name.as_ref())
- .any(|n| &n.as_str() == &lib.name);
+ .any(|n| n.as_str() == lib.name);
if new_name.is_empty() {
self.tcx.sess.err(&format!(
"an empty renaming target was specified for library `{}`",
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 89bb579..b2c7818 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -472,9 +472,7 @@
let len = BytePos::decode(decoder)?;
let hi = lo + len;
- let sess = if let Some(sess) = decoder.sess {
- sess
- } else {
+ let Some(sess) = decoder.sess else {
bug!("Cannot decode Span without Session.")
};
@@ -1181,7 +1179,7 @@
let ctor_res =
Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
let mut vis = self.get_visibility(ctor_def_id.index);
- if ctor_def_id == def_id && vis == ty::Visibility::Public {
+ if ctor_def_id == def_id && vis.is_public() {
// For non-exhaustive variants lower the constructor visibility to
// within the crate. We only need this for fictive constructors,
// for other constructors correct visibilities
@@ -1200,8 +1198,8 @@
}
}
- if let EntryKind::Mod(data) = kind {
- for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
+ if let EntryKind::Mod(exports) = kind {
+ for exp in exports.decode((self, sess)) {
match exp.res {
Res::Def(DefKind::Macro(..), _) => {}
_ if macros_only => continue,
@@ -1221,10 +1219,11 @@
}
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
- if let EntryKind::Mod(m) = self.kind(id) {
- m.decode((self, sess)).expansion
- } else {
- panic!("Expected module, found {:?}", self.local_def_id(id))
+ match self.kind(id) {
+ EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
+ self.get_expn_that_defined(id, sess)
+ }
+ _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index e12f049..eeb0a77 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -10,7 +10,7 @@
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
use rustc_session::utils::NativeLibKind;
@@ -26,7 +26,7 @@
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
$($name:ident => $compute:block)*) => {
- pub fn provide_extern(providers: &mut Providers) {
+ pub fn provide_extern(providers: &mut ExternProviders) {
$(fn $name<$lt>(
$tcx: TyCtxt<$lt>,
def_id_arg: ty::query::query_keys::$name<$lt>,
@@ -51,7 +51,7 @@
$compute
})*
- *providers = Providers {
+ *providers = ExternProviders {
$($name,)*
..*providers
};
@@ -318,7 +318,7 @@
}
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| {
- if child.vis != ty::Visibility::Public {
+ if !child.vis.is_public() {
return;
}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 20f7b05..d46829c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -797,6 +797,7 @@
| DefKind::ConstParam
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
@@ -832,6 +833,7 @@
DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
@@ -856,9 +858,11 @@
(true, mir_opt_base)
}
// Constants
- DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
- (true, false)
- }
+ DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::AssocConst
+ | DefKind::Static
+ | DefKind::Const => (true, false),
// Full-fledged functions
DefKind::AssocFn | DefKind::Fn => {
let generics = tcx.generics_of(def_id);
@@ -914,6 +918,7 @@
| DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
@@ -939,6 +944,7 @@
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Field
@@ -1086,11 +1092,11 @@
Lazy::empty()
};
- let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
-
- record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+ 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 {
record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
item_id.def_id.local_def_index
@@ -2187,5 +2193,8 @@
result[header + 2] = (pos >> 8) as u8;
result[header + 3] = (pos >> 0) as u8;
+ // Record metadata size for self-profiling
+ tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64);
+
EncodedMetadata { raw_data: result }
}
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 42855e9..4e09d23 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -346,7 +346,7 @@
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
- Mod(Lazy<ModData>),
+ Mod(Lazy<[Export]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
@@ -365,12 +365,6 @@
struct RenderedConst(String);
#[derive(MetadataEncodable, MetadataDecodable)]
-struct ModData {
- reexports: Lazy<[Export]>,
- expansion: ExpnId,
-}
-
-#[derive(MetadataEncodable, MetadataDecodable)]
struct FnData {
asyncness: hir::IsAsync,
constness: hir::Constness,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index d06c593..daeccde 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -12,6 +12,7 @@
either = "1.5.0"
gsgdt = "0.1.2"
tracing = "0.1"
+rustc-rayon = "0.3.1"
rustc-rayon-core = "0.3.1"
polonius-engine = "0.13.0"
rustc_apfloat = { path = "../rustc_apfloat" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 962aea4..ee2e190 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -1,43 +1,38 @@
-/// This declares a list of types which can be allocated by `Arena`.
-///
-/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
-/// This is faster and more memory efficient if there's only a few allocations of the type.
-/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
-/// faster and more memory efficient if there is lots of allocations.
+/// This higher-order macro declares a list of types which can be allocated by `Arena`.
///
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type
/// listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
- ($macro:path, $tcx:lifetime) => (
+ ($macro:path) => (
$macro!([
[] layout: rustc_target::abi::Layout,
- [] fn_abi: rustc_target::abi::call::FnAbi<$tcx, rustc_middle::ty::Ty<$tcx>>,
+ [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
// AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef,
- [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,
- [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>,
- [decode] mir: rustc_middle::mir::Body<$tcx>,
+ [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<'tcx>>,
+ [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<'tcx>>,
+ [decode] mir: rustc_middle::mir::Body<'tcx>,
[] steal_promoted:
rustc_data_structures::steal::Steal<
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
- rustc_middle::mir::Body<$tcx>
+ rustc_middle::mir::Body<'tcx>
>
>,
[decode] promoted:
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
- rustc_middle::mir::Body<$tcx>
+ rustc_middle::mir::Body<'tcx>
>,
- [decode] typeck_results: rustc_middle::ty::TypeckResults<$tcx>,
+ [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
[decode] borrowck_result:
- rustc_middle::mir::BorrowCheckResult<$tcx>,
+ rustc_middle::mir::BorrowCheckResult<'tcx>,
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
[decode] code_region: rustc_middle::mir::coverage::CodeRegion,
[] const_allocs: rustc_middle::mir::interpret::Allocation,
// Required for the incremental on-disk cache
- [few] mir_keys: rustc_hir::def_id::DefIdSet,
+ [] mir_keys: rustc_hir::def_id::DefIdSet,
[] region_scope_tree: rustc_middle::middle::region::ScopeTree,
[] dropck_outlives:
rustc_middle::infer::canonical::Canonical<'tcx,
@@ -77,26 +72,20 @@
rustc_middle::infer::canonical::Canonical<'tcx,
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
>,
- [few] all_traits: Vec<rustc_hir::def_id::DefId>,
- [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
- [few] foreign_module: rustc_session::cstore::ForeignModule,
- [few] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
+ [] all_traits: Vec<rustc_hir::def_id::DefId>,
+ [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
+ [] foreign_module: rustc_session::cstore::ForeignModule,
+ [] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
[] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
[] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
- [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>,
+ [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
[] attribute: rustc_ast::Attribute,
[] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
[] hir_id_set: rustc_hir::HirIdSet,
// Interned types
- [] tys: rustc_middle::ty::TyS<$tcx>,
- [] predicates: rustc_middle::ty::PredicateInner<$tcx>,
-
- // HIR query types
- [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>,
- [few] hir_definitions: rustc_hir::definitions::Definitions,
- [] hir_owner: rustc_middle::hir::Owner<$tcx>,
- [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
+ [] tys: rustc_middle::ty::TyS<'tcx>,
+ [] predicates: rustc_middle::ty::PredicateInner<'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
@@ -106,8 +95,10 @@
// 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>,
- ], $tcx);
+
+ [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
+ ]);
)
}
-arena_types!(rustc_arena::declare_arena, 'tcx);
+arena_types!(rustc_arena::declare_arena);
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 23d475a..f310001 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -75,147 +75,73 @@
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
/// jump table instead of large matches.
pub struct DepKindStruct {
- /// Whether the DepNode has parameters (query keys).
- pub(super) has_params: bool,
-
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
/// When their result is needed, it is recomputed. They are useful for fine-grained
/// dependency tracking, and caching within one compiler invocation.
- pub(super) is_anon: bool,
+ pub is_anon: bool,
/// Eval-always queries do not track their dependencies, and are always recomputed, even if
/// their inputs have not changed since the last compiler invocation. The result is still
/// cached within one compiler invocation.
- pub(super) is_eval_always: bool,
+ pub is_eval_always: bool,
/// Whether the query key can be recovered from the hashed fingerprint.
/// See [DepNodeParams] trait for the behaviour of each key type.
- // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style
- // can be made a specialized associated const.
- fingerprint_style: fn() -> FingerprintStyle,
-}
+ pub fingerprint_style: FingerprintStyle,
-impl std::ops::Deref for DepKind {
- type Target = DepKindStruct;
- fn deref(&self) -> &DepKindStruct {
- &DEP_KINDS[*self as usize]
- }
+ /// The red/green evaluation system will try to mark a specific DepNode in the
+ /// dependency graph as green by recursively trying to mark the dependencies of
+ /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+ /// where we don't know if it is red or green and we therefore actually have
+ /// to recompute its value in order to find out. Since the only piece of
+ /// information that we have at that point is the `DepNode` we are trying to
+ /// re-evaluate, we need some way to re-run a query from just that. This is what
+ /// `force_from_dep_node()` implements.
+ ///
+ /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+ /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+ /// is usually constructed by computing a stable hash of the query-key that the
+ /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+ /// back from hash to query-key (since hash functions are not reversible). For
+ /// this reason `force_from_dep_node()` is expected to fail from time to time
+ /// because we just cannot find out, from the `DepNode` alone, what the
+ /// corresponding query-key is and therefore cannot re-run the query.
+ ///
+ /// The system deals with this case letting `try_mark_green` fail which forces
+ /// the root query to be re-evaluated.
+ ///
+ /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+ /// Fortunately, we can use some contextual information that will allow us to
+ /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+ /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+ /// valid `DefPathHash`. Since we also always build a huge table that maps every
+ /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+ /// everything we need to re-run the query.
+ ///
+ /// Take the `mir_promoted` query as an example. Like many other queries, it
+ /// just has a single parameter: the `DefId` of the item it will compute the
+ /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+ /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+ /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+ /// `DefId` in `tcx.def_path_hash_to_def_id`.
+ pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>,
+
+ /// Invoke a query to put the on-disk cached value in memory.
+ pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>,
}
impl DepKind {
#[inline(always)]
- pub fn fingerprint_style(&self) -> FingerprintStyle {
+ pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
// Only fetch the DepKindStruct once.
- let data: &DepKindStruct = &**self;
+ let data = tcx.query_kind(self);
if data.is_anon {
return FingerprintStyle::Opaque;
}
-
- (data.fingerprint_style)()
+ data.fingerprint_style
}
}
-// erase!() just makes tokens go away. It's used to specify which macro argument
-// is repeated (i.e., which sub-expression of the macro we are in) but don't need
-// to actually use any of the arguments.
-macro_rules! erase {
- ($x:tt) => {{}};
-}
-
-macro_rules! is_anon_attr {
- (anon) => {
- true
- };
- ($attr:ident) => {
- false
- };
-}
-
-macro_rules! is_eval_always_attr {
- (eval_always) => {
- true
- };
- ($attr:ident) => {
- false
- };
-}
-
-macro_rules! contains_anon_attr {
- ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false});
-}
-
-macro_rules! contains_eval_always_attr {
- ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false});
-}
-
-#[allow(non_upper_case_globals)]
-pub mod dep_kind {
- use super::*;
- use crate::ty::query::query_keys;
- use rustc_query_system::dep_graph::FingerprintStyle;
-
- // We use this for most things when incr. comp. is turned off.
- pub const Null: DepKindStruct = DepKindStruct {
- has_params: false,
- is_anon: false,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Unit,
- };
-
- pub const TraitSelect: DepKindStruct = DepKindStruct {
- has_params: false,
- is_anon: true,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Unit,
- };
-
- pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
- has_params: true,
- is_anon: false,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Opaque,
- };
-
- pub const CompileMonoItem: DepKindStruct = DepKindStruct {
- has_params: true,
- is_anon: false,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Opaque,
- };
-
- macro_rules! define_query_dep_kinds {
- ($(
- [$($attrs:tt)*]
- $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
- ,)*) => (
- $(pub const $variant: DepKindStruct = {
- const has_params: bool = $({ erase!($tuple_arg_ty); true } |)* false;
- const is_anon: bool = contains_anon_attr!($($attrs)*);
- const is_eval_always: bool = contains_eval_always_attr!($($attrs)*);
-
- #[inline(always)]
- fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle {
- <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>
- ::fingerprint_style()
- }
-
- DepKindStruct {
- has_params,
- is_anon,
- is_eval_always,
- fingerprint_style,
- }
- };)*
- );
- }
-
- rustc_dep_node_append!([define_query_dep_kinds!][]);
-}
-
macro_rules! define_dep_nodes {
(<$tcx:tt>
$(
@@ -225,12 +151,10 @@
) => (
#[macro_export]
macro_rules! make_dep_kind_array {
- ($mod:ident) => {[ $(($mod::$variant),)* ]};
+ ($mod:ident) => {[ $($mod::$variant()),* ]};
}
- static DEP_KINDS: &[DepKindStruct] = &make_dep_kind_array!(dep_kind);
-
- /// This enum serves as an index into the `DEP_KINDS` array.
+ /// This enum serves as an index into arrays built by `make_dep_kind_array`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
#[allow(non_camel_case_types)]
pub enum DepKind {
@@ -296,7 +220,7 @@
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
- fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;
+ fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
/// Extracts the DefId corresponding to this DepNode. This will work
/// if two conditions are met:
@@ -311,7 +235,11 @@
fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
/// Used in testing
- fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>;
+ fn from_label_string(
+ tcx: TyCtxt<'_>,
+ label: &str,
+ def_path_hash: DefPathHash,
+ ) -> Result<Self, ()>;
/// Used in testing
fn has_label_string(label: &str) -> bool;
@@ -321,8 +249,8 @@
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
- fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
- debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash);
+ fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
+ debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() }
}
@@ -337,31 +265,27 @@
/// refers to something from the previous compilation session that
/// has been removed.
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
- if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash {
- Some(
- tcx.on_disk_cache
- .as_ref()?
- .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())),
- )
+ if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
+ Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())))
} else {
None
}
}
/// Used in testing
- fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
+ fn from_label_string(
+ tcx: TyCtxt<'_>,
+ label: &str,
+ def_path_hash: DefPathHash,
+ ) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?;
- match kind.fingerprint_style() {
+ match kind.fingerprint_style(tcx) {
FingerprintStyle::Opaque => Err(()),
- FingerprintStyle::Unit => {
- if !kind.has_params {
- Ok(DepNode::new_no_params(kind))
- } else {
- Err(())
- }
+ FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
+ FingerprintStyle::DefPathHash => {
+ Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
}
- FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)),
}
}
@@ -377,10 +301,12 @@
FingerprintStyle::Unit
}
+ #[inline(always)]
fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
Fingerprint::ZERO
}
+ #[inline(always)]
fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
Some(())
}
@@ -392,14 +318,17 @@
FingerprintStyle::DefPathHash
}
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
tcx.def_path_hash(*self).0
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.def_path_str(*self)
}
+ #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx)
}
@@ -411,14 +340,17 @@
FingerprintStyle::DefPathHash
}
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
self.to_def_id().to_fingerprint(tcx)
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
self.to_def_id().to_debug_str(tcx)
}
+ #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.expect_local())
}
@@ -430,15 +362,18 @@
FingerprintStyle::DefPathHash
}
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
def_id.to_fingerprint(tcx)
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.crate_name(*self).to_string()
}
+ #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate)
}
@@ -453,6 +388,7 @@
// We actually would not need to specialize the implementation of this
// method but it's faster to combine the hashes than to instantiate a full
// hashing context and stable-hashing state.
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let (def_id_0, def_id_1) = *self;
@@ -462,6 +398,7 @@
def_path_hash_0.0.combine(def_path_hash_1.0)
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
let (def_id_0, def_id_1) = *self;
@@ -478,6 +415,7 @@
// We actually would not need to specialize the implementation of this
// method but it's faster to combine the hashes than to instantiate a full
// hashing context and stable-hashing state.
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let HirId { owner, local_id } = *self;
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index cda9963..79d7ca3 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -12,7 +12,7 @@
SerializedDepNodeIndex, WorkProduct, WorkProductId,
};
-pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
+pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
@@ -24,29 +24,8 @@
impl rustc_query_system::dep_graph::DepKind for DepKind {
const NULL: Self = DepKind::Null;
- #[inline(always)]
- fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle {
- DepKind::fingerprint_style(self)
- }
-
- #[inline(always)]
- fn is_eval_always(&self) -> bool {
- self.is_eval_always
- }
-
- #[inline(always)]
- fn has_params(&self) -> bool {
- self.has_params
- }
-
fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}", node.kind)?;
-
- if !node.kind.has_params && !node.kind.is_anon {
- return Ok(());
- }
-
- write!(f, "(")?;
+ write!(f, "{:?}(", node.kind)?;
ty::tls::with_opt(|opt_tcx| {
if let Some(tcx) = opt_tcx {
@@ -110,4 +89,51 @@
fn sess(&self) -> &Session {
self.sess
}
+
+ #[inline(always)]
+ fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
+ kind.fingerprint_style(*self)
+ }
+
+ #[inline(always)]
+ fn is_eval_always(&self, kind: DepKind) -> bool {
+ self.query_kind(kind).is_eval_always
+ }
+
+ fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
+ debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+ // We must avoid ever having to call `force_from_dep_node()` for a
+ // `DepNode::codegen_unit`:
+ // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+ // would always end up having to evaluate the first caller of the
+ // `codegen_unit` query that *is* reconstructible. This might very well be
+ // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+ // to re-trigger calling the `codegen_unit` query with the right key. At
+ // that point we would already have re-done all the work we are trying to
+ // avoid doing in the first place.
+ // The solution is simple: Just explicitly call the `codegen_unit` query for
+ // each CGU, right after partitioning. This way `try_mark_green` will always
+ // hit the cache instead of having to go through `force_from_dep_node`.
+ // This assertion makes sure, we actually keep applying the solution above.
+ debug_assert!(
+ dep_node.kind != DepKind::codegen_unit,
+ "calling force_from_dep_node() on DepKind::codegen_unit"
+ );
+
+ let cb = self.query_kind(dep_node.kind);
+ if let Some(f) = cb.force_from_dep_node {
+ f(*self, dep_node);
+ true
+ } else {
+ false
+ }
+ }
+
+ fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
+ let cb = self.query_kind(dep_node.kind);
+ if let Some(f) = cb.try_load_from_on_disk_cache {
+ f(*self, dep_node)
+ }
+ }
}
diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs
deleted file mode 100644
index 8efec8e..0000000
--- a/compiler/rustc_middle/src/hir/map/blocks.rs
+++ /dev/null
@@ -1,239 +0,0 @@
-//! This module provides a simplified abstraction for working with
-//! code blocks identified by their integer `NodeId`. In particular,
-//! it captures a common set of attributes that all "function-like
-//! things" (represented by `FnLike` instances) share. For example,
-//! all `FnLike` instances have a type signature (be it explicit or
-//! inferred). And all `FnLike` instances have a body, i.e., the code
-//! that is run when the function-like thing it represents is invoked.
-//!
-//! With the above abstraction in place, one can treat the program
-//! text as a collection of blocks of code (and most such blocks are
-//! nested within a uniquely determined `FnLike`), and users can ask
-//! for the `Code` associated with a particular NodeId.
-
-use crate::hir::map::Map;
-use rustc_hir as hir;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Expr, FnDecl, Node};
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-/// An FnLikeNode is a Node that is like a fn, in that it has a decl
-/// and a body (as well as a NodeId, a span, etc).
-///
-/// More specifically, it is one of either:
-///
-/// - A function item,
-/// - A closure expr (i.e., an ExprKind::Closure), or
-/// - The default implementation for a trait method.
-///
-/// To construct one, use the `Code::from_node` function.
-#[derive(Copy, Clone, Debug)]
-pub struct FnLikeNode<'a> {
- node: Node<'a>,
-}
-
-/// MaybeFnLike wraps a method that indicates if an object
-/// corresponds to some FnLikeNode.
-trait MaybeFnLike {
- fn is_fn_like(&self) -> bool;
-}
-
-impl MaybeFnLike for hir::Item<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::ItemKind::Fn(..))
- }
-}
-
-impl MaybeFnLike for hir::ImplItem<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::ImplItemKind::Fn(..))
- }
-}
-
-impl MaybeFnLike for hir::TraitItem<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
- }
-}
-
-impl MaybeFnLike for hir::Expr<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::ExprKind::Closure(..))
- }
-}
-
-/// Carries either an FnLikeNode or an Expr, as these are the two
-/// constructs that correspond to "code" (as in, something from which
-/// we can construct a control-flow graph).
-#[derive(Copy, Clone)]
-pub enum Code<'a> {
- FnLike(FnLikeNode<'a>),
- Expr(&'a Expr<'a>),
-}
-
-impl<'a> Code<'a> {
- pub fn id(&self) -> hir::HirId {
- match *self {
- Code::FnLike(node) => node.id(),
- Code::Expr(block) => block.hir_id,
- }
- }
-
- /// Attempts to construct a Code from presumed FnLike or Expr node input.
- pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> {
- match map.get(id) {
- Node::Block(_) => {
- // Use the parent, hopefully an expression node.
- Code::from_node(map, map.get_parent_node(id))
- }
- Node::Expr(expr) => Some(Code::Expr(expr)),
- node => FnLikeNode::from_node(node).map(Code::FnLike),
- }
- }
-}
-
-/// These are all the components one can extract from a fn item for
-/// use when implementing FnLikeNode operations.
-struct ItemFnParts<'a> {
- ident: Ident,
- decl: &'a hir::FnDecl<'a>,
- header: hir::FnHeader,
- vis: &'a hir::Visibility<'a>,
- generics: &'a hir::Generics<'a>,
- body: hir::BodyId,
- id: hir::HirId,
- span: Span,
-}
-
-/// These are all the components one can extract from a closure expr
-/// for use when implementing FnLikeNode operations.
-struct ClosureParts<'a> {
- decl: &'a FnDecl<'a>,
- body: hir::BodyId,
- id: hir::HirId,
- span: Span,
-}
-
-impl<'a> ClosureParts<'a> {
- fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self {
- ClosureParts { decl: d, body: b, id, span: s }
- }
-}
-
-impl<'a> FnLikeNode<'a> {
- /// Attempts to construct a FnLikeNode from presumed FnLike node input.
- pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
- let fn_like = match node {
- Node::Item(item) => item.is_fn_like(),
- Node::TraitItem(tm) => tm.is_fn_like(),
- Node::ImplItem(it) => it.is_fn_like(),
- Node::Expr(e) => e.is_fn_like(),
- _ => false,
- };
- fn_like.then_some(FnLikeNode { node })
- }
-
- pub fn body(self) -> hir::BodyId {
- self.handle(
- |i: ItemFnParts<'a>| i.body,
- |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body,
- |c: ClosureParts<'a>| c.body,
- )
- }
-
- pub fn decl(self) -> &'a FnDecl<'a> {
- self.handle(
- |i: ItemFnParts<'a>| &*i.decl,
- |_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl,
- |c: ClosureParts<'a>| c.decl,
- )
- }
-
- pub fn span(self) -> Span {
- self.handle(
- |i: ItemFnParts<'_>| i.span,
- |_, _, _: &'a hir::FnSig<'a>, _, _, span| span,
- |c: ClosureParts<'_>| c.span,
- )
- }
-
- pub fn id(self) -> hir::HirId {
- self.handle(
- |i: ItemFnParts<'_>| i.id,
- |id, _, _: &'a hir::FnSig<'a>, _, _, _| id,
- |c: ClosureParts<'_>| c.id,
- )
- }
-
- pub fn constness(self) -> hir::Constness {
- self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness)
- }
-
- pub fn asyncness(self) -> hir::IsAsync {
- self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness)
- }
-
- pub fn unsafety(self) -> hir::Unsafety {
- self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety)
- }
-
- pub fn kind(self) -> FnKind<'a> {
- let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
- FnKind::ItemFn(p.ident, p.generics, p.header, p.vis)
- };
- let closure = |_: ClosureParts<'a>| FnKind::Closure;
- let method =
- |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis);
- self.handle(item, method, closure)
- }
-
- fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
- where
- I: FnOnce(ItemFnParts<'a>) -> A,
- M: FnOnce(
- hir::HirId,
- Ident,
- &'a hir::FnSig<'a>,
- Option<&'a hir::Visibility<'a>>,
- hir::BodyId,
- Span,
- ) -> A,
- C: FnOnce(ClosureParts<'a>) -> A,
- {
- match self.node {
- Node::Item(i) => match i.kind {
- hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
- id: i.hir_id(),
- ident: i.ident,
- decl: &sig.decl,
- body: block,
- vis: &i.vis,
- span: i.span,
- header: sig.header,
- generics,
- }),
- _ => bug!("item FnLikeNode that is not fn-like"),
- },
- Node::TraitItem(ti) => match ti.kind {
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- method(ti.hir_id(), ti.ident, sig, None, body, ti.span)
- }
- _ => bug!("trait method FnLikeNode that is not fn-like"),
- },
- Node::ImplItem(ii) => match ii.kind {
- hir::ImplItemKind::Fn(ref sig, body) => {
- method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span)
- }
- _ => bug!("impl method FnLikeNode that is not fn-like"),
- },
- Node::Expr(e) => match e.kind {
- hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
- closure(ClosureParts::new(&decl, block, e.hir_id, e.span))
- }
- _ => bug!("expr FnLikeNode that is not fn-like"),
- },
- _ => bug!("other FnLikeNode that is not fn-like"),
- }
- }
-}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e6f56b0..d9d0781 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,6 +1,4 @@
-use self::collector::NodeCollector;
-
-use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner};
+use crate::hir::{ModuleItems, Owner};
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
@@ -22,9 +20,6 @@
use rustc_target::spec::abi::Abi;
use std::collections::VecDeque;
-pub mod blocks;
-mod collector;
-
fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
match node {
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
@@ -166,8 +161,8 @@
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()? {
- OwnerNode::Item(item) => Some(*item),
+ krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() {
+ OwnerNode::Item(item) => Some(item),
_ => None,
})
}
@@ -271,7 +266,15 @@
};
DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
}
- Node::AnonConst(_) => DefKind::AnonConst,
+ Node::AnonConst(_) => {
+ let inline = match self.find(self.get_parent_node(hir_id)) {
+ Some(Node::Expr(&Expr {
+ kind: ExprKind::ConstBlock(ref anon_const), ..
+ })) if anon_const.hir_id == hir_id => true,
+ _ => false,
+ };
+ if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+ }
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure(.., None) => DefKind::Closure,
@@ -318,7 +321,7 @@
}
pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
- self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID)
+ self.find_parent_node(hir_id).unwrap()
}
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
@@ -381,7 +384,7 @@
}
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
- self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap()
+ 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>> {
@@ -443,7 +446,7 @@
pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
- _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP),
+ _ => Ident::empty(),
})
}
@@ -495,11 +498,35 @@
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
- self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id))
+ self.krate()
+ .owners
+ .iter_enumerated()
+ .flat_map(move |(owner, owner_info)| {
+ let bodies = &owner_info.as_ref()?.nodes.bodies;
+ Some(bodies.iter().map(move |&(local_id, _)| {
+ let hir_id = HirId { owner, local_id };
+ let body_id = BodyId { hir_id };
+ self.body_owner_def_id(body_id)
+ }))
+ })
+ .flatten()
}
pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
- par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id)));
+ use rustc_data_structures::sync::{par_iter, ParallelIterator};
+ #[cfg(parallel_compiler)]
+ use rustc_rayon::iter::IndexedParallelIterator;
+
+ par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| {
+ let owner = LocalDefId::new(owner);
+ if let Some(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 };
+ f(self.body_owner_def_id(body_id))
+ })
+ }
+ });
}
pub fn ty_param_owner(&self, id: HirId) -> HirId {
@@ -551,9 +578,14 @@
/// Walks the attributes in a crate.
pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
let krate = self.krate();
- for (&id, attrs) in krate.attrs.iter() {
- for a in *attrs {
- visitor.visit_attribute(id, a)
+ for (owner, info) in krate.owners.iter_enumerated() {
+ if let Some(info) = info {
+ for (local_id, attrs) in info.attrs.map.iter() {
+ let id = HirId { owner, local_id: *local_id };
+ for a in *attrs {
+ visitor.visit_attribute(id, a)
+ }
+ }
}
}
}
@@ -572,7 +604,7 @@
{
let krate = self.krate();
for owner in krate.owners.iter().filter_map(Option::as_ref) {
- match owner {
+ match owner.node() {
OwnerNode::Item(item) => visitor.visit_item(item),
OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
@@ -588,7 +620,7 @@
V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
{
let krate = self.krate();
- par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() {
+ 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),
@@ -839,21 +871,21 @@
pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::Item(item) }) => item,
+ Some(Owner { node: OwnerNode::Item(item), .. }) => item,
_ => bug!("expected item, found {}", self.node_to_string(id)),
}
}
pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::ImplItem(item) }) => item,
+ Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
_ => bug!("expected impl item, found {}", self.node_to_string(id)),
}
}
pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::TraitItem(item) }) => item,
+ Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
_ => bug!("expected trait item, found {}", self.node_to_string(id)),
}
}
@@ -867,7 +899,7 @@
pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::ForeignItem(item) }) => item,
+ Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
_ => bug!("expected foreign item, found {}", self.node_to_string(id)),
}
}
@@ -1032,42 +1064,10 @@
}
}
-pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tcx> {
- let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map");
-
- // We can access untracked state since we are an eval_always query.
- let hcx = tcx.create_stable_hashing_context();
- let mut collector = NodeCollector::root(
- tcx.sess,
- &**tcx.arena,
- tcx.untracked_crate,
- &tcx.untracked_resolutions.definitions,
- hcx,
- );
- let top_mod = tcx.untracked_crate.module();
- collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
-
- let map = collector.finalize_and_compute_crate_hash();
- tcx.arena.alloc(map)
-}
-
pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
- assert_eq!(crate_num, LOCAL_CRATE);
-
- // We can access untracked state since we are an eval_always query.
- let mut hcx = tcx.create_stable_hashing_context();
-
- let mut hir_body_nodes: Vec<_> = tcx
- .index_hir(())
- .map
- .iter_enumerated()
- .filter_map(|(def_id, hod)| {
- let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id);
- let hash = hod.as_ref()?.hash;
- Some((def_path_hash, hash, def_id))
- })
- .collect();
- hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+ debug_assert_eq!(crate_num, LOCAL_CRATE);
+ let krate = tcx.hir_crate(());
+ let hir_body_hash = krate.hir_hash;
let upstream_crates = upstream_crates(tcx);
@@ -1087,20 +1087,27 @@
source_file_names.sort_unstable();
+ let mut hcx = tcx.create_stable_hashing_context();
let mut stable_hasher = StableHasher::new();
- for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() {
- def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher);
- fingerprint.hash_stable(&mut hcx, &mut stable_hasher);
- AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id }
- .hash_stable(&mut hcx, &mut stable_hasher);
- if tcx.sess.opts.debugging_opts.incremental_relative_spans {
- let span = tcx.untracked_resolutions.definitions.def_span(*def_id);
- debug_assert_eq!(span.parent(), None);
- span.hash_stable(&mut hcx, &mut stable_hasher);
- }
- }
+ hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+ if tcx.sess.opts.debugging_opts.incremental_relative_spans {
+ let definitions = &tcx.untracked_resolutions.definitions;
+ let mut owner_spans: Vec<_> = krate
+ .owners
+ .iter_enumerated()
+ .filter_map(|(def_id, info)| {
+ let _ = info.as_ref()?;
+ let def_path_hash = definitions.def_path_hash(def_id);
+ let span = definitions.def_span(def_id);
+ debug_assert_eq!(span.parent(), None);
+ Some((def_path_hash, span))
+ })
+ .collect();
+ owner_spans.sort_unstable_by_key(|bn| bn.0);
+ owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
+ }
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 5016c5c..95d7273 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -8,28 +8,12 @@
use crate::ty::query::Providers;
use crate::ty::TyCtxt;
-use rustc_ast::Attribute;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::*;
-use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
use rustc_span::DUMMY_SP;
-use std::collections::BTreeMap;
-
-/// Result of HIR indexing.
-#[derive(Debug)]
-pub struct IndexedHir<'hir> {
- /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners.
- // The `mut` comes from construction time, and is harmless since we only ever hand out
- // immutable refs to IndexedHir.
- map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
- /// Map from each owner to its parent's HirId inside another owner.
- // This map is separate from `map` to eventually allow for per-owner indexing.
- parenting: FxHashMap<LocalDefId, HirId>,
-}
/// Top-level HIR node for current owner. This only contains the node for which
/// `HirId::local_id == 0`, and excludes bodies.
@@ -39,85 +23,14 @@
#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
node: OwnerNode<'tcx>,
+ hash_without_bodies: Fingerprint,
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
+ #[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let Owner { node } = self;
- hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher));
- }
-}
-
-/// HIR node coupled with its parent's id in the same HIR owner.
-///
-/// The parent is trash when the node is a HIR owner.
-#[derive(Clone, Debug)]
-pub struct ParentedNode<'tcx> {
- parent: ItemLocalId,
- node: Node<'tcx>,
-}
-
-#[derive(Debug)]
-pub struct OwnerNodes<'tcx> {
- /// Pre-computed hash of the full HIR.
- hash: Fingerprint,
- /// Full HIR for the current owner.
- // The zeroth node's parent is trash, but is never accessed.
- nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
- /// Content of local bodies.
- bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>,
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, 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, nodes: _, bodies: _ } = *self;
- hash.hash_stable(hcx, hasher);
- }
-}
-
-/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted
-/// to the nodes whose `HirId::owner` is `prefix`.
-#[derive(Copy, Clone)]
-pub struct AttributeMap<'tcx> {
- map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
- prefix: LocalDefId,
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for AttributeMap<'tcx> {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let range = self.range();
-
- range.clone().count().hash_stable(hcx, hasher);
- for (key, value) in range {
- key.hash_stable(hcx, hasher);
- value.hash_stable(hcx, hasher);
- }
- }
-}
-
-impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("AttributeMap")
- .field("prefix", &self.prefix)
- .field("range", &&self.range().collect::<Vec<_>>()[..])
- .finish()
- }
-}
-
-impl<'tcx> AttributeMap<'tcx> {
- fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
- self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[])
- }
-
- fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> {
- let local_zero = ItemLocalId::from_u32(0);
- let range = HirId { owner: self.prefix, local_id: local_zero }..HirId {
- owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 },
- local_id: local_zero,
- };
- self.map.range(range)
+ let Owner { node: _, hash_without_bodies } = self;
+ hash_without_bodies.hash_stable(hcx, hasher)
}
}
@@ -149,21 +62,32 @@
hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
};
providers.hir_crate = |tcx, ()| tcx.untracked_crate;
- providers.index_hir = map::index_hir;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.hir_owner = |tcx, id| {
- let owner = tcx.index_hir(()).map[id].as_ref()?;
- let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
- let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
- Some(Owner { node })
+ let owner = tcx.hir_crate(()).owners[id].as_ref()?;
+ let node = owner.node();
+ Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
};
- providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
+ providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes);
providers.hir_owner_parent = |tcx, id| {
- let index = tcx.index_hir(());
- index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_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);
+ if let Some(local_id) =
+ tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id)
+ {
+ parent_hir_id.local_id = *local_id;
+ }
+ parent_hir_id
+ });
+ parent
};
- providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
+ providers.hir_attrs =
+ |tcx, id| tcx.hir_crate(()).owners[id].as_ref().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| {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index e41f5ad..9ce9f65 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -30,6 +30,7 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(core_intrinsics)]
+#![feature(derive_default_enum)]
#![feature(discriminant_kind)]
#![feature(exhaustive_patterns)]
#![feature(if_let_guard)]
@@ -39,6 +40,7 @@
#![feature(new_uninit)]
#![feature(nll)]
#![feature(once_cell)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(in_band_lifetimes)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 1eba299..881b142 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -248,8 +248,12 @@
(Level::Warn, None) => sess.struct_warn(""),
(Level::ForceWarn, Some(span)) => sess.struct_span_force_warn(span, ""),
(Level::ForceWarn, None) => sess.struct_force_warn(""),
- (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
- (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
+ (Level::Deny | Level::Forbid, Some(span)) => {
+ let mut builder = sess.diagnostic().struct_err_lint("");
+ builder.set_span(span);
+ builder
+ }
+ (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
};
// If this code originates in a foreign macro, aka something that this crate
@@ -391,7 +395,7 @@
match expn_data.kind {
ExpnKind::Inlined
| ExpnKind::Root
- | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false,
+ | ExpnKind::Desugaring(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 597622b..8a5fc5f 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -3,7 +3,7 @@
pub use self::StabilityLevel::*;
-use crate::ty::{self, TyCtxt};
+use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -90,6 +90,7 @@
feature: Symbol,
reason: Option<Symbol>,
issue: Option<NonZeroU32>,
+ suggestion: Option<(Span, String, String, Applicability)>,
is_soft: bool,
span: Span,
soft_handler: impl FnOnce(&'static Lint, Span, &str),
@@ -116,8 +117,12 @@
if is_soft {
soft_handler(SOFT_UNSTABLE, span, &msg)
} else {
- feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg)
- .emit();
+ let mut err =
+ feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg);
+ if let Some((inner_types, ref msg, sugg, applicability)) = suggestion {
+ err.span_suggestion(inner_types, msg, sugg, applicability);
+ }
+ err.emit();
}
}
}
@@ -271,7 +276,13 @@
Allow,
/// We cannot use the item because it is unstable and we did not provide the
/// corresponding feature gate.
- Deny { feature: Symbol, reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
+ Deny {
+ feature: Symbol,
+ reason: Option<Symbol>,
+ issue: Option<NonZeroU32>,
+ suggestion: Option<(Span, String, String, Applicability)>,
+ is_soft: bool,
+ },
/// The item does not have the `#[stable]` or `#[unstable]` marker assigned.
Unmarked,
}
@@ -292,6 +303,32 @@
}
}
+// See issue #83250.
+fn suggestion_for_allocator_api(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+ span: Span,
+ feature: Symbol,
+) -> Option<(Span, String, String, Applicability)> {
+ if feature == sym::allocator_api {
+ if let Some(trait_) = tcx.parent(def_id) {
+ if tcx.is_diagnostic_item(sym::Vec, trait_) {
+ let sm = tcx.sess.parse_sess.source_map();
+ let inner_types = sm.span_extend_to_prev_char(span, '<', true);
+ if let Ok(snippet) = sm.span_to_snippet(inner_types) {
+ return Some((
+ inner_types,
+ "consider wrapping the inner types in tuple".to_string(),
+ format!("({})", snippet),
+ Applicability::MaybeIncorrect,
+ ));
+ }
+ }
+ }
+ }
+ None
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates the stability of an item.
///
@@ -406,7 +443,8 @@
}
}
- EvalResult::Deny { feature, reason, issue, is_soft }
+ let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
+ EvalResult::Deny { feature, reason, issue, suggestion, is_soft }
}
Some(_) => {
// Stable APIs are always ok to call and deprecated APIs are
@@ -457,9 +495,16 @@
};
match self.eval_stability(def_id, id, span, method_span) {
EvalResult::Allow => {}
- EvalResult::Deny { feature, reason, issue, is_soft } => {
- report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler)
- }
+ EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
+ self.sess,
+ feature,
+ reason,
+ issue,
+ suggestion,
+ is_soft,
+ span,
+ soft_handler,
+ ),
EvalResult::Unmarked => unmarked(span, def_id),
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 9472a28..7a51bb4 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -538,12 +538,12 @@
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
/// so this method lets us detect them and `bug!` on unexpected errors.
pub fn formatted_string(&self) -> bool {
- match self {
+ matches!(
+ self,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
- _ => false,
- }
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
+ )
}
/// Should this error be reported as a hard error, preventing compilation, or a soft error,
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 971556d..4210e07 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2246,8 +2246,12 @@
/// The `*` operator (multiplication)
Mul,
/// The `/` operator (division)
+ ///
+ /// Division by zero is UB.
Div,
/// The `%` operator (modulus)
+ ///
+ /// Using zero as the modulus (second operand) is UB.
Rem,
/// The `^` operator (bitwise xor)
BitXor,
@@ -2256,8 +2260,12 @@
/// The `|` operator (bitwise or)
BitOr,
/// The `<<` operator (shift left)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
Shl,
/// The `>>` operator (shift right)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
Shr,
/// The `==` operator (equality)
Eq,
@@ -2665,7 +2673,7 @@
mut self,
mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection,
) -> Self {
- self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect();
+ self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect();
self
}
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index db98cb7..8e1b887 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -71,6 +71,7 @@
/// or `typeck` appears in the name.
/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name
/// or `typeck` and `bar` both appear in the name.
+#[inline]
pub fn dump_mir<'tcx, F>(
tcx: TyCtxt<'tcx>,
pass_num: Option<&dyn Display>,
@@ -957,7 +958,7 @@
write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
}
(_, _) if is_function => write!(w, "fn ")?,
- (DefKind::AnonConst, _) => {} // things like anon const, not an item
+ (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
_ => bug!("Unexpected def kind {:?}", kind),
}
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index d5541d7..cb3f385 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -225,6 +225,7 @@
pub struct ConstQualifs {
pub has_mut_interior: bool,
pub needs_drop: bool,
+ pub needs_non_const_drop: bool,
pub custom_eq: bool,
pub error_occured: Option<ErrorReported>,
}
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 42683da..1260c69 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -632,11 +632,11 @@
for statement in statements {
let source_range = source_range_no_file(tcx, &statement.source_info.span);
text.push(format!(
- "\n{}{}: {}: {}",
+ "\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
statement_kind_name(&statement),
- format!("{:?}", statement)
+ statement
));
}
if let Some(term) = terminator {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4145cbd..ca93efb 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -36,18 +36,9 @@
/// prefer wrappers like `tcx.visit_all_items_in_krate()`.
query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
eval_always
- no_hash
desc { "get the crate HIR" }
}
- /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
- /// Avoid calling this query directly.
- query index_hir(_: ()) -> &'tcx crate::hir::IndexedHir<'tcx> {
- eval_always
- no_hash
- desc { "index HIR" }
- }
-
/// The items in a module.
///
/// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
@@ -62,7 +53,6 @@
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
- eval_always
desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
}
@@ -71,7 +61,6 @@
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner_parent(key: LocalDefId) -> hir::HirId {
- eval_always
desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
}
@@ -79,8 +68,7 @@
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> {
- eval_always
+ query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
}
@@ -88,8 +76,7 @@
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> {
- eval_always
+ query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> {
desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
}
@@ -120,6 +107,7 @@
/// 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> {
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> {
@@ -141,6 +129,7 @@
path = tcx.def_path_str(key),
}
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query analysis(key: ()) -> Result<(), ErrorReported> {
@@ -154,6 +143,7 @@
desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
@@ -194,6 +184,7 @@
/// Bounds from the parent (e.g. with nested impl trait) are not included.
query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Elaborated version of the predicates from `explicit_item_bounds`.
@@ -222,6 +213,7 @@
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
desc { "looking up the native libraries of a linked crate" }
+ separate_provide_extern
}
query lint_levels(_: ()) -> LintLevelMap {
@@ -239,11 +231,13 @@
// This query reads from untracked data in definitions.
eval_always
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query is_panic_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_panic_runtime" }
+ separate_provide_extern
}
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
@@ -273,6 +267,7 @@
query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query mir_const_qualif_const_arg(
key: (LocalDefId, DefId)
@@ -309,6 +304,7 @@
desc {
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
}
+ separate_provide_extern
}
/// Try to build an abstract representation of the given constant.
query thir_abstract_const_of_const_arg(
@@ -342,6 +338,7 @@
) -> &'tcx mir::Body<'tcx> {
desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
@@ -379,6 +376,7 @@
query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
@@ -417,6 +415,7 @@
query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query promoted_mir_of_const_arg(
key: (LocalDefId, DefId)
@@ -475,12 +474,14 @@
/// Returns the predicates written explicitly by the user.
query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns the inferred outlives predicates (e.g., for `struct
/// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Maps from the `DefId` of a trait to the list of
@@ -491,6 +492,7 @@
/// additional acyclicity requirements).
query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
@@ -516,12 +518,15 @@
query trait_def(key: DefId) -> ty::TraitDef {
desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
+ separate_provide_extern
}
query adt_def(key: DefId) -> &'tcx ty::AdtDef {
desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query adt_destructor(key: DefId) -> Option<ty::Destructor> {
desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
// The cycle error here should be reported as an error by `check_representable`.
@@ -550,10 +555,12 @@
/// `is_const_fn` function.
query is_const_fn_raw(key: DefId) -> bool {
desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query asyncness(key: DefId) -> hir::IsAsync {
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns `true` if calls to the function may be promoted.
@@ -570,16 +577,19 @@
/// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
query is_foreign_item(key: DefId) -> bool {
desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Gets a map with the variance of every item; use `item_variance` instead.
@@ -591,6 +601,7 @@
/// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Maps from thee `DefId` of a type to its (inferred) outlives.
@@ -602,12 +613,14 @@
/// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Maps from a trait item to the trait item "descriptor".
query associated_item(key: DefId) -> ty::AssocItem {
desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
+ separate_provide_extern
}
/// Collects the associated items defined on a trait or impl.
@@ -620,9 +633,11 @@
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+ separate_provide_extern
}
query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+ separate_provide_extern
}
query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
@@ -634,7 +649,7 @@
/// Methods in these implementations don't need to be exported.
query inherent_impls(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
- eval_always
+ separate_provide_extern
}
/// The result of unsafety-checking this `LocalDefId`.
@@ -671,11 +686,13 @@
desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
}
- /// The signature of functions.
+ /// Computes the signature of the function.
query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
+ /// Performs lint checking for the module.
query lint_mod(key: LocalDefId) -> () {
desc { |tcx| "linting {}", describe_as_module(key, tcx) }
}
@@ -685,6 +702,7 @@
desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
}
+ /// Checks for uses of unstable APIs in the module.
query check_mod_unstable_api_usage(key: LocalDefId) -> () {
desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
}
@@ -728,10 +746,10 @@
}
/// Caches `CoerceUnsized` kinds for impls on custom types.
- query coerce_unsized_info(key: DefId)
- -> ty::adjustment::CoerceUnsizedInfo {
- desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
- }
+ query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
+ desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
query typeck_item_bodies(_: ()) -> () {
desc { "type-checking all item bodies" }
@@ -778,10 +796,7 @@
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if(tcx, opt_result) {
- tcx.is_closure(key.to_def_id())
- || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
- }
+ cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc {
@@ -794,18 +809,23 @@
/// Not meant to be used directly outside of coherence.
query crate_inherent_impls(k: ()) -> CrateInherentImpls {
storage(ArenaCacheSelector<'tcx>)
- eval_always
desc { "all inherent impls defined in crate" }
}
/// Checks all types in the crate for overlap in their inherent impls. Reports errors.
/// Not meant to be used directly outside of coherence.
- query crate_inherent_impls_overlap_check(_: ())
- -> () {
- eval_always
+ query crate_inherent_impls_overlap_check(_: ()) -> () {
desc { "check for overlap between inherent impls defined in this crate" }
}
+ /// Checks whether all impls in the crate pass the overlap check, returning
+ /// which impls fail it. If all impls are correct, the returned slice is empty.
+ query orphan_check_crate(_: ()) -> &'tcx [LocalDefId] {
+ desc {
+ "checking whether the immpl in the this crate follow the orphan rules",
+ }
+ }
+
/// Check whether the function has any recursion that could cause the inliner to trigger
/// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
/// current function, just all intermediate functions.
@@ -914,6 +934,7 @@
desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
}
+ /// Generates a MIR body for the shim.
query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
storage(ArenaCacheSelector<'tcx>)
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
@@ -929,28 +950,29 @@
query opt_def_kind(def_id: DefId) -> Option<DefKind> {
desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
+ /// Gets the span for the definition.
query def_span(def_id: DefId) -> Span {
desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
- // FIXME(mw): DefSpans are not really inputs since they are derived from
- // HIR. But at the moment HIR hashing still contains some hacks that allow
- // to make type debuginfo to be source location independent. Declaring
- // DefSpan an input makes sure that changes to these are always detected
- // regardless of HIR hashing.
- eval_always
+ separate_provide_extern
}
+ /// Gets the span for the identifier of the definition.
query def_ident_span(def_id: DefId) -> Option<Span> {
desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> {
desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> {
desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query should_inherit_track_caller(def_id: DefId) -> bool {
@@ -959,10 +981,12 @@
query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
@@ -973,27 +997,33 @@
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Gets the rendered value of the specified constant or associated constant.
/// Used by rustdoc.
query rendered_const(def_id: DefId) -> String {
desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query impl_parent(def_id: DefId) -> Option<DefId> {
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Given an `associated_item`, find the trait it belongs to.
/// Return `None` if the `DefId` is not an associated item.
query trait_of_item(associated_item: DefId) -> Option<DefId> {
desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
+ separate_provide_extern
}
query is_ctfe_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query is_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query own_existential_vtable_entries(
@@ -1030,11 +1060,6 @@
}
/// Return all `impl` blocks in the current crate.
- ///
- /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
- /// Passing in any other crate will cause an ICE.
- ///
- /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
query all_local_trait_impls(_: ()) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> {
desc { "local trait impls" }
}
@@ -1159,6 +1184,7 @@
query dylib_dependency_formats(_: CrateNum)
-> &'tcx [(CrateNum, LinkagePreference)] {
desc { "dylib dependency formats of crate" }
+ separate_provide_extern
}
query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
@@ -1168,41 +1194,50 @@
query is_compiler_builtins(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_compiler_builtins" }
+ separate_provide_extern
}
query has_global_allocator(_: CrateNum) -> bool {
// This query depends on untracked global state in CStore
eval_always
fatal_cycle
desc { "checking if the crate has_global_allocator" }
+ separate_provide_extern
}
query has_panic_handler(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate has_panic_handler" }
+ separate_provide_extern
}
query is_profiler_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "query a crate is `#![profiler_runtime]`" }
+ separate_provide_extern
}
query panic_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
desc { "query a crate's configured panic strategy" }
+ separate_provide_extern
}
query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
desc { "query a crate's configured panic-in-drop strategy" }
+ separate_provide_extern
}
query is_no_builtins(_: CrateNum) -> bool {
fatal_cycle
desc { "test whether a crate has `#![no_builtins]`" }
+ separate_provide_extern
}
query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
fatal_cycle
desc { "query a crate's symbol mangling version" }
+ separate_provide_extern
}
query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
eval_always
desc { "getting crate's ExternCrateData" }
+ separate_provide_extern
}
query specializes(_: (DefId, DefId)) -> bool {
@@ -1219,10 +1254,12 @@
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query impl_constness(def_id: DefId) -> hir::Constness {
desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query check_item_well_formed(key: LocalDefId) -> () {
@@ -1251,9 +1288,11 @@
-> DefIdMap<SymbolExportLevel> {
storage(ArenaCacheSelector<'tcx>)
desc { "looking up the exported symbols of a crate" }
+ separate_provide_extern
}
query is_reachable_non_generic(def_id: DefId) -> bool {
desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
desc { |tcx|
@@ -1286,6 +1325,7 @@
"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
@@ -1309,6 +1349,7 @@
query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
desc { "looking up the foreign modules of a linked crate" }
+ separate_provide_extern
}
/// Identifies the entry-point (e.g., the `main` function) for a given
@@ -1324,18 +1365,22 @@
query crate_hash(_: CrateNum) -> Svh {
eval_always
desc { "looking up the hash a crate" }
+ separate_provide_extern
}
query crate_host_hash(_: CrateNum) -> Option<Svh> {
eval_always
desc { "looking up the hash of a host version of a crate" }
+ separate_provide_extern
}
query extra_filename(_: CrateNum) -> String {
eval_always
desc { "looking up the extra filename for a crate" }
+ separate_provide_extern
}
query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
eval_always
desc { "looking up the paths for extern crates" }
+ separate_provide_extern
}
/// Given a crate and a trait, look up all impls of that trait in the crate.
@@ -1343,6 +1388,7 @@
query implementations_of_trait(_: (CrateNum, DefId))
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up implementations of a trait in a crate" }
+ separate_provide_extern
}
/// Given a crate, look up all trait impls in that crate.
@@ -1350,6 +1396,7 @@
query all_trait_implementations(_: CrateNum)
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }
+ separate_provide_extern
}
query is_dllimport_foreign_item(def_id: DefId) -> bool {
@@ -1406,6 +1453,7 @@
query visibility(def_id: DefId) -> ty::Visibility {
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Computes the set of modules from which this type is visibly uninhabited.
@@ -1420,13 +1468,18 @@
query dep_kind(_: CrateNum) -> CrateDepKind {
eval_always
desc { "fetching what a dependency looks like" }
+ separate_provide_extern
}
+
+ /// Gets the name of the crate.
query crate_name(_: CrateNum) -> Symbol {
eval_always
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) }
+ separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
@@ -1440,6 +1493,7 @@
query defined_lib_features(_: CrateNum)
-> &'tcx [(Symbol, Option<Symbol>)] {
desc { "calculating the lib features defined in a crate" }
+ separate_provide_extern
}
/// Returns the lang items defined in another crate by loading it from metadata.
query get_lang_items(_: ()) -> LanguageItems {
@@ -1458,16 +1512,19 @@
/// Returns the lang items defined in another crate by loading it from metadata.
query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
desc { "calculating the lang items defined in a crate" }
+ separate_provide_extern
}
/// Returns the diagnostic items defined in a crate.
query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
storage(ArenaCacheSelector<'tcx>)
desc { "calculating the diagnostic items map in a crate" }
+ separate_provide_extern
}
query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
desc { "calculating the missing lang items in a crate" }
+ separate_provide_extern
}
query visible_parent_map(_: ()) -> DefIdMap<DefId> {
storage(ArenaCacheSelector<'tcx>)
@@ -1480,10 +1537,12 @@
query missing_extern_crate_item(_: CrateNum) -> bool {
eval_always
desc { "seeing if we're missing an `extern crate` item for this crate" }
+ separate_provide_extern
}
query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
eval_always
desc { "looking at the source for a crate" }
+ separate_provide_extern
}
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
eval_always
@@ -1494,6 +1553,7 @@
query is_private_dep(c: CrateNum) -> bool {
eval_always
desc { "check whether crate {} is a private dependency", c }
+ separate_provide_extern
}
query allocator_kind(_: ()) -> Option<AllocatorKind> {
eval_always
@@ -1502,7 +1562,6 @@
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
- eval_always
}
query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
@@ -1539,6 +1598,7 @@
query exported_symbols(_: CrateNum)
-> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
desc { "exported_symbols" }
+ separate_provide_extern
}
query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
@@ -1564,6 +1624,7 @@
|tcx| "determining which generic parameters are unused by `{}`",
tcx.def_path_str(key.def_id())
}
+ separate_provide_extern
}
query backend_optimization_level(_: ()) -> OptLevel {
desc { "optimization level used by backend" }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index b089ae2..49a64cb2 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -7,6 +7,7 @@
pub mod select;
pub mod specialization_graph;
mod structural_impls;
+pub mod util;
use crate::infer::canonical::Canonical;
use crate::thir::abstract_const::NotConstEvaluatable;
@@ -23,6 +24,7 @@
use std::borrow::Cow;
use std::fmt;
+use std::hash::{Hash, Hasher};
use std::ops::Deref;
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
@@ -108,7 +110,7 @@
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift)]
pub struct ObligationCauseData<'tcx> {
pub span: Span,
@@ -123,6 +125,14 @@
pub code: ObligationCauseCode<'tcx>,
}
+impl Hash for ObligationCauseData<'_> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.body_id.hash(state);
+ self.span.hash(state);
+ std::mem::discriminant(&self.code).hash(state);
+ }
+}
+
impl<'tcx> ObligationCause<'tcx> {
#[inline]
pub fn new(
@@ -267,14 +277,12 @@
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplMethodObligation {
- item_name: Symbol,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplTypeObligation {
- item_name: Symbol,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
@@ -440,16 +448,28 @@
#[derive(Clone, Debug, TypeFoldable, Lift)]
pub enum SelectionError<'tcx> {
+ /// The trait is not implemented.
Unimplemented,
+ /// After a closure impl has selected, its "outputs" were evaluated
+ /// (which for closures includes the "input" type params) and they
+ /// didn't resolve. See `confirm_poly_trait_refs` for more.
OutputTypeParameterMismatch(
ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>,
),
+ /// The trait pointed by `DefId` is not object safe.
TraitNotObjectSafe(DefId),
+ /// A given constant couldn't be evaluated.
NotConstEvaluatable(NotConstEvaluatable),
+ /// Exceeded the recursion depth during type projection.
Overflow,
+ /// Signaling that an error has already been emitted, to avoid
+ /// multiple errors being shown.
ErrorReporting,
+ /// Multiple applicable `impl`s where found. The `DefId`s correspond to
+ /// all the `impl`s' Items.
+ Ambiguous(Vec<DefId>),
}
/// When performing resolution, it is typically the case that there
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 6720493..5606605 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -12,12 +12,14 @@
use rustc_query_system::cache::Cache;
pub type SelectionCache<'tcx> = Cache<
- ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
+ (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
>;
-pub type EvaluationCache<'tcx> =
- Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>;
+pub type EvaluationCache<'tcx> = Cache<
+ (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
+ EvaluationResult,
+>;
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
@@ -101,7 +103,7 @@
/// `false` if there are no *further* obligations.
has_nested: bool,
},
- ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
+ ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
new file mode 100644
index 0000000..3490c68
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -0,0 +1,49 @@
+use rustc_data_structures::stable_set::FxHashSet;
+
+use crate::ty::{PolyTraitRef, TyCtxt};
+
+/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
+///
+/// A simplfied version of the same function at `rustc_infer::traits::util::supertraits`.
+pub fn supertraits<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: PolyTraitRef<'tcx>,
+) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
+ Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
+}
+
+struct Elaborator<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ visited: FxHashSet<PolyTraitRef<'tcx>>,
+ stack: Vec<PolyTraitRef<'tcx>>,
+}
+
+impl<'tcx> Elaborator<'tcx> {
+ fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
+ let supertrait_refs = self
+ .tcx
+ .super_predicates_of(trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .flat_map(|(pred, _)| {
+ pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_ref()
+ })
+ .map(|t| t.value)
+ .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
+
+ self.stack.extend(supertrait_refs);
+ }
+}
+
+impl<'tcx> Iterator for Elaborator<'tcx> {
+ type Item = PolyTraitRef<'tcx>;
+
+ fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
+ if let Some(trait_ref) = self.stack.pop() {
+ self.elaborate(trait_ref);
+ Some(trait_ref)
+ } else {
+ None
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 434008e..3f2b987 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -417,17 +417,17 @@
macro_rules! impl_arena_allocatable_decoder {
([]$args:tt) => {};
([decode $(, $attrs:ident)*]
- [[$name:ident: $ty:ty], $tcx:lifetime]) => {
- impl<$tcx, D: TyDecoder<$tcx>> RefDecodable<$tcx, D> for $ty {
+ [$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) -> Result<&'tcx Self, D::Error> {
decode_arena_allocable(decoder)
}
}
- impl<$tcx, D: TyDecoder<$tcx>> RefDecodable<$tcx, D> for [$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) -> Result<&'tcx Self, D::Error> {
decode_arena_allocable_slice(decoder)
}
}
@@ -438,15 +438,15 @@
}
macro_rules! impl_arena_allocatable_decoders {
- ([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
+ ([$($a:tt $name:ident: $ty:ty,)*]) => {
$(
- impl_arena_allocatable_decoder!($a [[$name: $ty], $tcx]);
+ impl_arena_allocatable_decoder!($a [$name: $ty]);
)*
}
}
-rustc_hir::arena_types!(impl_arena_allocatable_decoders, 'tcx);
-arena_types!(impl_arena_allocatable_decoders, 'tcx);
+rustc_hir::arena_types!(impl_arena_allocatable_decoders);
+arena_types!(impl_arena_allocatable_decoders);
#[macro_export]
macro_rules! implement_ty_decoder {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 869b2ab..27e22cc 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,7 +1,9 @@
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ParamEnv, ParamEnvAnd};
+use crate::ty::{
+ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+ TyCtxt, TypeFoldable,
+};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -54,6 +56,24 @@
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 {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: def.to_global(),
+ substs_: None,
+ promoted: None,
+ }),
+ ty,
+ }),
+ }
+ }
+
+ fn try_eval_lit_or_param(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Option<&'tcx Self> {
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 {
@@ -69,7 +89,7 @@
// 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 c;
+ return Some(c);
} else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
}
@@ -85,7 +105,7 @@
};
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
- let val = match expr.kind {
+ match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
@@ -95,16 +115,53 @@
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);
- ty::ConstKind::Param(ty::ParamConst::new(index, name))
+ Some(tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+ ty,
+ }))
}
- _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: def.to_global(),
- substs_: None,
- promoted: None,
- }),
+ _ => None,
+ }
+ }
+
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+ debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ let body_id = match tcx.hir().get(hir_id) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def_id.to_def_id()),
+ "from_inline_const can only process anonymous constants"
+ ),
};
- tcx.mk_const(ty::Const { val, ty })
+ let expr = &tcx.hir().body(body_id).value;
+
+ let ty = tcx.typeck(def_id).node_type(hir_id);
+
+ let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+ tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: ty::WithOptConstParam::unknown(def_id).to_global(),
+ substs_: Some(substs),
+ promoted: None,
+ }),
+ ty,
+ })
+ }
+ };
+ debug_assert!(!ret.has_free_regions(tcx));
+ ret
}
/// Interns the given value as a constant.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 83d7c30..8240273 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1,7 +1,7 @@
//! Type context book-keeping.
use crate::arena::Arena;
-use crate::dep_graph::DepGraph;
+use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
@@ -79,11 +79,6 @@
where
Self: Sized;
- /// 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`.
- fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId;
-
fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult;
@@ -1016,6 +1011,7 @@
pub queries: &'tcx dyn query::QueryEngine<'tcx>,
pub query_caches: query::QueryCaches<'tcx>,
+ query_kinds: &'tcx [DepKindStruct],
// Internal caches for metadata decoding. No need to track deps on this.
pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1149,6 +1145,7 @@
dep_graph: DepGraph,
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
queries: &'tcx dyn query::QueryEngine<'tcx>,
+ query_kinds: &'tcx [DepKindStruct],
crate_name: &str,
output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
@@ -1175,6 +1172,7 @@
on_disk_cache,
queries,
query_caches: query::QueryCaches::default(),
+ query_kinds,
ty_rcache: Default::default(),
pred_rcache: Default::default(),
selection_cache: Default::default(),
@@ -1188,6 +1186,10 @@
}
}
+ crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+ &self.query_kinds[k as usize]
+ }
+
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
#[track_caller]
pub fn ty_error(self) -> Ty<'tcx> {
@@ -1301,6 +1303,27 @@
}
}
+ /// 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 {
+ debug!("def_path_hash_to_def_id({:?})", hash);
+
+ let stable_crate_id = hash.stable_crate_id();
+
+ // 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()
+ } else {
+ // If this is a DefPathHash from an upstream crate, let the CrateStore map
+ // it to a DefId.
+ let cstore = &self.untracked_resolutions.cstore;
+ let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
+ cstore.def_path_hash_to_def_id(cnum, hash)
+ }
+ }
+
pub fn def_path_debug_str(self, def_id: DefId) -> String {
// We are explicitly not going through queries here in order to get
// crate name and stable crate id since this code is called from debug!()
@@ -1337,20 +1360,15 @@
#[inline(always)]
pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
- let krate = self.gcx.untracked_crate;
let resolutions = &self.gcx.untracked_resolutions;
-
- StableHashingContext::new(self.sess, krate, &resolutions.definitions, &*resolutions.cstore)
+ StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore)
}
#[inline(always)]
pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
- let krate = self.gcx.untracked_crate;
let resolutions = &self.gcx.untracked_resolutions;
-
StableHashingContext::ignore_spans(
self.sess,
- krate,
&resolutions.definitions,
&*resolutions.cstore,
)
@@ -2823,7 +2841,8 @@
}
pub fn provide(providers: &mut ty::query::Providers) {
- providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
+ 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.crate_name = |tcx, id| {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 092eae0..1b32c8a 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -221,9 +221,7 @@
) -> bool {
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
- let param = if let Some(param) = param {
- param
- } else {
+ let Some(param) = param else {
return false;
};
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 08b4d3a..b14a698 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -34,6 +34,7 @@
pub enum TypeError<'tcx> {
Mismatch,
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
+ PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
@@ -41,6 +42,7 @@
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<u64>),
ArgCount,
+ FieldMisMatch(Symbol, Symbol),
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
@@ -104,6 +106,9 @@
ConstnessMismatch(values) => {
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
}
+ PolarityMismatch(values) => {
+ write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
+ }
UnsafetyMismatch(values) => {
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
}
@@ -130,6 +135,7 @@
pluralize!(values.found)
),
ArgCount => write!(f, "incorrect number of function parameters"),
+ FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
RegionsInsufficientlyPolymorphic(br, _) => write!(
f,
@@ -212,15 +218,15 @@
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
- | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
- | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => {
- false
- }
+ | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
+ | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
+ | VariadicMismatch(_) | TargetFeatureCast(_) => false,
Mutability
| ArgumentMutability(_)
| TupleSize(_)
| ArgCount
+ | FieldMisMatch(..)
| RegionsDoesNotOutlive(..)
| RegionsInsufficientlyPolymorphic(..)
| RegionsOverlyPolymorphic(..)
@@ -769,11 +775,16 @@
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
- let opaque_local_def_id = def_id.expect_local();
- let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
- let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
- hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
- _ => bug!("The HirId comes from a `ty::Opaque`"),
+ let opaque_local_def_id = def_id.as_local();
+ let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
+ let hir = self.hir();
+ let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id);
+ match &hir.expect_item(opaque_hir_id).kind {
+ hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+ _ => bug!("The HirId comes from a `ty::Opaque`"),
+ }
+ } else {
+ return false;
};
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 0f89581..f53f187 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -3,7 +3,6 @@
use crate::ty::subst::{Subst, SubstsRef};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
@@ -13,14 +12,8 @@
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum GenericParamDefKind {
Lifetime,
- Type {
- has_default: bool,
- object_lifetime_default: ObjectLifetimeDefault,
- synthetic: Option<hir::SyntheticTyParamKind>,
- },
- Const {
- has_default: bool,
- },
+ Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
+ Const { has_default: bool },
}
impl GenericParamDefKind {
@@ -202,15 +195,7 @@
/// Returns `true` if `params` has `impl Trait`.
pub fn has_impl_trait(&'tcx self) -> bool {
self.params.iter().any(|param| {
- matches!(
- param.kind,
- ty::GenericParamDefKind::Type {
- synthetic: Some(
- hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
- ),
- ..
- }
- )
+ matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
})
}
}
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d0c7379..b87e23a 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -755,17 +755,14 @@
}
// Extract the number of elements from the layout of the array field:
- let len = if let Ok(TyAndLayout {
+ let Ok(TyAndLayout {
layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
..
- }) = self.layout_of(f0_ty)
- {
- count
- } else {
+ }) = self.layout_of(f0_ty) else {
return Err(LayoutError::Unknown(ty));
};
- (*e_ty, *len, true)
+ (*e_ty, *count, true)
} else {
// First ADT field is not an array:
(f0_ty, def.non_enum_variant().fields.len() as _, false)
@@ -787,9 +784,7 @@
// Compute the ABI of the element type:
let e_ly = self.layout_of(e_ty)?;
- let e_abi = if let Abi::Scalar(scalar) = e_ly.abi {
- scalar
- } else {
+ let Abi::Scalar(e_abi) = e_ly.abi else {
// This error isn't caught in typeck, e.g., if
// the element type of the vector is generic.
tcx.sess.fatal(&format!(
@@ -3065,9 +3060,10 @@
// LLVM's definition of `noalias` is based solely on memory
// dependencies rather than pointer equality
//
- // Due to miscompiles in LLVM < 12, we apply a separate NoAliasMutRef attribute
- // for UniqueBorrowed arguments, so that the codegen backend can decide
- // whether or not to actually emit the attribute.
+ // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+ // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled with the
+ // `-Zmutable-noalias` debugging option.
let no_alias = match kind {
PointerKind::Shared | PointerKind::UniqueBorrowed => false,
PointerKind::UniqueOwned => true,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 20d07bd..673733f 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -74,9 +74,10 @@
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
- GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
- PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
- RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+ GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
+ ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
+ PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
+ UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
};
pub use self::trait_def::TraitDef;
@@ -164,7 +165,18 @@
pub predicates: Vec<Predicate<'tcx>>,
}
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(
+ Copy,
+ Clone,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ HashStable,
+ Debug,
+ TypeFoldable
+)]
pub enum ImplPolarity {
/// `impl Trait for Type`
Positive,
@@ -177,6 +189,27 @@
Reservation,
}
+impl ImplPolarity {
+ /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
+ pub fn flip(&self) -> Option<ImplPolarity> {
+ match self {
+ ImplPolarity::Positive => Some(ImplPolarity::Negative),
+ ImplPolarity::Negative => Some(ImplPolarity::Positive),
+ ImplPolarity::Reservation => None,
+ }
+ }
+}
+
+impl fmt::Display for ImplPolarity {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Positive => f.write_str("positive"),
+ Self::Negative => f.write_str("negative"),
+ Self::Reservation => f.write_str("reservation"),
+ }
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
pub enum Visibility {
/// Visible everywhere (including in other crates).
@@ -300,6 +333,10 @@
Visibility::Invisible => false,
}
}
+
+ pub fn is_public(self) -> bool {
+ matches!(self, Visibility::Public)
+ }
}
/// The crate variances map is computed during typeck and contains the
@@ -459,6 +496,29 @@
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
self.inner.kind
}
+
+ /// 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>> {
+ let kind = self
+ .inner
+ .kind
+ .map_bound(|kind| match kind {
+ PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
+ Some(PredicateKind::Trait(TraitPredicate {
+ trait_ref,
+ constness,
+ polarity: polarity.flip()?,
+ }))
+ }
+
+ _ => None,
+ })
+ .transpose()?;
+
+ Some(tcx.mk_predicate(kind))
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
@@ -654,6 +714,8 @@
pub trait_ref: TraitRef<'tcx>,
pub constness: BoundConstness,
+
+ pub polarity: ImplPolarity,
}
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
@@ -788,7 +850,11 @@
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.value
.map_bound(|trait_ref| {
- PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness })
+ PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: self.constness,
+ polarity: ty::ImplPolarity::Positive,
+ })
})
.to_predicate(tcx)
}
@@ -1866,7 +1932,8 @@
| DefKind::Static
| DefKind::AssocConst
| DefKind::Ctor(..)
- | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+ | DefKind::AnonConst
+ | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 2610a76..175295b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -350,18 +350,26 @@
match self.tcx().extern_crate(def_id) {
Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
(ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
- debug!("try_print_visible_def_path: def_id={:?}", def_id);
- return Ok((
- if !span.is_dummy() {
- self.print_def_path(def_id, &[])?
- } else {
- self.path_crate(cnum)?
- },
- true,
- ));
+ // NOTE(eddyb) the only reason `span` might be dummy,
+ // that we're aware of, is that it's the `std`/`core`
+ // `extern crate` injected by default.
+ // FIXME(eddyb) find something better to key this on,
+ // or avoid ending up with `ExternCrateSource::Extern`,
+ // for the injected `std`/`core`.
+ if span.is_dummy() {
+ return Ok((self.path_crate(cnum)?, true));
+ }
+
+ // Disable `try_print_trimmed_def_path` behavior within
+ // the `print_def_path` call, to avoid infinite recursion
+ // in cases where the `extern crate foo` has non-trivial
+ // parents, e.g. it's nested in `impl foo::Trait for Bar`
+ // (see also issues #55779 and #87932).
+ self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?;
+
+ return Ok((self, true));
}
(ExternCrateSource::Path, LOCAL_CRATE) => {
- debug!("try_print_visible_def_path: def_id={:?}", def_id);
return Ok((self.path_crate(cnum)?, true));
}
_ => {}
@@ -635,37 +643,8 @@
}
return Ok(self);
}
- // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
- // by looking up the projections associated with the def_id.
- let bounds = self.tcx().explicit_item_bounds(def_id);
- let mut first = true;
- let mut is_sized = false;
- p!("impl");
- for (predicate, _) in bounds {
- let predicate = predicate.subst(self.tcx(), substs);
- let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() {
- let trait_ref = bound_predicate.rebind(pred.trait_ref);
- // Don't print +Sized, but rather +?Sized if absent.
- if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
- is_sized = true;
- continue;
- }
-
- p!(
- write("{}", if first { " " } else { "+" }),
- print(trait_ref.print_only_trait_path())
- );
- first = false;
- }
- }
- if !is_sized {
- p!(write("{}?Sized", if first { " " } else { "+" }));
- } else if first {
- p!(" Sized");
- }
- Ok(self)
+ self.pretty_print_opaque_impl_type(def_id, substs)
});
}
ty::Str => p!("str"),
@@ -736,6 +715,7 @@
p!(print_def_path(did, substs));
if !substs.as_closure().is_valid() {
p!(" closure_substs=(unavailable)");
+ p!(write(" substs={:?}", substs));
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
@@ -773,6 +753,225 @@
Ok(self)
}
+ fn pretty_print_opaque_impl_type(
+ mut self,
+ def_id: DefId,
+ substs: &'tcx ty::List<ty::GenericArg<'tcx>>,
+ ) -> Result<Self::Type, Self::Error> {
+ define_scoped_cx!(self);
+
+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+ // by looking up the projections associated with the def_id.
+ let bounds = self.tcx().explicit_item_bounds(def_id);
+
+ let mut traits = BTreeMap::new();
+ let mut fn_traits = BTreeMap::new();
+ let mut is_sized = false;
+
+ for (predicate, _) in bounds {
+ let predicate = predicate.subst(self.tcx(), substs);
+ let bound_predicate = predicate.kind();
+
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ let trait_ref = bound_predicate.rebind(pred.trait_ref);
+
+ // Don't print + Sized, but rather + ?Sized if absent.
+ if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
+ is_sized = true;
+ continue;
+ }
+
+ self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
+ }
+ ty::PredicateKind::Projection(pred) => {
+ let proj_ref = bound_predicate.rebind(pred);
+ 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());
+
+ self.insert_trait_and_projection(
+ trait_ref,
+ Some(proj_ty),
+ &mut traits,
+ &mut fn_traits,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ let mut first = true;
+ // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
+ let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
+
+ p!("impl");
+
+ for (fn_once_trait_ref, entry) in fn_traits {
+ // Get the (single) generic ty (the args) of this FnOnce trait ref.
+ let generics = self.generic_args_to_print(
+ self.tcx().generics_of(fn_once_trait_ref.def_id()),
+ fn_once_trait_ref.skip_binder().substs,
+ );
+
+ match (entry.return_ty, generics[0].expect_ty()) {
+ // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
+ // a return type.
+ (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
+ let name = if entry.fn_trait_ref.is_some() {
+ "Fn"
+ } else if entry.fn_mut_trait_ref.is_some() {
+ "FnMut"
+ } else {
+ "FnOnce"
+ };
+
+ p!(
+ write("{}", if first { " " } else { " + " }),
+ write("{}{}(", if paren_needed { "(" } else { "" }, name)
+ );
+
+ for (idx, ty) in arg_tys.tuple_fields().enumerate() {
+ if idx > 0 {
+ p!(", ");
+ }
+ p!(print(ty));
+ }
+
+ p!(")");
+ if !return_ty.skip_binder().is_unit() {
+ p!("-> ", print(return_ty));
+ }
+ p!(write("{}", if paren_needed { ")" } else { "" }));
+
+ first = false;
+ }
+ // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
+ // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
+ _ => {
+ if entry.has_fn_once {
+ traits.entry(fn_once_trait_ref).or_default().extend(
+ // Group the return ty with its def id, if we had one.
+ entry
+ .return_ty
+ .map(|ty| (self.tcx().lang_items().fn_once_output().unwrap(), ty)),
+ );
+ }
+ if let Some(trait_ref) = entry.fn_mut_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ if let Some(trait_ref) = entry.fn_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ }
+ }
+ }
+
+ // Print the rest of the trait types (that aren't Fn* family of traits)
+ for (trait_ref, assoc_items) in traits {
+ p!(
+ write("{}", if first { " " } else { " + " }),
+ print(trait_ref.skip_binder().print_only_trait_name())
+ );
+
+ let generics = self.generic_args_to_print(
+ self.tcx().generics_of(trait_ref.def_id()),
+ trait_ref.skip_binder().substs,
+ );
+
+ if !generics.is_empty() || !assoc_items.is_empty() {
+ p!("<");
+ let mut first = true;
+
+ for ty in generics {
+ if !first {
+ p!(", ");
+ }
+ p!(print(trait_ref.rebind(*ty)));
+ first = false;
+ }
+
+ for (assoc_item_def_id, ty) in assoc_items {
+ if !first {
+ p!(", ");
+ }
+ p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
+
+ // 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]")
+ }
+ _ => {
+ p!(print(ty))
+ }
+ }
+
+ first = false;
+ }
+
+ p!(">");
+ }
+
+ first = false;
+ }
+
+ if !is_sized {
+ p!(write("{}?Sized", if first { " " } else { " + " }));
+ } else if first {
+ p!(" Sized");
+ }
+
+ Ok(self)
+ }
+
+ /// Insert the trait ref and optionally a projection type associated with it into either the
+ /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
+ 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>>>>,
+ fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+ ) {
+ let trait_def_id = trait_ref.def_id();
+
+ // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
+ // super-trait ref and record it there.
+ if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
+ // If we have a FnOnce, then insert it into
+ if trait_def_id == fn_once_trait {
+ let entry = fn_traits.entry(trait_ref).or_default();
+ // Optionally insert the return_ty as well.
+ if let Some((_, ty)) = proj_ty {
+ entry.return_ty = Some(ty);
+ }
+ entry.has_fn_once = true;
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_mut_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref);
+ return;
+ }
+ }
+
+ // Otherwise, just group our traits and projection types.
+ traits.entry(trait_ref).or_default().extend(proj_ty);
+ }
+
fn pretty_print_bound_var(
&mut self,
debruijn: ty::DebruijnIndex,
@@ -2395,7 +2594,7 @@
// Iterate external crate defs but be mindful about visibility
while let Some(def) = queue.pop() {
for child in tcx.item_children(def).iter() {
- if child.vis != ty::Visibility::Public {
+ if !child.vis.is_public() {
continue;
}
@@ -2500,3 +2699,12 @@
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { trimmed_def_paths, ..*providers };
}
+
+#[derive(Default)]
+pub struct OpaqueFnEntry<'tcx> {
+ // The trait ref is already stored as a key, so just track if we have it as a real predicate
+ 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>>>,
+}
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index b1bc073..34f8062 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -102,6 +102,10 @@
}
}
+/// Helper for `TyCtxtEnsure` to avoid a closure.
+#[inline(always)]
+fn noop<T>(_: &T) {}
+
macro_rules! query_helper_param_ty {
(DefId) => { impl IntoQueryParam<DefId> };
($K:ty) => { $K };
@@ -119,6 +123,39 @@
};
}
+macro_rules! separate_provide_extern_decl {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ for<'tcx> fn(
+ TyCtxt<'tcx>,
+ query_keys::$name<'tcx>,
+ ) -> query_values::$name<'tcx>
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_decl!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! separate_provide_extern_default {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ |_, key| bug!(
+ "`tcx.{}({:?})` unsupported by its crate; \
+ perhaps the `{}` query was never assigned a provider function",
+ stringify!($name),
+ key,
+ stringify!($name),
+ )
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_default!([$($modifiers)*][$($args)*])
+ };
+}
+
macro_rules! define_callbacks {
(<$tcx:tt>
$($(#[$attr:meta])*
@@ -165,7 +202,7 @@
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
let key = key.into_query_param();
- let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {});
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
let lookup = match cached {
Ok(()) => return,
@@ -192,9 +229,7 @@
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
{
let key = key.into_query_param();
- let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| {
- value.clone()
- });
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
let lookup = match cached {
Ok(value) => return value,
@@ -212,6 +247,10 @@
) -> query_values::$name<'tcx>,)*
}
+ pub struct ExternProviders {
+ $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
+ }
+
impl Default for Providers {
fn default() -> Self {
Providers {
@@ -226,11 +265,24 @@
}
}
+ impl Default for ExternProviders {
+ fn default() -> Self {
+ ExternProviders {
+ $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
+ }
+ }
+ }
+
impl Copy for Providers {}
impl Clone for Providers {
fn clone(&self) -> Self { *self }
}
+ impl Copy for ExternProviders {}
+ impl Clone for ExternProviders {
+ fn clone(&self) -> Self { *self }
+ }
+
pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 2c78653..c7d8bec 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -187,8 +187,12 @@
})
.enumerate()
.map(|(i, r)| match r {
- Err(TypeError::Sorts(exp_found)) => Err(TypeError::ArgumentSorts(exp_found, i)),
- Err(TypeError::Mutability) => Err(TypeError::ArgumentMutability(i)),
+ Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
+ Err(TypeError::ArgumentSorts(exp_found, i))
+ }
+ Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
+ Err(TypeError::ArgumentMutability(i))
+ }
r => r,
});
Ok(ty::FnSig {
@@ -797,6 +801,20 @@
}
}
+impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::ImplPolarity,
+ b: ty::ImplPolarity,
+ ) -> RelateResult<'tcx, ty::ImplPolarity> {
+ if a != b {
+ Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+}
+
impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
@@ -806,6 +824,7 @@
Ok(ty::TraitPredicate {
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
constness: relation.relate(a.constness, b.constness)?,
+ polarity: relation.relate(a.polarity, b.polarity)?,
})
}
}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 8f343ba9..0f8e808 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -157,7 +157,7 @@
if let ty::BoundConstness::ConstIfConst = self.constness {
write!(f, "~const ")?;
}
- write!(f, "TraitPredicate({:?})", self.trait_ref)
+ write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
}
}
@@ -365,8 +365,11 @@
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
type Lifted = ty::TraitPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
- tcx.lift(self.trait_ref)
- .map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness })
+ tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness: self.constness,
+ polarity: self.polarity,
+ })
}
}
@@ -591,6 +594,7 @@
Some(match self {
Mismatch => Mismatch,
ConstnessMismatch(x) => ConstnessMismatch(x),
+ PolarityMismatch(x) => PolarityMismatch(x),
UnsafetyMismatch(x) => UnsafetyMismatch(x),
AbiMismatch(x) => AbiMismatch(x),
Mutability => Mutability,
@@ -598,6 +602,7 @@
TupleSize(x) => TupleSize(x),
FixedArraySize(x) => FixedArraySize(x),
ArgCount => ArgCount,
+ FieldMisMatch(x, y) => FieldMisMatch(x, y),
RegionsDoesNotOutlive(a, b) => {
return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index d3094b3..c2b32cd 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -704,6 +704,66 @@
}
}
+/// An inline const is modeled like
+///
+/// const InlineConst<'l0...'li, T0...Tj, R>: R;
+///
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+/// inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct InlineConstSubsts<'tcx> {
+ /// Generic parameters from the enclosing item,
+ /// concatenated with the inferred type of the constant.
+ pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+ /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+ ),
+ }
+ }
+
+ /// Divides the inline const substs into their respective components.
+ /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+ fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+ _ => bug!("inline const substs missing synthetics"),
+ }
+ }
+
+ /// Returns the substitutions of the inline const's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// Returns the type of this inline const.
+ pub fn ty(self) -> Ty<'tcx> {
+ self.split().ty.expect_ty()
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum ExistentialPredicate<'tcx> {
@@ -830,7 +890,7 @@
///
/// Trait references also appear in object types like `Foo<U>`, but in
/// that case the `Self` parameter is absent from the substitutions.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub struct TraitRef<'tcx> {
pub def_id: DefId,
@@ -882,6 +942,7 @@
self.map_bound(|trait_ref| ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
})
}
}
@@ -1744,10 +1805,13 @@
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");
let variant = def.non_enum_variant();
let f0_ty = variant.fields[0].ty(tcx, substs);
match f0_ty.kind() {
+ // If the first field is an array, we assume it is the only field and its
+ // elements are the SIMD components.
Array(f0_elem_ty, f0_len) => {
// FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
// The way we evaluate the `N` in `[T; N]` here only works since we use
@@ -1755,6 +1819,8 @@
// 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)
}
+ // Otherwise, the fields of this Adt are the SIMD components (and we assume they
+ // all have the same type).
_ => (variant.fields.len() as u64, f0_ty),
}
}
@@ -2006,7 +2072,9 @@
) -> Option<Discr<'tcx>> {
match self.kind() {
TyKind::Adt(adt, _) if adt.variants.is_empty() => {
- bug!("discriminant_for_variant called on zero variant enum");
+ // This can actually happen during CTFE, see
+ // https://github.com/rust-lang/rust/issues/89765.
+ None
}
TyKind::Adt(adt, _) if adt.is_enum() => {
Some(adt.discriminant_for_variant(tcx, variant_index))
@@ -2025,10 +2093,10 @@
ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => {
- let assoc_items =
- tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
- let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
- tcx.mk_projection(discriminant_def_id, tcx.mk_substs([self.into()].iter()))
+ let assoc_items = tcx.associated_item_def_ids(
+ tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
+ );
+ tcx.mk_projection(assoc_items[0], tcx.intern_substs(&[self.into()]))
}
ty::Bool
@@ -2195,10 +2263,11 @@
/// a miscompilation or unsoundness.
///
/// When in doubt, use `VarianceDiagInfo::default()`
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub enum VarianceDiagInfo<'tcx> {
/// No additional information - this is the default.
/// We will not add any additional information to error messages.
+ #[default]
None,
/// We switched our variance because a type occurs inside
/// the generic argument of a mutable reference or pointer
@@ -2233,9 +2302,3 @@
}
}
}
-
-impl<'tcx> Default for VarianceDiagInfo<'tcx> {
- fn default() -> Self {
- Self::None
- }
-}
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 2438d1a..73a8e18 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -3,7 +3,7 @@
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
@@ -204,6 +204,14 @@
GeneratorSubsts { substs: self }
}
+ /// Interpret these substitutions as the substitutions of an inline const.
+ /// Inline const substitutions have a particular structure controlled by the
+ /// compiler that encodes information like the inferred type;
+ /// see `ty::InlineConstSubsts` struct for more comments.
+ pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts { substs: self }
+ }
+
/// Creates an `InternalSubsts` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 2c88481..6e7acb2 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -325,9 +325,9 @@
let ty = self.type_of(adt_did);
let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
- if let Some(item) = self.associated_items(impl_did).in_definition_order().next() {
+ if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
if validate(self, impl_did).is_ok() {
- return Some((item.def_id, self.impl_constness(impl_did)));
+ return Some((*item_id, self.impl_constness(impl_did)));
}
}
None
@@ -423,6 +423,15 @@
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
}
+ /// Returns `true` if `def_id` refers to a definition that does not have its own
+ /// type-checking context, i.e. closure, generator or inline const.
+ pub fn is_typeck_child(self, def_id: DefId) -> bool {
+ matches!(
+ self.def_kind(def_id),
+ DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+ )
+ }
+
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Trait
@@ -440,16 +449,19 @@
matches!(self.def_kind(def_id), DefKind::Ctor(..))
}
- /// Given the def-ID of a fn or closure, returns the def-ID of
- /// the innermost fn item that the closure is contained within.
- /// This is a significant `DefId` because, when we do
- /// type-checking, we type-check this fn item and all of its
- /// (transitive) closures together. Therefore, when we fetch the
+ /// Given the `DefId`, returns the `DefId` of the innermost item that
+ /// has its own type-checking context or "inference enviornment".
+ ///
+ /// For example, a closure has its own `DefId`, but it is type-checked
+ /// with the containing item. Similarly, an inline const block has its
+ /// own `DefId` but it is type-checked together with the containing item.
+ ///
+ /// Therefore, when we fetch the
/// `typeck` the closure, for example, we really wind up
/// fetching the `typeck` the enclosing fn item.
- pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
+ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
let mut def_id = def_id;
- while self.is_closure(def_id) {
+ while self.is_typeck_child(def_id) {
def_id = self.parent(def_id).unwrap_or_else(|| {
bug!("closure {:?} has no parent", def_id);
});
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
index da857b0..0897704 100644
--- a/compiler/rustc_middle/src/util/common.rs
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -34,7 +34,7 @@
let rv = f();
let duration = start.elapsed();
let mut accu = accu.lock();
- *accu = *accu + duration;
+ *accu += duration;
rv
}
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 05995dd..c6a34ec 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -221,15 +221,13 @@
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 (capture_index, capture) = if let Some(capture_details) =
+ let Some((capture_index, capture)) =
find_capture_matching_projections(
typeck_results,
var_hir_id,
closure_def_id,
&from_builder.projection,
- ) {
- capture_details
- } else {
+ ) else {
if !enable_precise_capture(tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 4df073c..e3a05e0 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1606,13 +1606,12 @@
// encounter a candidate where the test is not relevant; at
// that point, we stop sorting.
while let Some(candidate) = candidates.first_mut() {
- if let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) {
- let (candidate, rest) = candidates.split_first_mut().unwrap();
- target_candidates[idx].push(candidate);
- candidates = rest;
- } else {
+ let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) else {
break;
- }
+ };
+ let (candidate, rest) = candidates.split_first_mut().unwrap();
+ target_candidates[idx].push(candidate);
+ candidates = rest;
}
// at least the first candidate ought to be tested
assert!(total_candidate_count > candidates.len());
@@ -1762,8 +1761,8 @@
) -> BlockAnd<()> {
let expr_span = expr.span;
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
- let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
let wildcard = Pat::wildcard_from_ty(pat.ty);
+ let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false);
let fake_borrow_temps = self.lower_match_tree(
block,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 4108ad5..cb94e75 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -966,59 +966,58 @@
DropKind::Value,
);
- if let Some(arg) = arg_opt {
- let pat = match tcx.hir().get(arg.pat.hir_id) {
- Node::Pat(pat) | Node::Binding(pat) => pat,
- node => bug!("pattern became {:?}", node),
- };
- let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
- let original_source_scope = self.source_scope;
- let span = pattern.span;
- self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
- match *pattern.kind {
- // Don't introduce extra copies for simple bindings
- PatKind::Binding {
- mutability,
- var,
- mode: BindingMode::ByValue,
- subpattern: None,
- ..
- } => {
- self.local_decls[local].mutability = mutability;
- self.local_decls[local].source_info.scope = self.source_scope;
- self.local_decls[local].local_info = if let Some(kind) = self_binding {
- Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
- BindingForm::ImplicitSelf(*kind),
- ))))
- } else {
- let binding_mode = ty::BindingMode::BindByValue(mutability);
- Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
- VarBindingForm {
- binding_mode,
- opt_ty_info,
- opt_match_place: Some((Some(place), span)),
- pat_span: span,
- },
- )))))
- };
- self.var_indices.insert(var, LocalsForNode::One(local));
- }
- _ => {
- scope = self.declare_bindings(
- scope,
- expr.span,
- &pattern,
- matches::ArmHasGuard(false),
- Some((Some(&place), span)),
- );
- let place_builder = PlaceBuilder::from(local);
- unpack!(
- block = self.place_into_pattern(block, pattern, place_builder, false)
- );
- }
+ let Some(arg) = arg_opt else {
+ continue;
+ };
+ let pat = match tcx.hir().get(arg.pat.hir_id) {
+ Node::Pat(pat) | Node::Binding(pat) => pat,
+ node => bug!("pattern became {:?}", node),
+ };
+ let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
+ let original_source_scope = self.source_scope;
+ let span = pattern.span;
+ self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
+ match *pattern.kind {
+ // Don't introduce extra copies for simple bindings
+ PatKind::Binding {
+ mutability,
+ var,
+ mode: BindingMode::ByValue,
+ subpattern: None,
+ ..
+ } => {
+ self.local_decls[local].mutability = mutability;
+ self.local_decls[local].source_info.scope = self.source_scope;
+ self.local_decls[local].local_info = if let Some(kind) = self_binding {
+ Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
+ BindingForm::ImplicitSelf(*kind),
+ ))))
+ } else {
+ let binding_mode = ty::BindingMode::BindByValue(mutability);
+ Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm {
+ binding_mode,
+ opt_ty_info,
+ opt_match_place: Some((Some(place), span)),
+ pat_span: span,
+ },
+ )))))
+ };
+ self.var_indices.insert(var, LocalsForNode::One(local));
}
- self.source_scope = original_source_scope;
+ _ => {
+ scope = self.declare_bindings(
+ scope,
+ expr.span,
+ &pattern,
+ matches::ArmHasGuard(false),
+ Some((Some(&place), span)),
+ );
+ let place_builder = PlaceBuilder::from(local);
+ unpack!(block = self.place_into_pattern(block, pattern, place_builder, false));
+ }
}
+ self.source_scope = original_source_scope;
}
// Enter the argument pattern bindings source scope, if it exists.
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index b74208e..8dadbf5 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -362,11 +362,7 @@
blocks: &IndexVec<DropIdx, Option<BasicBlock>>,
) {
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
- let block = if let Some(block) = blocks[drop_idx] {
- block
- } else {
- continue;
- };
+ let Some(block) = blocks[drop_idx] else { continue };
match drop_data.0.kind {
DropKind::Value => {
let terminator = TerminatorKind::Drop {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 0e82b18..7940bd1 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -256,23 +256,22 @@
}
PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => {
if self.inside_adt {
- if let ty::Ref(_, ty, _) = ty.kind() {
- match borrow_kind {
- BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
- if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
- self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
- }
- }
- BorrowKind::Mut { .. } => {
- self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
- }
- }
- } else {
+ let ty::Ref(_, ty, _) = ty.kind() else {
span_bug!(
pat.span,
"BindingMode::ByRef in pattern, but found non-reference type {}",
ty
);
+ };
+ match borrow_kind {
+ BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
+ if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
+ self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
+ }
+ }
+ BorrowKind::Mut { .. } => {
+ self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
+ }
}
}
visit::walk_pat(self, pat);
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 02023c4..b0f1e08 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -6,6 +6,7 @@
#![feature(crate_visibility_modifier)]
#![feature(bool_to_option)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(once_cell)]
#![feature(min_specialization)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index ef8bd20..e4c2d2d 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -2,7 +2,6 @@
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
use rustc_hir::intravisit::FnKind;
-use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
@@ -14,8 +13,8 @@
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_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
- if let FnKind::Closure = fn_like_node.kind() {
+ if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() {
+ if let FnKind::Closure = fn_kind {
// closures can't recur, so they don't matter.
return;
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 17296a9..b4005cc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -578,7 +578,7 @@
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
ExprKind::ConstBlock { value }
}
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 e28fd2c..d74c53f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -74,19 +74,16 @@
let (msg, sp) = match loc.source {
hir::LocalSource::Normal => ("local binding", Some(loc.span)),
- hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
hir::LocalSource::AsyncFn => ("async fn binding", None),
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
};
self.check_irrefutable(&loc.pat, msg, sp);
- self.check_patterns(&loc.pat, Irrefutable);
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
intravisit::walk_param(self, param);
self.check_irrefutable(¶m.pat, "function argument", None);
- self.check_patterns(¶m.pat, Irrefutable);
}
}
@@ -161,12 +158,12 @@
fn check_match(
&mut self,
scrut: &hir::Expr<'_>,
- arms: &'tcx [hir::Arm<'tcx>],
+ hir_arms: &'tcx [hir::Arm<'tcx>],
source: hir::MatchSource,
) {
let mut cx = self.new_cx(scrut.hir_id);
- for arm in arms {
+ for arm in hir_arms {
// Check the arm for some things unrelated to exhaustiveness.
self.check_patterns(&arm.pat, Refutable);
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
@@ -178,7 +175,7 @@
let mut have_errors = false;
- let arms: Vec<_> = arms
+ let arms: Vec<_> = hir_arms
.iter()
.map(|hir::Arm { pat, guard, .. }| MatchArm {
pat: self.lower_pattern(&mut cx, pat, &mut have_errors),
@@ -196,6 +193,9 @@
let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
match source {
+ // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
+ // when the iterator is an uninhabited type. unreachable_code will trigger instead.
+ hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
report_arm_reachability(&cx, &report)
}
@@ -208,7 +208,13 @@
let is_empty_match = arms.is_empty();
let witnesses = report.non_exhaustiveness_witnesses;
if !witnesses.is_empty() {
- non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+ if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
+ // the for loop pattern is not irrefutable
+ let pat = hir_arms[1].pat.for_loop_some().unwrap();
+ self.check_irrefutable(pat, "`for` loop binding", None);
+ } else {
+ non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+ }
}
}
@@ -225,6 +231,7 @@
let witnesses = report.non_exhaustiveness_witnesses;
if witnesses.is_empty() {
// The pattern is irrefutable.
+ self.check_patterns(pat, Irrefutable);
return;
}
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 847b89f..dd16e3c 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
@@ -130,6 +130,9 @@
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()
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index cb74ae4..ce80214 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -544,7 +544,7 @@
let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
if matches!(value.val, ConstKind::Param(_)) {
let span = self.tcx.hir().span(anon_const.hir_id);
self.errors.push(PatternError::ConstParamInPattern(span));
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index d959d2f..286473c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -289,6 +289,7 @@
use rustc_data_structures::captures::Captures;
use rustc_arena::TypedArena;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -443,9 +444,7 @@
/// expands it.
fn push(&mut self, row: PatStack<'p, 'tcx>) {
if !row.is_empty() && row.head().is_or_pat() {
- for row in row.expand_or_pat() {
- self.patterns.push(row);
- }
+ self.patterns.extend(row.expand_or_pat());
} else {
self.patterns.push(row);
}
@@ -797,7 +796,7 @@
return ret;
}
- assert!(rows.iter().all(|r| r.len() == v.len()));
+ debug_assert!(rows.iter().all(|r| r.len() == v.len()));
let ty = v.head().ty();
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
@@ -810,8 +809,9 @@
// We try each or-pattern branch in turn.
let mut matrix = matrix.clone();
for v in v.expand_or_pat() {
- let usefulness =
- is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ let usefulness = ensure_sufficient_stack(|| {
+ is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ });
ret.extend(usefulness);
// If pattern has a guard don't add it to the matrix.
if !is_under_guard {
@@ -842,8 +842,9 @@
// We cache the result of `Fields::wildcards` because it is used a lot.
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
let v = v.pop_head_constructor(cx, &ctor);
- let usefulness =
- is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ let usefulness = ensure_sufficient_stack(|| {
+ is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ });
let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
// When all the conditions are met we have a match with a `non_exhaustive` enum
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 7607ccc..11856f6 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -604,7 +604,7 @@
debug!("destructor_call_block({:?}, {:?})", self, succ);
let tcx = self.tcx();
let drop_trait = tcx.require_lang_item(LangItem::Drop, None);
- let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap();
+ let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
let ty = self.place_ty(self.place);
let substs = tcx.mk_substs_trait(ty, &[]);
@@ -624,12 +624,7 @@
)],
terminator: Some(Terminator {
kind: TerminatorKind::Call {
- func: Operand::function_handle(
- tcx,
- drop_fn.def_id,
- substs,
- self.source_info.span,
- ),
+ func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span),
args: vec![Operand::Move(Place::from(ref_place))],
destination: Some((unit_temp, succ)),
cleanup: unwind.into_option(),
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index c000e49..ba6b566 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -64,6 +64,13 @@
}
}
+ /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
+ #[cfg(test)]
+ pub(crate) fn allow_unreachable(&mut self) {
+ #[cfg(debug_assertions)]
+ self.reachable_blocks.insert_all()
+ }
+
/// Returns the underlying `Results`.
pub fn results(&self) -> &Results<'tcx, A> {
&self.results.borrow()
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index a598912..6efa8da 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -268,6 +268,8 @@
let mut cursor =
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+ cursor.allow_unreachable();
+
let every_target = || {
body.basic_blocks()
.iter_enumerated()
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 158ba1b..d38b567 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -3,25 +3,14 @@
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_span::DUMMY_SP;
-
-pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
/// to a given local.
///
-/// The `K` parameter determines what kind of borrows are tracked. By default,
-/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
-/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
-///
/// At present, this is used as a very limited form of alias analysis. For example,
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
-/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a
-/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
-/// function call or inline assembly.
-pub struct MaybeBorrowedLocals<K = AnyBorrow> {
- kind: K,
+/// immovable generators.
+pub struct MaybeBorrowedLocals {
ignore_borrow_on_drop: bool,
}
@@ -29,29 +18,11 @@
/// A dataflow analysis that records whether a pointer or reference exists that may alias the
/// given local.
pub fn all_borrows() -> Self {
- MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
+ MaybeBorrowedLocals { ignore_borrow_on_drop: false }
}
}
-impl MaybeMutBorrowedLocals<'mir, 'tcx> {
- /// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
- /// alias the given local.
- ///
- /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
- /// types with interior mutability.
- pub fn mut_borrows_only(
- tcx: TyCtxt<'tcx>,
- body: &'mir mir::Body<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Self {
- MaybeBorrowedLocals {
- kind: MutBorrow { body, tcx, param_env },
- ignore_borrow_on_drop: false,
- }
- }
-}
-
-impl<K> MaybeBorrowedLocals<K> {
+impl MaybeBorrowedLocals {
/// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
///
/// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
@@ -69,21 +40,14 @@
MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
}
- fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
- TransferFunction {
- kind: &self.kind,
- trans,
- ignore_borrow_on_drop: self.ignore_borrow_on_drop,
- }
+ fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
+ TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
}
}
-impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
type Domain = BitSet<Local>;
- const NAME: &'static str = K::ANALYSIS_NAME;
+ const NAME: &'static str = "maybe_borrowed_locals";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = unborrowed
@@ -95,10 +59,7 @@
}
}
-impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
type Idx = Local;
fn statement_effect(
@@ -131,16 +92,14 @@
}
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
-struct TransferFunction<'a, T, K> {
+struct TransferFunction<'a, T> {
trans: &'a mut T,
- kind: &'a K,
ignore_borrow_on_drop: bool,
}
-impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
+impl<T> Visitor<'tcx> for TransferFunction<'a, T>
where
T: GenKill<Local>,
- K: BorrowAnalysisKind<'tcx>,
{
fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
self.super_statement(stmt, location);
@@ -156,14 +115,14 @@
self.super_rvalue(rvalue, location);
match rvalue {
- mir::Rvalue::AddressOf(mt, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
+ mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
- mir::Rvalue::Ref(_, kind, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
+ mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
@@ -211,64 +170,3 @@
}
}
}
-
-pub struct AnyBorrow;
-
-pub struct MutBorrow<'mir, 'tcx> {
- tcx: TyCtxt<'tcx>,
- body: &'mir Body<'tcx>,
- param_env: ParamEnv<'tcx>,
-}
-
-impl MutBorrow<'mir, 'tcx> {
- /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
- ///
- /// This assumes that it is UB to take the address of a struct field whose type is
- /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
- /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
- /// have to check the type of the borrowed **local** instead of the borrowed **place**
- /// below. See [rust-lang/unsafe-code-guidelines#134].
- ///
- /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
- fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
- !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
- }
-}
-
-pub trait BorrowAnalysisKind<'tcx> {
- const ANALYSIS_NAME: &'static str;
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
-}
-
-impl BorrowAnalysisKind<'tcx> for AnyBorrow {
- const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
-
- fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
- true
- }
- fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
- true
- }
-}
-
-impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
- const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
-
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
- match kind {
- mir::BorrowKind::Mut { .. } => true,
- mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
- self.shared_borrow_allows_mutation(place)
- }
- }
- }
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
- match mt {
- Mutability::Mut => true,
- Mutability::Not => self.shared_borrow_allows_mutation(place),
- }
- }
-}
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 474f4f2..2585701 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -4,17 +4,18 @@
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
+use rustc_middle::mir::visit::{MirVisitable, Visitor};
use rustc_middle::mir::{self, Body, Location};
use rustc_middle::ty::{self, TyCtxt};
-use crate::drop_flag_effects;
use crate::drop_flag_effects_for_function_entry;
use crate::drop_flag_effects_for_location;
use crate::elaborate_drops::DropFlagState;
use crate::framework::SwitchIntEdgeEffects;
-use crate::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
+use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::on_lookup_result_bits;
use crate::MoveDataParamEnv;
+use crate::{drop_flag_effects, on_all_children_bits};
use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
mod borrowed_locals;
@@ -22,7 +23,7 @@
mod liveness;
mod storage_liveness;
-pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
+pub use self::borrowed_locals::MaybeBorrowedLocals;
pub use self::init_locals::MaybeInitializedLocals;
pub use self::liveness::MaybeLiveLocals;
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
@@ -307,22 +308,45 @@
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
- _statement: &mir::Statement<'tcx>,
+ statement: &mir::Statement<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
+ });
+
+ if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+ return;
+ }
+
+ // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
+ for_each_mut_borrow(statement, location, |place| {
+ let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { return };
+ on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+ trans.gen(child);
+ })
})
}
fn terminator_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
- _terminator: &mir::Terminator<'tcx>,
+ terminator: &mir::Terminator<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
+ });
+
+ if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+ return;
+ }
+
+ for_each_mut_borrow(terminator, location, |place| {
+ let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { return };
+ on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+ trans.gen(child);
+ })
})
}
@@ -427,7 +451,10 @@
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
- })
+ });
+
+ // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
+ // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
}
fn terminator_effect(
@@ -438,7 +465,7 @@
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
- })
+ });
}
fn call_return_effect(
@@ -704,3 +731,37 @@
_ => None,
}
}
+
+struct OnMutBorrow<F>(F);
+
+impl<F> Visitor<'_> for OnMutBorrow<F>
+where
+ F: FnMut(&mir::Place<'_>),
+{
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) {
+ // FIXME: Does `&raw const foo` allow mutation? See #90413.
+ match rvalue {
+ mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
+ | mir::Rvalue::AddressOf(_, place) => (self.0)(place),
+
+ _ => {}
+ }
+
+ self.super_rvalue(rvalue, location)
+ }
+}
+
+/// Calls `f` for each mutable borrow or raw reference in the program.
+///
+/// This DOES NOT call `f` for a shared borrow of a type with interior mutability. That's okay for
+/// initializedness, because we cannot move from an `UnsafeCell` (outside of `core::cell`), but
+/// other analyses will likely need to check for `!Freeze`.
+fn for_each_mut_borrow<'tcx>(
+ mir: &impl MirVisitable<'tcx>,
+ location: Location,
+ f: impl FnMut(&mir::Place<'_>),
+) {
+ let mut vis = OnMutBorrow(f);
+
+ mir.apply(location, &mut vis);
+}
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 402391b..77a72ce 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -2,10 +2,10 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(exact_size_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(once_cell)]
#![feature(stmt_expr_attributes)]
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index c0bf4b6..28e5d76 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -11,8 +11,7 @@
use rustc_middle::ty::{self, Ty, TyCtxt};
use crate::impls::{
- DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals,
- MaybeUninitializedPlaces,
+ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
};
use crate::move_paths::{HasMoveData, MoveData};
use crate::move_paths::{LookupResult, MovePathIndex};
@@ -62,14 +61,6 @@
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
}
- if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
- let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
- .into_engine(tcx, body)
- .iterate_to_fixpoint();
-
- sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed);
- }
-
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
@@ -281,28 +272,6 @@
}
}
-impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
- fn peek_at(
- &self,
- tcx: TyCtxt<'tcx>,
- place: mir::Place<'tcx>,
- flow_state: &BitSet<Local>,
- call: PeekCall,
- ) {
- info!(?place, "peek_at");
- let local = if let Some(l) = place.as_local() {
- l
- } else {
- tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
- return;
- };
-
- if !flow_state.contains(local) {
- tcx.sess.span_err(call.span, "rustc_peek: bit not set");
- }
- }
-}
-
impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
fn peek_at(
&self,
@@ -312,9 +281,7 @@
call: PeekCall,
) {
info!(?place, "peek_at");
- let local = if let Some(l) = place.as_local() {
- l
- } else {
+ let Some(local) = place.as_local() else {
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
return;
};
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 17790ec..63c637a 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -68,11 +68,10 @@
return;
}
- use rustc_middle::hir::map::blocks::FnLikeNode;
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 = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ 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;
// Only run const prop on functions, methods, closures and associated constants
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 1c946bd..6807d02 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -14,13 +14,11 @@
use crate::MirPass;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_index::vec::IndexVec;
use rustc_middle::hir;
-use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::dump_enabled;
@@ -29,7 +27,6 @@
TerminatorKind,
};
use rustc_middle::ty::TyCtxt;
-use rustc_query_system::ich::StableHashingContext;
use rustc_span::def_id::DefId;
use rustc_span::source_map::SourceMap;
use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
@@ -66,7 +63,7 @@
}
let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local());
- let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
// Only instrument functions, methods, and closures (not constants since they are evaluated
// at compile time by Miri).
@@ -76,7 +73,7 @@
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
// Closures are carved out by their initial `Assign` statement.)
if !is_fn_like {
- trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id());
+ trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id());
return;
}
@@ -488,7 +485,7 @@
// Non-code expressions are injected into the coverage map, without generating executable code.
fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) {
- debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false });
+ debug_assert!(matches!(expression, CoverageKind::Expression { .. }));
debug!(" injecting non-code expression {:?}", expression);
let inject_in_bb = mir::START_BLOCK;
let data = &mut mir_body[inject_in_bb];
@@ -574,15 +571,13 @@
}
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
+ // FIXME(cjgillot) Stop hashing HIR manually here.
let mut hcx = tcx.create_no_span_stable_hashing_context();
- hash(&mut hcx, &hir_body.value).to_smaller_hash()
-}
-
-fn hash(
- hcx: &mut StableHashingContext<'tcx>,
- node: &impl HashStable<StableHashingContext<'tcx>>,
-) -> Fingerprint {
let mut stable_hasher = StableHasher::new();
- node.hash_stable(hcx, &mut stable_hasher);
+ let owner = hir_body.id().hir_id.owner;
+ let bodies = &tcx.hir_owner_nodes(owner).as_ref().unwrap().bodies;
+ hcx.with_hir_bodies(false, owner, bodies, |hcx| {
+ hir_body.value.hash_stable(hcx, &mut stable_hasher)
+ });
stable_hasher.finish()
}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index cc525a4..d13fa07 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -94,10 +94,9 @@
stmt_index: usize,
) -> Self {
let is_closure = match statement.kind {
- StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
- AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
- _ => false,
- },
+ StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
+ matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _))
+ }
_ => false,
};
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 2a24e1e..6b99514 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -1,13 +1,12 @@
//! This pass just dumps MIR at a specified point.
use std::borrow::Cow;
-use std::fmt;
use std::fs::File;
use std::io;
use crate::MirPass;
+use rustc_middle::mir::write_mir_pretty;
use rustc_middle::mir::Body;
-use rustc_middle::mir::{dump_enabled, dump_mir, write_mir_pretty};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OutputFilenames, OutputType};
@@ -21,29 +20,6 @@
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
}
-pub struct Disambiguator {
- is_after: bool,
-}
-
-impl fmt::Display for Disambiguator {
- fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- let title = if self.is_after { "after" } else { "before" };
- write!(formatter, "{}", title)
- }
-}
-
-pub fn on_mir_pass<'tcx>(
- tcx: TyCtxt<'tcx>,
- pass_num: &dyn fmt::Display,
- pass_name: &str,
- body: &Body<'tcx>,
- is_after: bool,
-) {
- if dump_enabled(tcx, pass_name, body.source.def_id()) {
- dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, body, |_, _| Ok(()));
- }
-}
-
pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
let path = outputs.path(OutputType::Mir);
let mut f = io::BufWriter::new(File::create(&path)?);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index ee4e91e..84a1e3f 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -673,9 +673,7 @@
assert!(args.next().is_none());
let tuple = Place::from(tuple);
- let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() {
- s
- } else {
+ let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else {
bug!("Closure arguments are not passed as a tuple");
};
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9b11c8f..f9ef314 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,9 +1,9 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(option_get_or_insert_default)]
@@ -27,7 +27,7 @@
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
@@ -65,6 +65,7 @@
mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
+mod reveal_all;
mod separate_const_switch;
mod shim;
mod simplify;
@@ -187,12 +188,14 @@
let mut index = 0;
let mut run_pass = |pass: &dyn MirPass<'tcx>| {
let run_hooks = |body: &_, index, is_after| {
- dump_mir::on_mir_pass(
+ let disambiguator = if is_after { "after" } else { "before" };
+ dump_mir(
tcx,
- &format_args!("{:03}-{:03}", phase_index, index),
+ Some(&format_args!("{:03}-{:03}", phase_index, index)),
&pass.name(),
+ &disambiguator,
body,
- is_after,
+ |_, _| Ok(()),
);
};
run_hooks(body, index, false);
@@ -428,8 +431,7 @@
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- use rustc_middle::hir::map::blocks::FnLikeNode;
- let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
if is_fn_like {
let did = def.did.to_def_id();
let def = ty::WithOptConstParam::unknown(did);
@@ -488,6 +490,7 @@
// to them. We run some optimizations before that, because they may be harder to do on the state
// machine than on MIR with async primitives.
let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
+ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
&lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
&normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
&unreachable_prop::UnreachablePropagation,
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index a2cce9f..822a372 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -17,9 +17,7 @@
pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let language_items = tcx.lang_items();
- let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() {
- slice_len_fn_item
- } else {
+ let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else {
// there is no language item to compare to :)
return;
};
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index 76f0e83..a04a0b5 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -208,7 +208,7 @@
operand,
cast_ty,
) => {
- let local = if let Some(local) = place.as_local() { local } else { return };
+ let Some(local) = place.as_local() else { return };
match operand {
Operand::Copy(place) | Operand::Move(place) => {
let operand_local =
@@ -255,9 +255,7 @@
}
}
Rvalue::Len(place) => {
- let local = if let Some(local) = place.local_or_deref_local() {
- local
- } else {
+ let Some(local) = place.local_or_deref_local() else {
return;
};
if let Some(cast_statement_idx) = state.get(&local).copied() {
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 5c9d04a..c71bc51 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -13,7 +13,7 @@
trace!("Running RemoveUnneededDrops on {:?}", body.source);
let did = body.source.def_id();
- let param_env = tcx.param_env(did);
+ let param_env = tcx.param_env_reveal_all_normalized(did);
let mut should_simplify = false;
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
new file mode 100644
index 0000000..6c423a2
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -0,0 +1,58 @@
+//! Normalizes MIR in RevealAll mode.
+
+use crate::MirPass;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub struct RevealAll;
+
+impl<'tcx> MirPass<'tcx> for RevealAll {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ // This pass must run before inlining, since we insert callee bodies in RevealAll mode.
+ // Do not apply this transformation to generators.
+ if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
+ && body.generator.is_none()
+ {
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ RevealAllVisitor { tcx, param_env }.visit_body(body);
+ }
+ }
+}
+
+struct RevealAllVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
+ #[inline]
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ #[inline]
+ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
+ *ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+ }
+
+ #[inline]
+ fn process_projection_elem(
+ &mut self,
+ elem: PlaceElem<'tcx>,
+ _: Location,
+ ) -> Option<PlaceElem<'tcx>> {
+ match elem {
+ PlaceElem::Field(field, ty) => {
+ let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
+ // None of those contain a Ty.
+ PlaceElem::Index(..)
+ | PlaceElem::Deref
+ | PlaceElem::ConstantIndex { .. }
+ | PlaceElem::Subslice { .. }
+ | PlaceElem::Downcast(..) => None,
+ }
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index f2ea5fe..f59aaa6 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -310,7 +310,6 @@
match self_ty.kind() {
_ if is_copy => builder.copy_shim(),
- ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
ty::Closure(_, substs) => {
builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
}
@@ -459,154 +458,6 @@
);
}
- fn loop_header(
- &mut self,
- beg: Place<'tcx>,
- end: Place<'tcx>,
- loop_body: BasicBlock,
- loop_end: BasicBlock,
- is_cleanup: bool,
- ) {
- let tcx = self.tcx;
-
- let cond = self.make_place(Mutability::Mut, tcx.types.bool);
- let compute_cond = self.make_statement(StatementKind::Assign(Box::new((
- cond,
- Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))),
- ))));
-
- // `if end != beg { goto loop_body; } else { goto loop_end; }`
- self.block(
- vec![compute_cond],
- TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
- is_cleanup,
- );
- }
-
- fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
- Box::new(Constant {
- span: self.span,
- user_ty: None,
- literal: ty::Const::from_usize(self.tcx, value).into(),
- })
- }
-
- fn array_shim(
- &mut self,
- dest: Place<'tcx>,
- src: Place<'tcx>,
- ty: Ty<'tcx>,
- len: &'tcx ty::Const<'tcx>,
- ) {
- let tcx = self.tcx;
- let span = self.span;
-
- let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
- let end = self.make_place(Mutability::Not, tcx.types.usize);
-
- // BB #0
- // `let mut beg = 0;`
- // `let end = len;`
- // `goto #1;`
- let inits = vec![
- self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::Use(Operand::Constant(self.make_usize(0))),
- )))),
- self.make_statement(StatementKind::Assign(Box::new((
- end,
- Rvalue::Use(Operand::Constant(Box::new(Constant {
- span: self.span,
- user_ty: None,
- literal: len.into(),
- }))),
- )))),
- ];
- self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
- // BB #1: loop {
- // BB #2;
- // BB #3;
- // }
- // BB #4;
- self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
-
- // BB #2
- // `dest[i] = Clone::clone(src[beg])`;
- // Goto #3 if ok, #5 if unwinding happens.
- let dest_field = self.tcx.mk_place_index(dest, beg);
- let src_field = self.tcx.mk_place_index(src, beg);
- self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5));
-
- // BB #3
- // `beg = beg + 1;`
- // `goto #1`;
- let statements = vec![self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::BinaryOp(
- BinOp::Add,
- Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
- ),
- ))))];
- self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
- // BB #4
- // `return dest;`
- self.block(vec![], TerminatorKind::Return, false);
-
- // BB #5 (cleanup)
- // `let end = beg;`
- // `let mut beg = 0;`
- // goto #6;
- let end = beg;
- let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
- let init = self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::Use(Operand::Constant(self.make_usize(0))),
- ))));
- self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
- // BB #6 (cleanup): loop {
- // BB #7;
- // BB #8;
- // }
- // BB #9;
- self.loop_header(
- Place::from(beg),
- Place::from(end),
- BasicBlock::new(7),
- BasicBlock::new(9),
- true,
- );
-
- // BB #7 (cleanup)
- // `drop(dest[beg])`;
- self.block(
- vec![],
- TerminatorKind::Drop {
- place: self.tcx.mk_place_index(dest, beg),
- target: BasicBlock::new(8),
- unwind: None,
- },
- true,
- );
-
- // BB #8 (cleanup)
- // `beg = beg + 1;`
- // `goto #6;`
- let statement = self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::BinaryOp(
- BinOp::Add,
- Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
- ),
- ))));
- self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
- // BB #9 (resume)
- self.block(vec![], TerminatorKind::Resume, true);
- }
-
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
where
I: Iterator<Item = Ty<'tcx>>,
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 5cef64d..2aa5061 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -83,12 +83,9 @@
let bb = BasicBlock::from_usize(bb);
trace!("processing block {:?}", bb);
- let discriminant_ty =
- if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) {
- ty
- } else {
- continue;
- };
+ let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
+ continue;
+ };
let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index baf3810..64cd6f5 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -27,9 +27,8 @@
// 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<'_>| match stmt.kind {
- StatementKind::LlvmInlineAsm(..) => true,
- _ => false,
+ bb_data.statements.iter().any(|stmt: &Statement<'_>| {
+ matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
})
};
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 5147408..59988e6 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -806,13 +806,22 @@
}
}
}
+ mir::TerminatorKind::Assert { ref msg, .. } => {
+ let lang_item = match msg {
+ mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
+ _ => LangItem::Panic,
+ };
+ let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, 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::Assert { .. } => {}
+ | mir::TerminatorKind::Unreachable => {}
mir::TerminatorKind::GeneratorDrop
| mir::TerminatorKind::Yield { .. }
| mir::TerminatorKind::FalseEdge { .. }
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 08b1d7b..f408215 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
+#![feature(let_else)]
#![feature(in_band_lifetimes)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index be68208..b419061 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -458,9 +458,7 @@
let is_generic = instance.substs.non_erasable_generics().next().is_some();
// Upstream `DefId` instances get different handling than local ones.
- let def_id = if let Some(def_id) = def_id.as_local() {
- def_id
- } else {
+ let Some(def_id) = def_id.as_local() else {
return if export_generics && is_generic {
// If it is an upstream monomorphization and we export generics, we must make
// it available to downstream crates.
diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
index 7a7a56a..658c902 100644
--- a/compiler/rustc_monomorphize/src/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -361,6 +361,17 @@
)
});
+ if tcx.prof.enabled() {
+ // Record CGU size estimates for self-profiling.
+ for cgu in codegen_units {
+ tcx.prof.artifact_size(
+ "codegen_unit_size_estimate",
+ &cgu.name().as_str()[..],
+ cgu.size_estimate() as u64,
+ );
+ }
+ }
+
let mono_items: DefIdSet = items
.iter()
.filter_map(|mono_item| match *mono_item {
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index e6e4438..5950806 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -167,6 +167,7 @@
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
@@ -195,7 +196,7 @@
generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>,
) {
- let base_def_id = tcx.closure_base_def_id(def_id);
+ let base_def_id = tcx.typeck_root_def_id(def_id);
if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
return;
}
@@ -303,7 +304,7 @@
ControlFlow::CONTINUE
}
ty::ConstKind::Unevaluated(uv)
- if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
+ if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
{
self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index 799b4e1..4392c02 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -67,7 +67,7 @@
src_file.prefer_local(),
line_nos
) {
- eprintln!("Error writting to file {}", e.to_string())
+ eprintln!("Error writing to file {}", e)
}
}
}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 8e90f73..1a62096 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,11 +1,13 @@
+use crate::lexer::unicode_chars::UNICODE_ARRAY;
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream};
+use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult};
use rustc_lexer::unescape::{self, Mode};
use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_session::lint::builtin::{
- TEXT_DIRECTION_CODEPOINT_IN_COMMENT, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
+ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::ParseSess;
@@ -137,12 +139,8 @@
// Opening delimiter of the length 2 is not included into the comment text.
let content_start = start + BytePos(2);
let content = self.str_from(content_start);
- let span = self.mk_sp(start, self.pos);
- const UNICODE_TEXT_FLOW_CHARS: &[char] = &[
- '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}',
- '\u{202C}', '\u{2069}',
- ];
- if content.contains(UNICODE_TEXT_FLOW_CHARS) {
+ if contains_text_flow_control_chars(content) {
+ let span = self.mk_sp(start, self.pos);
self.sess.buffer_lint_with_diagnostic(
&TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
span,
@@ -225,6 +223,22 @@
}
token::Ident(sym, is_raw_ident)
}
+ rustc_lexer::TokenKind::InvalidIdent
+ // Do not recover an identifier with emoji if the codepoint is a confusable
+ // with a recoverable substitution token, like `âž–`.
+ if UNICODE_ARRAY
+ .iter()
+ .find(|&&(c, _, _)| {
+ let sym = self.str_from(start);
+ sym.chars().count() == 1 && c == sym.chars().next().unwrap()
+ })
+ .is_none() =>
+ {
+ let sym = nfc_normalize(self.str_from(start));
+ let span = self.mk_sp(start, self.pos);
+ self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span);
+ token::Ident(sym, false)
+ }
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start as u32);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
@@ -296,7 +310,7 @@
rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
- rustc_lexer::TokenKind::Unknown => {
+ rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
let c = self.str_from(start).chars().next().unwrap();
let mut err =
self.struct_fatal_span_char(start, self.pos, "unknown start of token", c);
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 569f186..7f68112 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -82,6 +82,33 @@
Applicability::MachineApplicable,
);
}
+ } else {
+ let printable: Vec<char> = lit
+ .chars()
+ .filter(|&x| {
+ unicode_width::UnicodeWidthChar::width(x).unwrap_or(0) != 0
+ && !x.is_whitespace()
+ })
+ .collect();
+
+ if let [ch] = printable.as_slice() {
+ has_help = true;
+
+ handler.span_note(
+ span,
+ &format!(
+ "there are non-printing characters, the full sequence is `{}`",
+ lit.escape_default(),
+ ),
+ );
+
+ handler.span_suggestion(
+ span,
+ "consider removing the non-printing characters",
+ ch.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
if !has_help {
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 3eebc08..ccd11f0 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -7,7 +7,7 @@
use rustc_span::{symbol::kw, BytePos, Pos, Span};
#[rustfmt::skip] // for line breaks
-const UNICODE_ARRAY: &[(char, &str, char)] = &[
+pub(crate) const UNICODE_ARRAY: &[(char, &str, char)] = &[
('
', "Line Separator", ' '),
('
', "Paragraph Separator", ' '),
(' ', "Ogham Space mark", ' '),
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 8095f38..ce39d07 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -6,9 +6,11 @@
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
-use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
-use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
+use rustc_ast::{
+ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
+ BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
+ PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err};
@@ -662,7 +664,7 @@
let snapshot = self.clone();
self.bump();
let lo = self.token.span;
- match self.parse_angle_args() {
+ match self.parse_angle_args(None) {
Ok(args) => {
let span = lo.to(self.prev_token.span);
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
@@ -719,7 +721,7 @@
let x = self.parse_seq_to_before_end(
&token::Gt,
SeqSep::trailing_allowed(token::Comma),
- |p| p.parse_generic_arg(),
+ |p| p.parse_generic_arg(None),
);
match x {
Ok((_, _, false)) => {
@@ -1103,7 +1105,7 @@
self.expect(&token::ModSep)?;
let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None };
- self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
+ self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
path.span = ty_span.to(self.prev_token.span);
let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
@@ -1121,7 +1123,7 @@
Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
}
- pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
+ pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
if self.eat(&token::Semi) {
let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
err.span_suggestion_short(
@@ -1342,10 +1344,10 @@
self.struct_span_err(
MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
- "unexpected parenthesis surrounding `for` loop head",
+ "unexpected parentheses surrounding `for` loop head",
)
.multipart_suggestion(
- "remove parenthesis in `for` loop",
+ "remove parentheses in `for` loop",
vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
@@ -1909,6 +1911,71 @@
Ok(expr)
}
+ fn recover_const_param_decl(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
+ let snapshot = self.clone();
+ let param = match self.parse_const_param(vec![]) {
+ Ok(param) => param,
+ Err(mut err) => {
+ err.cancel();
+ *self = snapshot;
+ return Err(err);
+ }
+ };
+ let mut err =
+ self.struct_span_err(param.span(), "unexpected `const` parameter declaration");
+ err.span_label(param.span(), "expected a `const` expression, not a parameter declaration");
+ if let (Some(generics), Ok(snippet)) =
+ (ty_generics, self.sess.source_map().span_to_snippet(param.span()))
+ {
+ let (span, sugg) = match &generics.params[..] {
+ [] => (generics.span, format!("<{}>", snippet)),
+ [.., generic] => (generic.span().shrink_to_hi(), format!(", {}", snippet)),
+ };
+ err.multipart_suggestion(
+ "`const` parameters must be declared for the `impl`",
+ vec![(span, sugg), (param.span(), param.ident.to_string())],
+ Applicability::MachineApplicable,
+ );
+ }
+ let value = self.mk_expr_err(param.span());
+ err.emit();
+ return Ok(Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })));
+ }
+
+ pub fn recover_const_param_declaration(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
+ // We have to check for a few different cases.
+ if let Ok(arg) = self.recover_const_param_decl(ty_generics) {
+ return Ok(arg);
+ }
+
+ // We haven't consumed `const` yet.
+ let start = self.token.span;
+ self.bump(); // `const`
+
+ // Detect and recover from the old, pre-RFC2000 syntax for const generics.
+ let mut err = self
+ .struct_span_err(start, "expected lifetime, type, or constant, found keyword `const`");
+ if self.check_const_arg() {
+ err.span_suggestion_verbose(
+ start.until(self.token.span),
+ "the `const` keyword is only needed in the definition of the type",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
+ } else {
+ let after_kw_const = self.token.span;
+ self.recover_const_arg(after_kw_const, err).map(Some)
+ }
+ }
+
/// Try to recover from possible generic const argument without `{` and `}`.
///
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 3d29d30..f7ee874 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1032,6 +1032,8 @@
[IdentLike(_), Punct('+' | '-')] |
// 1e+2 | 1e-2
[IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
+ // 1.2e+ | 1.2e-
+ [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
// 1.2e+3 | 1.2e-3
[IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
// See the FIXME about `TokenCursor` above.
@@ -1148,7 +1150,7 @@
}
let fn_span_lo = self.token.span;
- let mut segment = self.parse_path_segment(PathStyle::Expr)?;
+ let mut segment = self.parse_path_segment(PathStyle::Expr, None)?;
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
self.check_turbofish_missing_angle_brackets(&mut segment);
@@ -1241,7 +1243,7 @@
} else if self.eat_keyword(kw::Unsafe) {
self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs)
} else if self.check_inline_const(0) {
- self.parse_const_block(lo.to(self.token.span))
+ self.parse_const_block(lo.to(self.token.span), false)
} else if self.is_do_catch_block() {
self.recover_do_catch(attrs)
} else if self.is_try_block() {
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index f175c5b..a9ab2cd 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -48,7 +48,10 @@
})
}
- fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
+ crate fn parse_const_param(
+ &mut self,
+ preceding_attrs: Vec<Attribute>,
+ ) -> PResult<'a, GenericParam> {
let const_span = self.token.span;
self.expect_keyword(kw::Const)?;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 624390a..24a8df4 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -216,11 +216,11 @@
return Err(e);
}
- (Ident::invalid(), ItemKind::Use(tree))
+ (Ident::empty(), ItemKind::Use(tree))
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
- (ident, ItemKind::Fn(Box::new(FnKind(def(), sig, generics, body))))
+ (ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
@@ -279,15 +279,15 @@
} else if self.eat_keyword(kw::Macro) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
- } else if self.is_macro_rules_item() {
+ } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
// MACRO_RULES ITEM
- self.parse_item_macro_rules(vis)?
+ self.parse_item_macro_rules(vis, has_bang)?
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
self.recover_missing_kw_before_item()?;
return Ok(None);
} else if macros_allowed && self.check_path() {
// MACRO INVOCATION ITEM
- (Ident::invalid(), ItemKind::MacCall(self.parse_item_macro(vis)?))
+ (Ident::empty(), ItemKind::MacCall(self.parse_item_macro(vis)?))
} else {
return Ok(None);
};
@@ -300,7 +300,7 @@
|| self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
- || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
+ || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
}
/// Are we sure this could not possibly be a macro invocation?
@@ -514,7 +514,7 @@
tokens: None,
})
} else {
- self.parse_ty()?
+ self.parse_ty_with_generics_recovery(&generics)?
};
// If `for` is missing we try to recover.
@@ -560,7 +560,7 @@
};
let trait_ref = TraitRef { path, ref_id: ty_first.id };
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety,
polarity,
defaultness,
@@ -573,7 +573,7 @@
}
None => {
// impl Type
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety,
polarity,
defaultness,
@@ -586,7 +586,7 @@
}
};
- Ok((Ident::invalid(), item_kind))
+ Ok((Ident::empty(), item_kind))
}
fn parse_item_list<T>(
@@ -682,7 +682,7 @@
self.expect_keyword(kw::Trait)?;
let ident = self.parse_ident()?;
- let mut tps = self.parse_generics()?;
+ let mut generics = self.parse_generics()?;
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
@@ -702,7 +702,7 @@
}
let bounds = self.parse_generic_bounds(None)?;
- tps.where_clause = self.parse_where_clause()?;
+ generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
let whole_span = lo.to(self.prev_token.span);
@@ -717,12 +717,15 @@
self.sess.gated_spans.gate(sym::trait_alias, whole_span);
- Ok((ident, ItemKind::TraitAlias(tps, bounds)))
+ Ok((ident, ItemKind::TraitAlias(generics, bounds)))
} else {
// It's a normal trait.
- tps.where_clause = self.parse_where_clause()?;
+ generics.where_clause = self.parse_where_clause()?;
let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
- Ok((ident, ItemKind::Trait(Box::new(TraitKind(is_auto, unsafety, tps, bounds, items)))))
+ Ok((
+ ident,
+ ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })),
+ ))
}
}
@@ -769,7 +772,7 @@
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
/// ```
/// The `"type"` has already been eaten.
- fn parse_type_alias(&mut self, def: Defaultness) -> PResult<'a, ItemInfo> {
+ fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
@@ -778,10 +781,10 @@
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
generics.where_clause = self.parse_where_clause()?;
- let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
+ let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(Box::new(TyAliasKind(def, generics, bounds, default)))))
+ Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
}
/// Parses a `UseTree`.
@@ -933,7 +936,7 @@
let abi = self.parse_abi(); // ABI?
let items = self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?;
let module = ast::ForeignMod { unsafety, abi, items };
- Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
+ Ok((Ident::empty(), ItemKind::ForeignMod(module)))
}
/// Parses a foreign item (one in an `extern { ... }` block).
@@ -1039,9 +1042,7 @@
};
match impl_info.1 {
- ItemKind::Impl(box ImplKind {
- of_trait: Some(ref trai), ref mut constness, ..
- }) => {
+ ItemKind::Impl(box Impl { of_trait: Some(ref trai), ref mut constness, .. }) => {
*constness = Const::Yes(const_span);
let before_trait = trai.path.span.shrink_to_lo();
@@ -1534,18 +1535,43 @@
Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false })))
}
- /// Is this unambiguously the start of a `macro_rules! foo` item definition?
- fn is_macro_rules_item(&mut self) -> bool {
- self.check_keyword(kw::MacroRules)
- && self.look_ahead(1, |t| *t == token::Not)
- && self.look_ahead(2, |t| t.is_ident())
+ /// Is this a possibly malformed start of a `macro_rules! foo` item definition?
+
+ fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
+ if self.check_keyword(kw::MacroRules) {
+ let macro_rules_span = self.token.span;
+
+ if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
+ return IsMacroRulesItem::Yes { has_bang: true };
+ } else if self.look_ahead(1, |t| (t.is_ident())) {
+ // macro_rules foo
+ self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
+ .span_suggestion(
+ macro_rules_span,
+ "add a `!`",
+ "macro_rules!".to_owned(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+
+ return IsMacroRulesItem::Yes { has_bang: false };
+ }
+ }
+
+ IsMacroRulesItem::No
}
/// Parses a `macro_rules! foo { ... }` declarative macro.
- fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> {
+ fn parse_item_macro_rules(
+ &mut self,
+ vis: &Visibility,
+ has_bang: bool,
+ ) -> PResult<'a, ItemInfo> {
self.expect_keyword(kw::MacroRules)?; // `macro_rules`
- self.expect(&token::Not)?; // `!`
+ if has_bang {
+ self.expect(&token::Not)?; // `!`
+ }
let ident = self.parse_ident()?;
if self.eat(&token::Not) {
@@ -2121,3 +2147,8 @@
}
}
}
+
+enum IsMacroRulesItem {
+ Yes { has_bang: bool },
+ No,
+}
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 5c701fe..9212aaa 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1095,8 +1095,12 @@
}
/// Parses inline const expressions.
- fn parse_const_block(&mut self, span: Span) -> PResult<'a, P<Expr>> {
- self.sess.gated_spans.gate(sym::inline_const, span);
+ fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> {
+ if pat {
+ self.sess.gated_spans.gate(sym::inline_const_pat, span);
+ } else {
+ self.sess.gated_spans.gate(sym::inline_const, span);
+ }
self.eat_keyword(kw::Const);
let blk = self.parse_block()?;
let anon_const = AnonConst {
@@ -1258,7 +1262,7 @@
/// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`,
/// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
/// If the following element can't be a tuple (i.e., it's a function definition), then
- /// it's not a tuple struct field), and the contents within the parentheses isn't valid,
+ /// it's not a tuple struct field), and the contents within the parentheses aren't valid,
/// so emit a proper diagnostic.
// Public for rustfmt usage.
pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index b03b545..bb3947b 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -437,7 +437,7 @@
PatKind::Box(pat)
} else if self.check_inline_const(0) {
// Parse `const pat`
- let const_expr = self.parse_const_block(lo.to(self.token.span))?;
+ let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
if let Some(re) = self.parse_range_end() {
self.parse_pat_range_begin_with(const_expr, re)?
@@ -817,7 +817,7 @@
// Ensure the user doesn't receive unhelpful unexpected token errors
self.bump();
if self.is_pat_range_end_start(0) {
- let _ = self.parse_pat_range_end();
+ let _ = self.parse_pat_range_end().map_err(|mut e| e.cancel());
}
self.error_inclusive_range_with_extra_equals(span_with_eq);
@@ -884,7 +884,7 @@
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
if self.check_inline_const(0) {
- self.parse_const_block(self.token.span)
+ self.parse_const_block(self.token.span, true)
} else if self.check_path() {
let lo = self.token.span;
let (qself, path) = if self.eat_lt() {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c7d080a..7f8fadb 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -3,10 +3,11 @@
use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
-use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
-use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
-use rustc_ast::{GenericArg, GenericArgs};
-use rustc_ast::{Path, PathSegment, QSelf};
+use rustc_ast::{
+ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
+ AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+ Path, PathSegment, QSelf,
+};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
@@ -78,7 +79,7 @@
}
let qself = QSelf { ty, path_span, position: path.segments.len() };
- self.parse_path_segments(&mut path.segments, style)?;
+ self.parse_path_segments(&mut path.segments, style, None)?;
Ok((
qself,
@@ -119,6 +120,10 @@
true
}
+ pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ self.parse_path_inner(style, None)
+ }
+
/// Parses simple paths.
///
/// `path = [::] segment+`
@@ -129,7 +134,11 @@
/// `a::b::C::<D>` (with disambiguator)
/// `Fn(Args)` (without disambiguator)
/// `Fn::(Args)` (with disambiguator)
- pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ pub(super) fn parse_path_inner(
+ &mut self,
+ style: PathStyle,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Path> {
maybe_whole!(self, NtPath, |path| {
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
@@ -152,7 +161,7 @@
if self.eat(&token::ModSep) {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
- self.parse_path_segments(&mut segments, style)?;
+ self.parse_path_segments(&mut segments, style, ty_generics)?;
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
}
@@ -161,9 +170,10 @@
&mut self,
segments: &mut Vec<PathSegment>,
style: PathStyle,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, ()> {
loop {
- let segment = self.parse_path_segment(style)?;
+ let segment = self.parse_path_segment(style, ty_generics)?;
if style == PathStyle::Expr {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
@@ -191,7 +201,11 @@
}
}
- pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
+ pub(super) fn parse_path_segment(
+ &mut self,
+ style: PathStyle,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;
let is_args_start = |token: &Token| {
matches!(
@@ -229,8 +243,11 @@
let lo = self.token.span;
let args = if self.eat_lt() {
// `<'a, T, A = U>`
- let args =
- self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?;
+ let args = self.parse_angle_args_with_leading_angle_bracket_recovery(
+ style,
+ lo,
+ ty_generics,
+ )?;
self.expect_gt()?;
let span = lo.to(self.prev_token.span);
AngleBracketedArgs { args, span }.into()
@@ -238,9 +255,9 @@
// `(T, U) -> R`
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let inputs_span = lo.to(self.prev_token.span);
- let span = ident.span.to(self.prev_token.span);
let output =
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
+ let span = ident.span.to(self.prev_token.span);
ParenthesizedArgs { span, inputs, inputs_span, output }.into()
};
@@ -275,6 +292,7 @@
&mut self,
style: PathStyle,
lo: Span,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, Vec<AngleBracketedArg>> {
// We need to detect whether there are extra leading left angle brackets and produce an
// appropriate error and suggestion. This cannot be implemented by looking ahead at
@@ -350,7 +368,7 @@
let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
- match self.parse_angle_args() {
+ match self.parse_angle_args(ty_generics) {
Ok(args) => Ok(args),
Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
// Swap `self` with our backup of the parser state before attempting to parse
@@ -403,7 +421,7 @@
.emit();
// Try again without unmatched angle bracket characters.
- self.parse_angle_args()
+ self.parse_angle_args(ty_generics)
}
}
Err(e) => Err(e),
@@ -412,9 +430,12 @@
/// Parses (possibly empty) list of generic arguments / associated item constraints,
/// possibly including trailing comma.
- pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
+ pub(super) fn parse_angle_args(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Vec<AngleBracketedArg>> {
let mut args = Vec::new();
- while let Some(arg) = self.parse_angle_arg()? {
+ while let Some(arg) = self.parse_angle_arg(ty_generics)? {
args.push(arg);
if !self.eat(&token::Comma) {
if !self.token.kind.should_end_const_arg() {
@@ -431,9 +452,12 @@
}
/// Parses a single argument in the angle arguments `<...>` of a path segment.
- fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
+ fn parse_angle_arg(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<AngleBracketedArg>> {
let lo = self.token.span;
- let arg = self.parse_generic_arg()?;
+ let arg = self.parse_generic_arg(ty_generics)?;
match arg {
Some(arg) => {
if self.check(&token::Colon) | self.check(&token::Eq) {
@@ -476,7 +500,7 @@
/// 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>> {
- let arg = self.parse_generic_arg()?;
+ 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),
@@ -563,7 +587,10 @@
/// Parse a generic argument in a path segment.
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
- pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
+ pub(super) fn parse_generic_arg(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
let start = self.token.span;
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
// Parse lifetime argument.
@@ -580,25 +607,8 @@
return self.recover_const_arg(start, err).map(Some);
}
}
- } else if self.eat_keyword_noexpect(kw::Const) {
- // Detect and recover from the old, pre-RFC2000 syntax for const generics.
- let mut err = self.struct_span_err(
- start,
- "expected lifetime, type, or constant, found keyword `const`",
- );
- if self.check_const_arg() {
- err.span_suggestion_verbose(
- start.until(self.token.span),
- "the `const` keyword is only needed in the definition of the type",
- String::new(),
- Applicability::MaybeIncorrect,
- );
- err.emit();
- GenericArg::Const(self.parse_const_arg()?)
- } else {
- let after_kw_const = self.token.span;
- return self.recover_const_arg(after_kw_const, err).map(Some);
- }
+ } else if self.token.is_keyword(kw::Const) {
+ return self.recover_const_param_declaration(ty_generics);
} else {
return Ok(None);
};
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 9ec6eff..01e751e 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -16,7 +16,7 @@
};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt};
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym};
@@ -300,6 +300,12 @@
None => LocalKind::Decl,
Some(init) => {
if self.eat_keyword(kw::Else) {
+ if self.token.is_keyword(kw::If) {
+ // `let...else if`. Emit the same error that `parse_block()` would,
+ // but explicitly point out that this pattern is not allowed.
+ let msg = "conditional `else if` is not supported for `let...else`";
+ return Err(self.error_block_no_opening_brace_msg(msg));
+ }
let els = self.parse_block()?;
self.check_let_else_init_bool_expr(&init);
self.check_let_else_init_trailing_brace(&init);
@@ -328,7 +334,7 @@
),
)
.multipart_suggestion(
- "wrap the expression in parenthesis",
+ "wrap the expression in parentheses",
suggs,
Applicability::MachineApplicable,
)
@@ -349,7 +355,7 @@
"right curly brace `}` before `else` in a `let...else` statement not allowed",
)
.multipart_suggestion(
- "try wrapping the expression in parenthesis",
+ "try wrapping the expression in parentheses",
suggs,
Applicability::MachineApplicable,
)
@@ -392,10 +398,9 @@
Ok(block)
}
- fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
+ fn error_block_no_opening_brace_msg(&mut self, msg: &str) -> DiagnosticBuilder<'a> {
let sp = self.token.span;
- let tok = super::token_descr(&self.token);
- let mut e = self.struct_span_err(sp, &format!("expected `{{`, found {}", tok));
+ let mut e = self.struct_span_err(sp, msg);
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
// Check to see if the user has written something like
@@ -435,7 +440,13 @@
_ => {}
}
e.span_label(sp, "expected `{`");
- Err(e)
+ e
+ }
+
+ fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
+ let tok = super::token_descr(&self.token);
+ let msg = format!("expected `{{`, found {}", tok);
+ Err(self.error_block_no_opening_brace_msg(&msg))
}
/// Parses a block. Inner attributes are allowed.
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 9840037..9bfde0e 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -4,9 +4,10 @@
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token, TokenKind};
-use rustc_ast::{self as ast, BareFnTy, FnRetTy, GenericParam, Lifetime, MutTy, Ty, TyKind};
-use rustc_ast::{GenericBound, GenericBounds, MacCall, Mutability};
-use rustc_ast::{PolyTraitRef, TraitBoundModifier, TraitObjectSyntax};
+use rustc_ast::{
+ self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
+ MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
+};
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
@@ -98,6 +99,20 @@
AllowCVariadic::No,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
+ )
+ }
+
+ pub(super) fn parse_ty_with_generics_recovery(
+ &mut self,
+ ty_params: &Generics,
+ ) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ Some(ty_params),
)
}
@@ -110,6 +125,7 @@
AllowCVariadic::Yes,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
)
}
@@ -125,6 +141,7 @@
AllowCVariadic::No,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
)
}
@@ -135,6 +152,7 @@
AllowCVariadic::Yes,
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
+ None,
)
}
@@ -152,6 +170,7 @@
AllowCVariadic::No,
recover_qpath,
recover_return_sign,
+ None,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
@@ -171,6 +190,7 @@
AllowCVariadic::No,
recover_qpath,
recover_return_sign,
+ None,
)?;
FnRetTy::Ty(ty)
} else {
@@ -184,6 +204,7 @@
allow_c_variadic: AllowCVariadic,
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -233,7 +254,7 @@
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
TyKind::Path(Some(qself), path)
} else if self.check_path() {
- self.parse_path_start_ty(lo, allow_plus)?
+ self.parse_path_start_ty(lo, allow_plus, ty_generics)?
} else if self.can_begin_bound() {
self.parse_bare_trait_object(lo, allow_plus)?
} else if self.eat(&token::DotDotDot) {
@@ -430,7 +451,7 @@
}
// Parses the `typeof(EXPR)`.
- // To avoid ambiguity, the type is surrounded by parenthesis.
+ // To avoid ambiguity, the type is surrounded by parentheses.
fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> {
self.expect(&token::OpenDelim(token::Paren))?;
let expr = self.parse_anon_const_expr()?;
@@ -512,9 +533,14 @@
/// 1. a type macro, `mac!(...)`,
/// 2. a bare trait object, `B0 + ... + Bn`,
/// 3. or a path, `path::to::MyType`.
- fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
+ fn parse_path_start_ty(
+ &mut self,
+ lo: Span,
+ allow_plus: AllowPlus,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, TyKind> {
// Simple path
- let path = self.parse_path(PathStyle::Type)?;
+ let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
// Macro invocation in type position
Ok(TyKind::MacCall(MacCall {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 2aa20d0..4781813 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -5,7 +5,7 @@
use rustc_ast::tokenstream::{DelimSpan, TokenTree};
use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
use rustc_errors::{Applicability, FatalError, PResult};
-use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::ParseSess;
use rustc_span::{sym, Symbol};
@@ -15,14 +15,13 @@
return;
}
- let attr_info =
- attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+ let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check input tokens for built-in and key-value attributes.
match attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
- Some((name, _, template, _)) if name != sym::rustc_dummy => {
- check_builtin_attribute(sess, attr, name, template)
+ Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
+ check_builtin_attribute(sess, attr, *name, *template)
}
_ if let MacArgs::Eq(..) = attr.get_normal_item().args => {
// All key-value attributes are restricted to meta-item syntax.
@@ -168,7 +167,7 @@
attr: &Attribute,
name: Symbol,
) -> ! {
- let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2;
+ let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
emit_malformed_attribute(sess, attr, name, template);
// This is fatal, otherwise it will likely cause a cascade of other errors
// (and an error here is expected to be very rare).
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index e5fbddd..f761eaa 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -9,9 +9,9 @@
use rustc_middle::ty::TyCtxt;
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability};
-use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
+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};
@@ -23,6 +23,7 @@
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use std::collections::hash_map::Entry;
pub(crate) fn target_from_impl_item<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -69,7 +70,7 @@
let mut doc_aliases = FxHashMap::default();
let mut is_valid = true;
let mut specified_inline = None;
- let mut seen = FxHashSet::default();
+ let mut seen = FxHashMap::default();
let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs {
let attr_is_valid = match attr.name_or_empty() {
@@ -112,6 +113,7 @@
self.check_default_method_body_is_const(attr, span, target)
}
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_const_unstable
| sym::rustc_const_stable
| sym::unstable
@@ -147,8 +149,10 @@
_ => {}
}
+ let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
+
if hir_id != CRATE_HIR_ID {
- if let Some((_, AttributeType::CrateLevel, ..)) =
+ if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
{
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
@@ -164,21 +168,37 @@
}
}
- // Duplicate attributes
- match attr.name_or_empty() {
- name @ sym::macro_use => {
- let args = attr.meta_item_list().unwrap_or_else(Vec::new);
- let args: Vec<_> = args.iter().map(|arg| arg.name_or_empty()).collect();
- if !seen.insert((name, args)) {
- self.tcx.struct_span_lint_hir(
- UNUSED_ATTRIBUTES,
- hir_id,
+ if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
+ check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
+ }
+
+ // Warn on useless empty attributes.
+ if matches!(
+ attr.name_or_empty(),
+ sym::macro_use
+ | sym::allow
+ | sym::warn
+ | sym::deny
+ | sym::forbid
+ | sym::feature
+ | sym::repr
+ | sym::target_feature
+ ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+ {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build("unused attribute")
+ .span_suggestion(
attr.span,
- |lint| lint.build("unused attribute").emit(),
- );
- }
- }
- _ => {}
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .note(&format!(
+ "attribute `{}` with an empty list has no effect",
+ attr.name_or_empty()
+ ))
+ .emit();
+ });
}
}
@@ -765,7 +785,7 @@
"not a `use` item",
);
}
- err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information")
+ err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information")
.emit();
},
);
@@ -962,7 +982,7 @@
}
sym::primitive => {
- if !self.tcx.features().doc_primitive {
+ if !self.tcx.features().rustdoc_internals {
self.tcx.struct_span_lint_hir(
INVALID_DOC_ATTRIBUTES,
hir_id,
@@ -1046,6 +1066,37 @@
is_valid
}
+ /// Warns against some misuses of `#[must_use]`
+ 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() {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(
+ "`must_use` attribute on `async` functions \
+ applies to the anonymous `Future` returned by the \
+ function, not the value within",
+ )
+ .span_label(
+ *span,
+ "this attribute does nothing, the `Future`s \
+ returned by async functions are already `must_use`",
+ )
+ .emit();
+ });
+ }
+ }
+
+ // For now, its always valid
+ true
+ }
+
/// 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 {
match target {
@@ -1958,3 +2009,77 @@
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_attrs, ..*providers };
}
+
+fn check_duplicates(
+ tcx: TyCtxt<'_>,
+ attr: &Attribute,
+ hir_id: HirId,
+ duplicates: AttributeDuplicates,
+ seen: &mut FxHashMap<Symbol, Span>,
+) {
+ use AttributeDuplicates::*;
+ if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
+ return;
+ }
+ match duplicates {
+ DuplicatesOk => {}
+ WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
+ match seen.entry(attr.name_or_empty()) {
+ Entry::Occupied(mut entry) => {
+ let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
+ let to_remove = entry.insert(attr.span);
+ (to_remove, attr.span)
+ } else {
+ (attr.span, *entry.get())
+ };
+ tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| {
+ let mut db = lint.build("unused attribute");
+ db.span_note(other, "attribute also specified here").span_suggestion(
+ this,
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) {
+ db.warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ );
+ }
+ db.emit();
+ });
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(attr.span);
+ }
+ }
+ }
+ ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
+ Entry::Occupied(mut entry) => {
+ let (this, other) = if matches!(duplicates, ErrorPreceding) {
+ let to_remove = entry.insert(attr.span);
+ (to_remove, attr.span)
+ } else {
+ (attr.span, *entry.get())
+ };
+ tcx.sess
+ .struct_span_err(
+ this,
+ &format!("multiple `{}` attributes", attr.name_or_empty()),
+ )
+ .span_note(other, "attribute also specified here")
+ .span_suggestion(
+ this,
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(attr.span);
+ }
+ },
+ }
+}
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index a0ceb56..9ccf76b 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -173,6 +173,12 @@
None => return true,
};
+ // If the function belongs to a trait, then it must enable the const_trait_impl
+ // feature to use that trait function (with a const default body).
+ if tcx.trait_of_item(def_id).is_some() {
+ return true;
+ }
+
// If this crate is not using stability attributes, or this function is not claiming to be a
// stable `const fn`, that is all that is required.
if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
@@ -210,10 +216,10 @@
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
match missing_gates.as_slice() {
- &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
+ [] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
- &[missing_primary, ref missing_secondary @ ..] => {
- let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);
+ [missing_primary, ref missing_secondary @ ..] => {
+ let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
// If multiple feature gates would be required to enable this expression, include
// them as help messages. Don't emit a separate error for each missing feature gate.
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 4adec3c..af1c724 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -7,7 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_zip)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 5fc8e23..6a8feb0 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -334,9 +334,10 @@
// properly, we can't miss any types.
match expr.kind {
- // Manually recurse over closures, because they are the only
+ // Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
- hir::ExprKind::Closure(.., body, _, _) => {
+ hir::ExprKind::Closure(.., body, _, _)
+ | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}
@@ -817,9 +818,9 @@
}
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- if closure_base_def_id != def_id {
- return tcx.region_scope_tree(closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.region_scope_tree(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ae3a9c7..1166814 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -23,7 +23,7 @@
use rustc_middle::thir::abstract_const::Node as ACNode;
use rustc_middle::ty::fold::TypeVisitor;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::hygiene::Transparency;
@@ -124,9 +124,11 @@
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _ }) => {
- self.visit_trait(trait_ref)
- }
+ ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: _,
+ polarity: _,
+ }) => self.visit_trait(trait_ref),
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
self.visit_projection_ty(projection_ty)
@@ -153,11 +155,8 @@
tcx: TyCtxt<'tcx>,
ct: AbstractConst<'tcx>,
) -> ControlFlow<V::BreakTy> {
- const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() {
- ACNode::Leaf(leaf) => {
- let leaf = leaf.subst(tcx, ct.substs);
- self.visit_const(leaf)
- }
+ const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+ ACNode::Leaf(leaf) => self.visit_const(leaf),
ACNode::Cast(_, _, ty) => self.visit_ty(ty),
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
ControlFlow::CONTINUE
@@ -544,7 +543,7 @@
module: LocalDefId,
) {
let level = Some(AccessLevel::Reachable);
- if let ty::Visibility::Public = vis {
+ if vis.is_public() {
self.update(def_id, level);
}
match def_kind {
@@ -581,7 +580,7 @@
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
- if let ty::Visibility::Public = vis {
+ if vis.is_public() {
let item =
self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
if let hir::ItemKind::Struct(ref struct_def, _)
@@ -619,6 +618,7 @@
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl
@@ -933,7 +933,7 @@
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 == ty::Visibility::Public {
+ 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));
@@ -1918,8 +1918,7 @@
/// 1. It's contained within a public type
/// 2. It comes from a private crate
fn leaks_private_dep(&self, item_id: DefId) -> bool {
- let ret = self.required_visibility == ty::Visibility::Public
- && self.tcx.is_private_dep(item_id.krate);
+ let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
ret
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 89df3d4..f984bb1 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -7,9 +7,8 @@
doctest = false
[dependencies]
-measureme = "9.0.0"
+measureme = "10.0.0"
rustc-rayon-core = "0.3.1"
-tracing = "0.1"
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/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index e50a8c1..440b6f1 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -13,23 +13,19 @@
extern crate rustc_macros;
#[macro_use]
extern crate rustc_middle;
-#[macro_use]
-extern crate tracing;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::DiagnosticBuilder;
-use rustc_middle::dep_graph;
+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};
-use rustc_middle::ty::query::{Providers, QueryEngine};
+use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_query_system::ich::StableHashingContext;
+use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
#[macro_use]
mod plumbing;
pub use plumbing::QueryCtxt;
-use plumbing::QueryStruct;
use rustc_query_system::query::*;
mod stats;
@@ -41,9 +37,8 @@
mod values;
use self::values::Value;
-use rustc_query_system::query::QueryAccessors;
pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryDescription;
+pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable};
mod on_disk_cache;
pub use on_disk_cache::OnDiskCache;
@@ -53,6 +48,14 @@
mod util;
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
+ if def_id.is_top_level_module() {
+ "top-level module".to_string()
+ } else {
+ format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+ }
+}
+
rustc_query_append! { [define_queries!][<'tcx>] }
impl<'tcx> Queries<'tcx> {
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 48eb488..552906a 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -219,7 +219,7 @@
// Do this *before* we clone 'latest_foreign_def_path_hashes', since
// loading existing queries may cause us to create new DepNodes, which
// may in turn end up invoking `store_foreign_def_id_hash`
- tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx));
+ tcx.dep_graph.exec_cache_promotions(tcx);
*self.serialized_data.write() = None;
}
@@ -358,23 +358,6 @@
Ok(())
})
}
-
- fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId {
- debug!("def_path_hash_to_def_id({:?})", hash);
-
- let stable_crate_id = hash.stable_crate_id();
-
- // If this is a DefPathHash from the local crate, we can look up the
- // DefId in the tcx's `Definitions`.
- if stable_crate_id == tcx.sess.local_stable_crate_id() {
- tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id()
- } else {
- // If this is a DefPathHash from an upstream crate, let the CrateStore map
- // it to a DefId.
- let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id);
- tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash)
- }
- }
}
impl<'sess> OnDiskCache<'sess> {
@@ -764,7 +747,7 @@
// 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().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash))
+ Ok(d.tcx().def_path_hash_to_def_id(def_path_hash))
}
}
@@ -1035,7 +1018,7 @@
) -> FileEncodeResult
where
CTX: QueryContext + 'tcx,
- Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
+ Q: super::QueryDescription<CTX>,
Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
{
let _timer = tcx
@@ -1050,7 +1033,7 @@
if res.is_err() {
return;
}
- if Q::cache_on_disk(tcx, &key, Some(value)) {
+ if Q::cache_on_disk(*tcx.dep_context(), &key) {
let dep_node = SerializedDepNodeIndex::new(dep_node.index());
// Record position of the cache entry.
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 4d1e39d..81a36e0 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -2,20 +2,17 @@
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::{on_disk_cache, queries, Queries};
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
+use crate::{on_disk_cache, Queries};
+use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::ty::tls::{self, ImplicitCtxt};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
use rustc_query_system::dep_graph::HasDepContext;
-use rustc_query_system::query::{
- QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
-};
+use rustc_query_system::query::{QueryContext, QueryJobId, QueryMap, QuerySideEffects};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::{Diagnostic, Handler};
use rustc_serialize::opaque;
-use rustc_span::def_id::LocalDefId;
use std::any::Any;
@@ -53,36 +50,6 @@
self.queries.try_collect_active_jobs(**self)
}
- fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
- let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
- (cb.try_load_from_on_disk_cache)(*self, dep_node)
- }
-
- fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
- debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
- // We must avoid ever having to call `force_from_dep_node()` for a
- // `DepNode::codegen_unit`:
- // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
- // would always end up having to evaluate the first caller of the
- // `codegen_unit` query that *is* reconstructible. This might very well be
- // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
- // to re-trigger calling the `codegen_unit` query with the right key. At
- // that point we would already have re-done all the work we are trying to
- // avoid doing in the first place.
- // The solution is simple: Just explicitly call the `codegen_unit` query for
- // each CGU, right after partitioning. This way `try_mark_green` will always
- // hit the cache instead of having to go through `force_from_dep_node`.
- // This assertion makes sure, we actually keep applying the solution above.
- debug_assert!(
- dep_node.kind != DepKind::codegen_unit,
- "calling force_from_dep_node() on DepKind::codegen_unit"
- );
-
- let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
- (cb.force_from_dep_node)(*self, dep_node)
- }
-
// Interactions with on_disk_cache
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
self.queries
@@ -193,60 +160,6 @@
}
}
-/// This struct stores metadata about each Query.
-///
-/// Information is retrieved by indexing the `QUERIES` array using the integer value
-/// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual
-/// jump table instead of large matches.
-pub struct QueryStruct {
- /// The red/green evaluation system will try to mark a specific DepNode in the
- /// dependency graph as green by recursively trying to mark the dependencies of
- /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
- /// where we don't know if it is red or green and we therefore actually have
- /// to recompute its value in order to find out. Since the only piece of
- /// information that we have at that point is the `DepNode` we are trying to
- /// re-evaluate, we need some way to re-run a query from just that. This is what
- /// `force_from_dep_node()` implements.
- ///
- /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
- /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
- /// is usually constructed by computing a stable hash of the query-key that the
- /// `DepNode` corresponds to. Consequently, it is not in general possible to go
- /// back from hash to query-key (since hash functions are not reversible). For
- /// this reason `force_from_dep_node()` is expected to fail from time to time
- /// because we just cannot find out, from the `DepNode` alone, what the
- /// corresponding query-key is and therefore cannot re-run the query.
- ///
- /// The system deals with this case letting `try_mark_green` fail which forces
- /// the root query to be re-evaluated.
- ///
- /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
- /// Fortunately, we can use some contextual information that will allow us to
- /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
- /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
- /// valid `DefPathHash`. Since we also always build a huge table that maps every
- /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
- /// everything we need to re-run the query.
- ///
- /// Take the `mir_promoted` query as an example. Like many other queries, it
- /// just has a single parameter: the `DefId` of the item it will compute the
- /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
- /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
- /// is actually a `DefPathHash`, and can therefore just look up the corresponding
- /// `DefId` in `tcx.def_path_hash_to_def_id`.
- ///
- /// When you implement a new query, it will likely have a corresponding new
- /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
- /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
- /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
- /// add it to the "We don't have enough information to reconstruct..." group in
- /// the match below.
- pub(crate) force_from_dep_node: fn(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool,
-
- /// Invoke a query to put the on-disk cached value in memory.
- pub(crate) try_load_from_on_disk_cache: fn(QueryCtxt<'_>, &DepNode),
-}
-
macro_rules! handle_cycle_error {
([][$tcx: expr, $error:expr]) => {{
$error.emit();
@@ -291,14 +204,30 @@
}
macro_rules! hash_result {
- ([][$hcx:expr, $result:expr]) => {{
- dep_graph::hash_result($hcx, &$result)
+ ([]) => {{
+ Some(dep_graph::hash_result)
}};
- ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{
+ ([(no_hash) $($rest:tt)*]) => {{
None
}};
+ ([$other:tt $($modifiers:tt)*]) => {
+ hash_result!([$($modifiers)*])
+ };
+}
+
+macro_rules! get_provider {
+ ([][$tcx:expr, $name:ident, $key:expr]) => {{
+ $tcx.queries.local_providers.$name
+ }};
+ ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
+ if $key.query_crate_is_local() {
+ $tcx.queries.local_providers.$name
+ } else {
+ $tcx.queries.extern_providers.$name
+ }
+ }};
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
- hash_result!([$($modifiers)*][$($args)*])
+ get_provider!([$($modifiers)*][$($args)*])
};
}
@@ -374,10 +303,8 @@
const NAME: &'static str = stringify!($name);
}
- impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> for queries::$name<$tcx> {
- const ANON: bool = is_anon!([$($modifiers)*]);
- const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
- const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
+ impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> {
+ rustc_query_description! { $name<$tcx> }
type Cache = query_storage::$name<$tcx>;
@@ -396,32 +323,25 @@
}
#[inline]
- fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
- fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
+ fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
+ QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value>
{
- if key.query_crate_is_local() {
- tcx.queries.local_providers.$name
- } else {
- tcx.queries.extern_providers.$name
+ let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
+ let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
+ QueryVtable {
+ anon: is_anon!([$($modifiers)*]),
+ eval_always: is_eval_always!([$($modifiers)*]),
+ dep_kind: dep_graph::DepKind::$name,
+ hash_result: hash_result!([$($modifiers)*]),
+ handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]),
+ compute,
+ cache_on_disk,
+ try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
}
}
-
- fn hash_result(
- _hcx: &mut StableHashingContext<'_>,
- _result: &Self::Value
- ) -> Option<Fingerprint> {
- hash_result!([$($modifiers)*][_hcx, _result])
- }
-
- fn handle_cycle_error(
- tcx: QueryCtxt<'tcx>,
- mut error: DiagnosticBuilder<'_>,
- ) -> Self::Value {
- handle_cycle_error!([$($modifiers)*][tcx, error])
- }
})*
- #[allow(non_upper_case_globals)]
+ #[allow(nonstandard_style)]
pub mod query_callbacks {
use super::*;
use rustc_middle::dep_graph::DepNode;
@@ -431,68 +351,100 @@
use rustc_query_system::dep_graph::FingerprintStyle;
// We use this for most things when incr. comp. is turned off.
- pub const Null: QueryStruct = QueryStruct {
- force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node),
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn Null() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: false,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Unit,
+ force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
+ try_load_from_on_disk_cache: None,
+ }
+ }
- pub const TraitSelect: QueryStruct = QueryStruct {
- force_from_dep_node: |_, _| false,
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn TraitSelect() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: true,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Unit,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
- pub const CompileCodegenUnit: QueryStruct = QueryStruct {
- force_from_dep_node: |_, _| false,
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn CompileCodegenUnit() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: false,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Opaque,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
- pub const CompileMonoItem: QueryStruct = QueryStruct {
- force_from_dep_node: |_, _| false,
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn CompileMonoItem() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: false,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Opaque,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
- $(pub const $name: QueryStruct = {
- const is_anon: bool = is_anon!([$($modifiers)*]);
+ $(pub fn $name()-> DepKindStruct {
+ let is_anon = is_anon!([$($modifiers)*]);
+ let is_eval_always = is_eval_always!([$($modifiers)*]);
+
+ let fingerprint_style =
+ <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style();
+
+ if is_anon || !fingerprint_style.reconstructible() {
+ return DepKindStruct {
+ is_anon,
+ is_eval_always,
+ fingerprint_style,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
#[inline(always)]
- fn fingerprint_style() -> FingerprintStyle {
- <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>
- ::fingerprint_style()
+ fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> {
+ <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node)
}
- fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> {
- <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node)
- }
-
- fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
- force_query::<queries::$name<'_>, _>(tcx, dep_node)
- }
-
- fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
- if is_anon {
- return
+ fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool {
+ if let Some(key) = recover(tcx, dep_node) {
+ let tcx = QueryCtxt::from_tcx(tcx);
+ force_query::<queries::$name<'_>, _>(tcx, key, dep_node);
+ true
+ } else {
+ false
}
+ }
- if !fingerprint_style().reconstructible() {
- return
- }
+ fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) {
+ debug_assert!(tcx.dep_graph.is_green(&dep_node));
- debug_assert!(tcx.dep_graph.is_green(dep_node));
-
- let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
- if queries::$name::cache_on_disk(tcx, &key, None) {
+ let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
+ if queries::$name::cache_on_disk(tcx, &key) {
let _ = tcx.$name(key);
}
}
- QueryStruct {
- force_from_dep_node,
- try_load_from_on_disk_cache,
+ DepKindStruct {
+ is_anon,
+ is_eval_always,
+ fingerprint_style,
+ force_from_dep_node: Some(force_from_dep_node),
+ try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache),
}
- };)*
+ })*
}
- static QUERY_CALLBACKS: &[QueryStruct] = &make_dep_kind_array!(query_callbacks);
+ pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] {
+ arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
+ }
}
}
@@ -504,7 +456,7 @@
input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
pub struct Queries<$tcx> {
local_providers: Box<Providers>,
- extern_providers: Box<Providers>,
+ extern_providers: Box<ExternProviders>,
pub on_disk_cache: Option<OnDiskCache<$tcx>>,
@@ -517,7 +469,7 @@
impl<$tcx> Queries<$tcx> {
pub fn new(
local_providers: Providers,
- extern_providers: Providers,
+ extern_providers: ExternProviders,
on_disk_cache: Option<OnDiskCache<$tcx>>,
) -> Self {
Queries {
@@ -575,13 +527,3 @@
}
};
}
-
-fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
- if def_id.is_top_level_module() {
- "top-level module".to_string()
- } else {
- format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
- }
-}
-
-rustc_query_description! {}
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 8602219..c274c2c 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -60,8 +60,11 @@
/// Creates a new, parameterless DepNode. This method will assert
/// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters.
- pub fn new_no_params(kind: K) -> DepNode<K> {
- debug_assert!(!kind.has_params());
+ pub fn new_no_params<Ctxt>(tcx: Ctxt, kind: K) -> DepNode<K>
+ where
+ Ctxt: super::DepContext<DepKind = K>,
+ {
+ debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
DepNode { kind, hash: Fingerprint::ZERO.into() }
}
@@ -75,7 +78,7 @@
#[cfg(debug_assertions)]
{
- if !kind.fingerprint_style().reconstructible()
+ if !tcx.fingerprint_style(kind).reconstructible()
&& (tcx.sess().opts.debugging_opts.incremental_info
|| tcx.sess().opts.debugging_opts.query_dep_graph)
{
@@ -121,11 +124,12 @@
where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{
- #[inline]
+ #[inline(always)]
default fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
}
+ #[inline(always)]
default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
let mut hcx = tcx.create_stable_hashing_context();
let mut hasher = StableHasher::new();
@@ -135,10 +139,12 @@
hasher.finish()
}
+ #[inline(always)]
default fn to_debug_str(&self, _: Ctxt) -> String {
format!("{:?}", *self)
}
+ #[inline(always)]
default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
None
}
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 114d12f..a8be1ca 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -33,12 +33,6 @@
/// each task has a `DepNodeIndex` that uniquely identifies it. This unique
/// ID is used for self-profiling.
virtual_dep_node_index: Lrc<AtomicU32>,
-
- /// The cached event id for profiling node interning. This saves us
- /// from having to look up the event id every time we intern a node
- /// which may incur too much overhead.
- /// This will be None if self-profiling is disabled.
- node_intern_event_id: Option<EventId>,
}
rustc_index::newtype_index! {
@@ -96,14 +90,13 @@
dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
}
-pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
+pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
where
R: for<'a> HashStable<StableHashingContext<'a>>,
{
let mut stable_hasher = StableHasher::new();
result.hash_stable(hcx, &mut stable_hasher);
-
- Some(stable_hasher.finish())
+ stable_hasher.finish()
}
impl<K: DepKind> DepGraph<K> {
@@ -117,8 +110,13 @@
) -> DepGraph<K> {
let prev_graph_node_count = prev_graph.node_count();
- let current =
- CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats);
+ let current = CurrentDepGraph::new(
+ profiler,
+ prev_graph_node_count,
+ encoder,
+ record_graph,
+ record_stats,
+ );
// Instantiate a dependy-less node only once for anonymous queries.
let _green_node_index = current.intern_new_node(
@@ -129,10 +127,6 @@
);
debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
- let node_intern_event_id = profiler
- .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
- .map(EventId::from_label);
-
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
@@ -143,16 +137,11 @@
colors: DepNodeColorMap::new(prev_graph_node_count),
})),
virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
- node_intern_event_id,
}
}
pub fn new_disabled() -> DepGraph<K> {
- DepGraph {
- data: None,
- virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
- node_intern_event_id: None,
- }
+ DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
}
/// Returns `true` if we are actually building the full dep-graph, and `false` otherwise.
@@ -215,7 +204,7 @@
cx: Ctxt,
arg: A,
task: fn(Ctxt, A) -> R,
- hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+ hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
) -> (R, DepNodeIndex) {
if self.is_fully_enabled() {
self.with_task_impl(key, cx, arg, task, hash_result)
@@ -234,7 +223,7 @@
cx: Ctxt,
arg: A,
task: fn(Ctxt, A) -> R,
- hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+ hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
) -> (R, DepNodeIndex) {
// This function is only called when the graph is enabled.
let data = self.data.as_ref().unwrap();
@@ -253,7 +242,7 @@
key
);
- let task_deps = if key.kind.is_eval_always() {
+ let task_deps = if cx.dep_context().is_eval_always(key.kind) {
None
} else {
Some(Lock::new(TaskDeps {
@@ -268,15 +257,14 @@
let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
let dcx = cx.dep_context();
- let mut hcx = dcx.create_stable_hashing_context();
let hashing_timer = dcx.profiler().incr_result_hashing();
- let current_fingerprint = hash_result(&mut hcx, &result);
+ let current_fingerprint = hash_result.map(|f| {
+ let mut hcx = dcx.create_stable_hashing_context();
+ f(&mut hcx, &result)
+ });
let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
- // Get timer for profiling `DepNode` interning
- let node_intern_timer =
- self.node_intern_event_id.map(|eid| dcx.profiler().generic_activity_with_event_id(eid));
// Intern the new `DepNode`.
let (dep_node_index, prev_and_color) = data.current.intern_node(
dcx.profiler(),
@@ -286,7 +274,6 @@
current_fingerprint,
print_status,
);
- drop(node_intern_timer);
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -315,7 +302,7 @@
where
OP: FnOnce() -> R,
{
- debug_assert!(!dep_kind.is_eval_always());
+ debug_assert!(!cx.is_eval_always(dep_kind));
if let Some(ref data) = self.data {
let task_deps = Lock::new(TaskDeps::default());
@@ -492,7 +479,7 @@
tcx: Ctxt,
dep_node: &DepNode<K>,
) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
- debug_assert!(!dep_node.kind.is_eval_always());
+ debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
// Return None if the dep graph is disabled
let data = self.data.as_ref()?;
@@ -552,7 +539,7 @@
// We don't know the state of this dependency. If it isn't
// an eval_always node, let's try to mark it green recursively.
- if !dep_dep_node.kind.is_eval_always() {
+ if !tcx.dep_context().is_eval_always(dep_dep_node.kind) {
debug!(
"try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
is unknown, trying to mark it green",
@@ -575,7 +562,7 @@
"try_mark_previous_green({:?}) --- trying to force dependency {:?}",
dep_node, dep_dep_node
);
- if !tcx.try_force_from_dep_node(dep_dep_node) {
+ if !tcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
// The DepNode could not be forced.
debug!(
"try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
@@ -642,7 +629,7 @@
}
// We never try to mark eval_always nodes as green
- debug_assert!(!dep_node.kind.is_eval_always());
+ debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
@@ -740,8 +727,7 @@
//
// This method will only load queries that will end up in the disk cache.
// Other queries will not be executed.
- pub fn exec_cache_promotions<Ctxt: QueryContext<DepKind = K>>(&self, qcx: Ctxt) {
- let tcx = qcx.dep_context();
+ pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
let data = self.data.as_ref().unwrap();
@@ -749,7 +735,7 @@
match data.colors.get(prev_index) {
Some(DepNodeColor::Green(_)) => {
let dep_node = data.previous.index_to_node(prev_index);
- qcx.try_load_from_on_disk_cache(&dep_node);
+ tcx.try_load_from_on_disk_cache(dep_node);
}
None | Some(DepNodeColor::Red) => {
// We can skip red nodes because a node can only be marked
@@ -876,10 +862,17 @@
/// debugging and only active with `debug_assertions`.
total_read_count: AtomicU64,
total_duplicate_read_count: AtomicU64,
+
+ /// The cached event id for profiling node interning. This saves us
+ /// from having to look up the event id every time we intern a node
+ /// which may incur too much overhead.
+ /// This will be None if self-profiling is disabled.
+ node_intern_event_id: Option<EventId>,
}
impl<K: DepKind> CurrentDepGraph<K> {
fn new(
+ profiler: &SelfProfilerRef,
prev_graph_node_count: usize,
encoder: FileEncoder,
record_graph: bool,
@@ -908,6 +901,10 @@
let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200;
+ let node_intern_event_id = profiler
+ .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
+ .map(EventId::from_label);
+
CurrentDepGraph {
encoder: Steal::new(GraphEncoder::new(
encoder,
@@ -927,6 +924,7 @@
forbidden_edge,
total_read_count: AtomicU64::new(0),
total_duplicate_read_count: AtomicU64::new(0),
+ node_intern_event_id,
}
}
@@ -970,6 +968,10 @@
) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
let print_status = cfg!(debug_assertions) && print_status;
+ // Get timer for profiling `DepNode` interning
+ let _node_intern_timer =
+ self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid));
+
if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
// Determine the color and index of the new `DepNode`.
if let Some(fingerprint) = fingerprint {
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index dcda572..047fc9f 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -32,6 +32,17 @@
/// Access the compiler session.
fn sess(&self) -> &Session;
+
+ /// Return whether this kind always require evaluation.
+ fn is_eval_always(&self, kind: Self::DepKind) -> bool;
+
+ fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle;
+
+ /// Try to force a dep node to execute and see if it's green.
+ fn try_force_from_dep_node(&self, dep_node: DepNode<Self::DepKind>) -> bool;
+
+ /// Load data from the on-disk cache.
+ fn try_load_from_on_disk_cache(&self, dep_node: DepNode<Self::DepKind>);
}
pub trait HasDepContext: Copy {
@@ -51,7 +62,7 @@
}
/// Describes the contents of the fingerprint generated by a given query.
-#[derive(PartialEq, Eq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum FingerprintStyle {
/// The fingerprint is actually a DefPathHash.
DefPathHash,
@@ -75,12 +86,6 @@
pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
const NULL: Self;
- /// Return whether this kind always require evaluation.
- fn is_eval_always(&self) -> bool;
-
- /// Return whether this kind requires additional parameters to be executed.
- fn has_params(&self) -> bool;
-
/// Implementation of `std::fmt::Debug` for `DepNode`.
fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
@@ -93,6 +98,4 @@
fn read_deps<OP>(op: OP)
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
-
- fn fingerprint_style(&self) -> FingerprintStyle;
}
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index f5f67fc..47197a1 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -222,7 +222,7 @@
index
}
- fn finish(self) -> FileEncodeResult {
+ fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
let Self { mut encoder, total_node_count, total_edge_count, result, stats: _ } = self;
let () = result?;
@@ -235,7 +235,11 @@
IntEncodedWithFixedSize(edge_count).encode(&mut encoder)?;
debug!("position: {:?}", encoder.position());
// Drop the encoder so that nothing is written after the counts.
- encoder.flush()
+ let result = encoder.flush();
+ // FIXME(rylev): we hardcode the dep graph file name so we don't need a dependency on
+ // rustc_incremental just for that.
+ profiler.artifact_size("dep_graph", "dep-graph.bin", encoder.position() as u64);
+ result
}
}
@@ -332,6 +336,6 @@
pub fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph");
- self.status.into_inner().finish()
+ self.status.into_inner().finish(profiler)
}
}
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index f2e935c..5f31fa0 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -1,6 +1,7 @@
use crate::ich;
use rustc_ast as ast;
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::sync::Lrc;
use rustc_hir as hir;
@@ -27,7 +28,6 @@
cstore: &'a dyn CrateStore,
pub(super) body_resolver: BodyResolver<'a>,
hash_spans: bool,
- hash_bodies: bool,
pub(super) node_id_hashing_mode: NodeIdHashingMode,
// Very often, we are hashing something that does not need the
@@ -46,24 +46,19 @@
/// We could also just store a plain reference to the `hir::Crate` but we want
/// to avoid that the crate is used to get untracked access to all of the HIR.
#[derive(Clone, Copy)]
-pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
-
-impl<'tcx> BodyResolver<'tcx> {
- /// Returns a reference to the `hir::Body` with the given `BodyId`.
- /// **Does not do any tracking**; use carefully.
- pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
- self.0.body(id)
- }
+pub(super) enum BodyResolver<'tcx> {
+ Forbidden,
+ Traverse {
+ hash_bodies: bool,
+ owner: LocalDefId,
+ bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
+ },
}
impl<'a> StableHashingContext<'a> {
- /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
- /// Don't use it for anything else or you'll run the risk of
- /// leaking data out of the tracking system.
#[inline]
fn new_with_or_without_spans(
sess: &'a Session,
- krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
always_ignore_spans: bool,
@@ -72,13 +67,12 @@
!always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
StableHashingContext {
- body_resolver: BodyResolver(krate),
+ body_resolver: BodyResolver::Forbidden,
definitions,
cstore,
caching_source_map: None,
raw_source_map: sess.source_map(),
hash_spans: hash_spans_initial,
- hash_bodies: true,
node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
}
}
@@ -86,13 +80,11 @@
#[inline]
pub fn new(
sess: &'a Session,
- krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
) -> Self {
Self::new_with_or_without_spans(
sess,
- krate,
definitions,
cstore,
/*always_ignore_spans=*/ false,
@@ -102,20 +94,41 @@
#[inline]
pub fn ignore_spans(
sess: &'a Session,
- krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
) -> Self {
let always_ignore_spans = true;
- Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+ Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans)
+ }
+
+ /// Allow hashing
+ #[inline]
+ pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) {
+ let prev = match &mut self.body_resolver {
+ BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
+ BodyResolver::Traverse { ref mut hash_bodies, .. } => {
+ std::mem::replace(hash_bodies, hb)
+ }
+ };
+ f(self);
+ match &mut self.body_resolver {
+ BodyResolver::Forbidden => unreachable!(),
+ BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev,
+ }
}
#[inline]
- pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
- let prev_hash_bodies = self.hash_bodies;
- self.hash_bodies = hash_bodies;
+ pub fn with_hir_bodies(
+ &mut self,
+ hash_bodies: bool,
+ owner: LocalDefId,
+ bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ let prev = self.body_resolver;
+ self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies };
f(self);
- self.hash_bodies = prev_hash_bodies;
+ self.body_resolver = prev;
}
#[inline]
@@ -153,11 +166,6 @@
}
#[inline]
- pub fn hash_bodies(&self) -> bool {
- self.hash_bodies
- }
-
- #[inline]
pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
match self.caching_source_map {
Some(ref mut sm) => sm,
diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs
index 04eb263..3a0aab8 100644
--- a/compiler/rustc_query_system/src/ich/impls_hir.rs
+++ b/compiler/rustc_query_system/src/ich/impls_hir.rs
@@ -1,12 +1,11 @@
//! This module contains `HashStable` implementations for various HIR data
//! types in no particular order.
+use crate::ich::hcx::BodyResolver;
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_hir as hir;
-use rustc_hir::definitions::DefPathHash;
-use smallvec::SmallVec;
use std::mem;
impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
@@ -29,8 +28,13 @@
#[inline]
fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
let hcx = self;
- if hcx.hash_bodies() {
- hcx.body_resolver.body(id).hash_stable(hcx, hasher);
+ match hcx.body_resolver {
+ BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
+ BodyResolver::Traverse { hash_bodies: false, .. } => {}
+ BodyResolver::Traverse { hash_bodies: true, owner, bodies } => {
+ assert_eq!(id.hir_id.owner, owner);
+ bodies[&id.hir_id.local_id].hash_stable(hcx, hasher);
+ }
}
}
@@ -115,6 +119,16 @@
self.node_id_hashing_mode = prev_hash_node_ids;
}
+
+ #[inline]
+ fn hash_hir_trait_candidate(&mut self, tc: &hir::TraitCandidate, hasher: &mut StableHasher) {
+ self.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+ let hir::TraitCandidate { def_id, import_ids } = tc;
+
+ def_id.hash_stable(hcx, hasher);
+ import_ids.hash_stable(hcx, hasher);
+ });
+ }
}
impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
@@ -129,27 +143,3 @@
});
}
}
-
-impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- let hir::TraitCandidate { def_id, import_ids } = self;
-
- def_id.hash_stable(hcx, hasher);
- import_ids.hash_stable(hcx, hasher);
- });
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
- type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
-
- fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
- let hir::TraitCandidate { def_id, import_ids } = self;
-
- (
- hcx.def_path_hash(*def_id),
- import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
- )
- }
-}
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index bc23de0..b1295ba 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -3,8 +3,10 @@
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(thread_local_const_init)]
+#![feature(extern_types)]
#[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 76a165e..d2b102b 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -19,15 +19,16 @@
type Stored: Clone;
}
-pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
+pub struct QueryVtable<CTX: QueryContext, K, V> {
pub anon: bool,
pub dep_kind: CTX::DepKind,
pub eval_always: bool,
+ pub cache_on_disk: bool,
- pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option<Fingerprint>,
+ pub compute: fn(CTX::DepContext, K) -> V,
+ pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
- pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
- pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
+ pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
}
impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
@@ -38,30 +39,25 @@
DepNode::construct(tcx, self.dep_kind, key)
}
- pub(crate) fn hash_result(
- &self,
- hcx: &mut StableHashingContext<'_>,
- value: &V,
- ) -> Option<Fingerprint> {
- (self.hash_result)(hcx, value)
- }
-
- pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool {
- (self.cache_on_disk)(tcx, key, value)
+ pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V {
+ (self.compute)(tcx, key)
}
pub(crate) fn try_load_from_disk(&self, tcx: CTX, index: SerializedDepNodeIndex) -> Option<V> {
- (self.try_load_from_disk)(tcx, index)
+ self.try_load_from_disk
+ .expect("QueryDescription::load_from_disk() called for an unsupported query.")(
+ tcx, index,
+ )
}
}
-pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
- const ANON: bool;
- const EVAL_ALWAYS: bool;
- const DEP_KIND: CTX::DepKind;
+pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
+ const TRY_LOAD_FROM_DISK: Option<fn(CTX, SerializedDepNodeIndex) -> Option<Self::Value>>;
type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
+ 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>
where
@@ -73,43 +69,7 @@
CTX: 'a;
// Don't use this method to compute query results, instead use the methods on TyCtxt
- fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
+ fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>;
- fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value)
- -> Option<Fingerprint>;
-
- fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
-}
-
-pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
- fn describe(tcx: CTX, key: Self::Key) -> String;
-
- #[inline]
- fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
- false
- }
-
- fn try_load_from_disk(_: CTX, _: SerializedDepNodeIndex) -> Option<Self::Value> {
- panic!("QueryDescription::load_from_disk() called for an unsupported query.")
- }
-}
-
-pub(crate) trait QueryVtableExt<CTX: QueryContext, K, V> {
- const VTABLE: QueryVtable<CTX, K, V>;
-}
-
-impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
-where
- CTX: QueryContext,
- Q: QueryDescription<CTX>,
-{
- const VTABLE: QueryVtable<CTX, Q::Key, Q::Value> = QueryVtable {
- anon: Q::ANON,
- dep_kind: Q::DEP_KIND,
- eval_always: Q::EVAL_ALWAYS,
- hash_result: Q::hash_result,
- handle_cycle_error: Q::handle_cycle_error,
- cache_on_disk: Q::cache_on_disk,
- try_load_from_disk: Q::try_load_from_disk,
- };
+ fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
}
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 98b2a45..bd67303 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -644,9 +644,7 @@
if Some(i) == num_frames {
break;
}
- let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) {
- info
- } else {
+ let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else {
break;
};
let mut diag = Diagnostic::new(
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index dffe7f3..a2f7843 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -12,9 +12,9 @@
};
mod config;
-pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
+pub use self::config::{QueryConfig, QueryDescription, QueryVtable};
-use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
+use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
@@ -122,12 +122,6 @@
fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>>;
- /// Load data from the on-disk cache.
- fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>);
-
- /// Try to force a dep node to execute and see if it's green.
- fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
-
/// Load side effects associated to the node in the previous session.
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 07d7205..b08db39e 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -2,9 +2,9 @@
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
use crate::query::caches::QueryCache;
-use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
+use crate::query::config::{QueryDescription, QueryVtable};
use crate::query::job::{
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
};
@@ -18,6 +18,7 @@
use rustc_data_structures::sync::{Lock, LockGuard};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::{DiagnosticBuilder, FatalError};
+use rustc_session::Session;
use rustc_span::{Span, DUMMY_SP};
use std::cell::Cell;
use std::collections::hash_map::Entry;
@@ -382,7 +383,6 @@
lookup: QueryLookup,
dep_node: Option<DepNode<CTX::DepKind>>,
query: &QueryVtable<CTX, C::Key, C::Value>,
- compute: fn(CTX::DepContext, C::Key) -> C::Value,
) -> (C::Stored, Option<DepNodeIndex>)
where
C: QueryCache,
@@ -398,7 +398,7 @@
query.dep_kind,
) {
TryGetJob::NotYetStarted(job) => {
- let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id, compute);
+ let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
let result = job.complete(cache, result, dep_node_index);
(result, Some(dep_node_index))
}
@@ -429,7 +429,6 @@
mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
query: &QueryVtable<CTX, K, V>,
job_id: QueryJobId<CTX::DepKind>,
- compute: fn(CTX::DepContext, K) -> V,
) -> (V, DepNodeIndex)
where
K: Clone + DepNodeParams<CTX::DepContext>,
@@ -441,7 +440,7 @@
// Fast path for when incr. comp. is off.
if !dep_graph.is_fully_enabled() {
let prof_timer = tcx.dep_context().profiler().query_provider();
- let result = tcx.start_query(job_id, None, || compute(*tcx.dep_context(), key));
+ let result = tcx.start_query(job_id, None, || query.compute(*tcx.dep_context(), key));
let dep_node_index = dep_graph.next_virtual_depnode_index();
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
return (result, dep_node_index);
@@ -455,7 +454,7 @@
// The diagnostics for this query will be promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
if let Some(ret) = tcx.start_query(job_id, None, || {
- try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query, compute)
+ try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query)
}) {
return ret;
}
@@ -467,14 +466,14 @@
let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || {
if query.anon {
return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
- compute(*tcx.dep_context(), key)
+ query.compute(*tcx.dep_context(), key)
});
}
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
- dep_graph.with_task(dep_node, *tcx.dep_context(), key, compute, query.hash_result)
+ dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result)
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -498,7 +497,6 @@
key: &K,
dep_node: &DepNode<CTX::DepKind>,
query: &QueryVtable<CTX, K, V>,
- compute: fn(CTX::DepContext, K) -> V,
) -> Option<(V, DepNodeIndex)>
where
K: Clone,
@@ -515,28 +513,41 @@
// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
- if query.cache_on_disk(tcx, key, None) {
+ 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);
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
- // We always expect to find a cached result for things that
- // can be forced from `DepNode`.
- debug_assert!(
- !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(),
- "missing on-disk cache entry for {:?}",
- dep_node
- );
-
if let Some(result) = result {
+ let prev_fingerprint = tcx
+ .dep_context()
+ .dep_graph()
+ .prev_fingerprint_of(dep_node)
+ .unwrap_or(Fingerprint::ZERO);
// If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
- if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) {
+ //
+ // If not, we still seek to verify a subset of fingerprints loaded
+ // from disk. Re-hashing results is fairly expensive, so we can't
+ // currently afford to verify every hash. This subset should still
+ // give us some coverage of potential bugs though.
+ let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
+ if unlikely!(
+ try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
+ ) {
incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
}
return Some((result, dep_node_index));
}
+
+ // We always expect to find a cached result for things that
+ // can be forced from `DepNode`.
+ debug_assert!(
+ !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
+ "missing on-disk cache entry for {:?}",
+ dep_node
+ );
}
// We could not load a result from the on-disk cache, so
@@ -544,7 +555,7 @@
let prof_timer = tcx.dep_context().profiler().query_provider();
// The dep-graph for this computation is already in-place.
- let result = dep_graph.with_ignore(|| compute(*tcx.dep_context(), key.clone()));
+ let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone()));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -577,46 +588,94 @@
);
debug!("BEGIN verify_ich({:?})", dep_node);
- let mut hcx = tcx.create_stable_hashing_context();
-
- let new_hash = query.hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO);
+ let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
+ let mut hcx = tcx.create_stable_hashing_context();
+ f(&mut hcx, result)
+ });
+ let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
debug!("END verify_ich({:?})", dep_node);
- let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
-
if Some(new_hash) != old_hash {
- let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
- format!("`cargo clean -p {}` or `cargo clean`", crate_name)
- } else {
- "`cargo clean`".to_string()
- };
+ incremental_verify_ich_cold(tcx.sess(), DebugArg::from(&dep_node), DebugArg::from(&result));
+ }
+}
- // When we emit an error message and panic, we try to debug-print the `DepNode`
- // and query result. Unforunately, this can cause us to run additional queries,
- // which may result in another fingerprint mismatch while we're in the middle
- // of processing this one. To avoid a double-panic (which kills the process
- // before we can print out the query static), we print out a terse
- // but 'safe' message if we detect a re-entrant call to this method.
- thread_local! {
- static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
- };
+// This DebugArg business is largely a mirror of std::fmt::ArgumentV1, which is
+// currently not exposed publicly.
+//
+// The PR which added this attempted to use `&dyn Debug` instead, but that
+// showed statistically significant worse compiler performance. It's not
+// actually clear what the cause there was -- the code should be cold. If this
+// can be replaced with `&dyn Debug` with on perf impact, then it probably
+// should be.
+extern "C" {
+ type Opaque;
+}
- let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+struct DebugArg<'a> {
+ value: &'a Opaque,
+ fmt: fn(&Opaque, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
+}
- if old_in_panic {
- tcx.sess().struct_err("internal compiler error: re-entrant incremental verify failure, suppressing message")
- .emit();
- } else {
- tcx.sess().struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
+impl<'a, T> From<&'a T> for DebugArg<'a>
+where
+ T: std::fmt::Debug,
+{
+ fn from(value: &'a T) -> DebugArg<'a> {
+ DebugArg {
+ value: unsafe { std::mem::transmute(value) },
+ fmt: unsafe {
+ std::mem::transmute(<T as std::fmt::Debug>::fmt as fn(_, _) -> std::fmt::Result)
+ },
+ }
+ }
+}
+
+impl std::fmt::Debug for DebugArg<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ (self.fmt)(self.value, f)
+ }
+}
+
+// Note that this is marked #[cold] and intentionally takes the equivalent of
+// `dyn Debug` for its arguments, as we want to avoid generating a bunch of
+// different implementations for LLVM to chew on (and filling up the final
+// binary, too).
+#[cold]
+fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
+ let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
+ format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+ } else {
+ "`cargo clean`".to_string()
+ };
+
+ // When we emit an error message and panic, we try to debug-print the `DepNode`
+ // and query result. Unfortunately, this can cause us to run additional queries,
+ // which may result in another fingerprint mismatch while we're in the middle
+ // of processing this one. To avoid a double-panic (which kills the process
+ // before we can print out the query static), we print out a terse
+ // but 'safe' message if we detect a re-entrant call to this method.
+ thread_local! {
+ static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
+ };
+
+ let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+
+ if old_in_panic {
+ sess.struct_err(
+ "internal compiler error: re-entrant incremental verify failure, suppressing message",
+ )
+ .emit();
+ } else {
+ sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
.help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
.note(&"Please follow the instructions below to create a bug report with the provided information")
.note(&"See <https://github.com/rust-lang/rust/issues/84970> for more information")
.emit();
- panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
- }
-
- INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
+ panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
}
+
+ INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
}
/// Ensure that either this query has all green inputs or been executed.
@@ -665,41 +724,6 @@
}
}
-#[inline(never)]
-fn force_query_impl<CTX, C>(
- tcx: CTX,
- state: &QueryState<CTX::DepKind, C::Key>,
- cache: &QueryCacheStore<C>,
- key: C::Key,
- dep_node: DepNode<CTX::DepKind>,
- query: &QueryVtable<CTX, C::Key, C::Value>,
- compute: fn(CTX::DepContext, C::Key) -> C::Value,
-) -> bool
-where
- C: QueryCache,
- C::Key: DepNodeParams<CTX::DepContext>,
- CTX: QueryContext,
-{
- debug_assert!(!query.anon);
-
- // We may be concurrently trying both execute and force a query.
- // Ensure that only one of them runs the query.
- let cached = cache.cache.lookup(cache, &key, |_, index| {
- if unlikely!(tcx.dep_context().profiler().enabled()) {
- tcx.dep_context().profiler().query_cache_hit(index.into());
- }
- });
-
- let lookup = match cached {
- Ok(()) => return true,
- Err(lookup) => lookup,
- };
-
- let _ =
- try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), query, compute);
- true
-}
-
pub enum QueryMode {
Get,
Ensure,
@@ -717,9 +741,9 @@
Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- let query = &Q::VTABLE;
+ let query = Q::make_vtable(tcx, &key);
let dep_node = if let QueryMode::Ensure = mode {
- let (must_run, dep_node) = ensure_must_run(tcx, &key, query);
+ let (must_run, dep_node) = ensure_must_run(tcx, &key, &query);
if !must_run {
return None;
}
@@ -729,7 +753,6 @@
};
debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
- let compute = Q::compute_fn(tcx, &key);
let (result, dep_node_index) = try_execute_query(
tcx,
Q::query_state(tcx),
@@ -738,8 +761,7 @@
key,
lookup,
dep_node,
- query,
- compute,
+ &query,
);
if let Some(dep_node_index) = dep_node_index {
tcx.dep_context().dep_graph().read_index(dep_node_index)
@@ -747,36 +769,29 @@
Some(result)
}
-pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
+pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>)
where
Q: QueryDescription<CTX>,
Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- if Q::ANON {
- return false;
- }
+ // We may be concurrently trying both execute and force a query.
+ // Ensure that only one of them runs the query.
+ let cache = Q::query_cache(tcx);
+ let cached = cache.cache.lookup(cache, &key, |_, index| {
+ if unlikely!(tcx.dep_context().profiler().enabled()) {
+ tcx.dep_context().profiler().query_cache_hit(index.into());
+ }
+ });
- if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() {
- return false;
- }
-
- let key = if let Some(key) =
- <Q::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
- {
- key
- } else {
- return false;
+ let lookup = match cached {
+ Ok(()) => return,
+ Err(lookup) => lookup,
};
- let compute = Q::compute_fn(tcx, &key);
- force_query_impl(
- tcx,
- Q::query_state(tcx),
- Q::query_cache(tcx),
- key,
- *dep_node,
- &Q::VTABLE,
- compute,
- )
+ let query = Q::make_vtable(tcx, &key);
+ let state = Q::query_state(tcx);
+ debug_assert!(!query.anon);
+
+ try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), &query);
}
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index f1d3315d..bd27c16 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -23,6 +23,7 @@
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_metadata = { path = "../rustc_metadata" }
+rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2a562a0..3cf9d32 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -15,7 +15,7 @@
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
-use rustc_ast::{Block, FnKind, ForeignItem, ForeignItemKind, ImplKind, Item, ItemKind, NodeId};
+use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
@@ -145,17 +145,11 @@
} else {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
- let expn_id = if def_kind == DefKind::Mod {
- self.cstore().module_expansion_untracked(def_id, &self.session)
- } else {
- // FIXME: Parent expansions for enums and traits are not kept in metadata.
- ExpnId::root()
- };
Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, name),
- expn_id,
+ self.cstore().module_expansion_untracked(def_id, &self.session),
self.cstore().get_span_untracked(def_id, &self.session),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.map_or(false, |module| module.no_implicit_prelude),
@@ -886,7 +880,7 @@
}
// These items do not add names to modules.
- ItemKind::Impl(box ImplKind { of_trait: Some(..), .. }) => {
+ ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
}
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
@@ -973,6 +967,7 @@
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
@@ -1199,15 +1194,9 @@
// Mark the given macro as unused unless its name starts with `_`.
// Macro uses will remove items from this set, and the remaining
// items will be reported as `unused_macros`.
- fn insert_unused_macro(
- &mut self,
- ident: Ident,
- def_id: LocalDefId,
- node_id: NodeId,
- span: Span,
- ) {
+ fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) {
if !ident.as_str().starts_with('_') {
- self.r.unused_macros.insert(def_id, (node_id, span));
+ self.r.unused_macros.insert(def_id, (node_id, ident));
}
}
@@ -1251,7 +1240,7 @@
self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
} else {
self.r.check_reserved_macro_name(ident, res);
- self.insert_unused_macro(ident, def_id, item.id, span);
+ self.insert_unused_macro(ident, def_id, item.id);
}
self.r.visibilities.insert(def_id, vis);
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
@@ -1272,7 +1261,7 @@
_ => self.resolve_visibility(&item.vis),
};
if vis != ty::Visibility::Public {
- self.insert_unused_macro(ident, def_id, item.id, span);
+ self.insert_unused_macro(ident, def_id, item.id);
}
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
self.r.visibilities.insert(def_id, vis);
@@ -1386,7 +1375,7 @@
if ctxt == AssocCtxt::Trait {
let (def_kind, ns) = match item.kind {
AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
- AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) => {
+ AssocItemKind::Fn(box Fn { ref sig, .. }) => {
if sig.decl.has_self() {
self.r.has_self.insert(def_id);
}
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 760b746..6369912 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -32,7 +32,6 @@
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::pluralize;
-use rustc_middle::ty;
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
@@ -228,7 +227,7 @@
for import in self.potentially_unused_imports.iter() {
match import.kind {
_ if import.used.get()
- || import.vis.get() == ty::Visibility::Public
+ || import.vis.get().is_public()
|| import.span.is_dummy() =>
{
if let ImportKind::MacroUse = import.kind {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 05675e0..2e4cb4f 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -11,7 +11,7 @@
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_middle::bug;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::DefIdTree;
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
@@ -66,6 +66,8 @@
pub descr: &'static str,
pub path: Path,
pub accessible: bool,
+ /// An extra note that should be issued if this item is suggested
+ pub note: Option<String>,
}
/// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -418,6 +420,10 @@
err.span_label(span, label);
if let Some((suggestions, msg, applicability)) = suggestion {
+ if suggestions.is_empty() {
+ err.help(&msg);
+ return err;
+ }
err.multipart_suggestion(&msg, suggestions, applicability);
}
@@ -444,12 +450,24 @@
// let foo =...
// ^^^ given this Span
// ------- get this Span to have an applicable suggestion
+
+ // 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);
- if sp.lo().0 == 0 {
+
+ 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(sp.lo().0 - current.len() as u32));
+ let sp = sp.with_lo(BytePos(pos_for_suggestion));
err.span_suggestion(
sp,
&format!("consider using `{}` instead of `{}`", sugg, current),
@@ -725,7 +743,7 @@
suggestions.extend(
BUILTIN_ATTRIBUTES
.iter()
- .map(|(name, ..)| TypoSuggestion::typo_from_res(*name, res)),
+ .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)),
);
}
}
@@ -829,11 +847,22 @@
return;
}
+ // #90113: Do not count an inaccessible reexported item as a candidate.
+ if let NameBindingKind::Import { binding, .. } = name_binding.kind {
+ if this.is_accessible_from(binding.vis, parent_scope.module)
+ && !this.is_accessible_from(name_binding.vis, parent_scope.module)
+ {
+ return;
+ }
+ }
+
// collect results based on the filter function
// avoid suggesting anything from the same module in which we are resolving
+ // avoid suggesting anything with a hygienic name
if ident.name == lookup_ident.name
&& ns == namespace
&& !ptr::eq(in_module, parent_scope.module)
+ && !ident.span.normalize_to_macros_2_0().from_expansion()
{
let res = name_binding.res();
if filter_fn(res) {
@@ -863,11 +892,38 @@
}
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+ // See if we're recommending TryFrom, TryInto, or FromIterator and add
+ // a note about editions
+ let note = if let Some(did) = did {
+ let requires_note = !did.is_local()
+ && this.cstore().item_attrs(did, this.session).iter().any(
+ |attr| {
+ if attr.has_name(sym::rustc_diagnostic_item) {
+ [sym::TryInto, sym::TryFrom, sym::FromIterator]
+ .map(|x| Some(x))
+ .contains(&attr.value_str())
+ } else {
+ false
+ }
+ },
+ );
+
+ requires_note.then(|| {
+ format!(
+ "'{}' is included in the prelude starting in Edition 2021",
+ path_names_to_string(&path)
+ )
+ })
+ } else {
+ None
+ };
+
candidates.push(ImportSuggestion {
did,
descr: res.descr(),
path,
accessible: child_accessible,
+ note,
});
}
}
@@ -1156,14 +1212,9 @@
(b1, b2, misc1, misc2, false)
};
- let mut err = struct_span_err!(
- self.session,
- ident.span,
- E0659,
- "`{ident}` is ambiguous ({why})",
- why = kind.descr()
- );
+ let mut err = struct_span_err!(self.session, ident.span, E0659, "`{ident}` is ambiguous");
err.span_label(ident.span, "ambiguous name");
+ err.note(&format!("ambiguous because of {}", kind.descr()));
let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
@@ -1269,7 +1320,7 @@
);
let def_span = self.session.source_map().guess_head_span(binding.span);
let mut note_span = MultiSpan::from_span(def_span);
- if !first && binding.vis == ty::Visibility::Public {
+ if !first && binding.vis.is_public() {
note_span.push_span_label(def_span, "consider importing it directly".into());
}
err.span_note(note_span, &msg);
@@ -1327,7 +1378,7 @@
if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
{
// Insert a placeholder that's later replaced by `self`/`super`/etc.
- path.insert(0, Segment::from_ident(Ident::invalid()));
+ path.insert(0, Segment::from_ident(Ident::empty()));
}
_ => return None,
}
@@ -1471,9 +1522,7 @@
module: ModuleOrUniformRoot<'b>,
ident: Ident,
) -> Option<(Option<Suggestion>, Vec<String>)> {
- let mut crate_module = if let ModuleOrUniformRoot::Module(module) = module {
- module
- } else {
+ let ModuleOrUniformRoot::Module(mut crate_module) = module else {
return None;
};
@@ -1762,12 +1811,14 @@
return;
}
- let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
- let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+ let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+ Vec::new();
+ let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+ Vec::new();
candidates.iter().for_each(|c| {
(if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
- .push((path_names_to_string(&c.path), c.descr, c.did))
+ .push((path_names_to_string(&c.path), c.descr, c.did, &c.note))
});
// we want consistent results across executions, but candidates are produced
@@ -1790,6 +1841,10 @@
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() {
+ err.note(note);
+ }
+
if let Some(span) = use_placement_span {
for candidate in &mut accessible_path_strings {
// produce an additional newline to separate the new use statement
@@ -1818,7 +1873,7 @@
assert!(!inaccessible_path_strings.is_empty());
if inaccessible_path_strings.len() == 1 {
- let (name, descr, def_id) = &inaccessible_path_strings[0];
+ let (name, descr, def_id, note) = &inaccessible_path_strings[0];
let msg = format!("{} `{}` exists but is inaccessible", descr, name);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
@@ -1830,12 +1885,15 @@
} else {
err.note(&msg);
}
+ if let Some(note) = (*note).as_deref() {
+ err.note(note);
+ }
} else {
- let (_, descr_first, _) = &inaccessible_path_strings[0];
+ let (_, descr_first, _, _) = &inaccessible_path_strings[0];
let descr = if inaccessible_path_strings
.iter()
.skip(1)
- .all(|(_, descr, _)| descr == descr_first)
+ .all(|(_, descr, _, _)| descr == descr_first)
{
descr_first.to_string()
} else {
@@ -1846,7 +1904,7 @@
let mut has_colon = false;
let mut spans = Vec::new();
- for (name, _, def_id) in &inaccessible_path_strings {
+ for (name, _, def_id, _) in &inaccessible_path_strings {
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
let span = definitions.def_span(local_def_id);
let span = session.source_map().guess_head_span(span);
@@ -1866,6 +1924,10 @@
multi_span.push_span_label(span, format!("`{}`: not accessible", name));
}
+ for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ err.note(note);
+ }
+
err.span_note(multi_span, &msg);
}
}
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 515b2c3..bf4cece 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -164,7 +164,7 @@
import: Import { kind: ImportKind::ExternCrate { .. }, .. },
..
},
- ) => import.vis.get() == ty::Visibility::Public,
+ ) => import.vis.get().is_public(),
_ => false,
}
}
@@ -978,7 +978,7 @@
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = import.module_path.clone();
- full_path.push(Segment::from_ident(Ident::invalid()));
+ full_path.push(Segment::from_ident(Ident::empty()));
self.r.lint_if_path_starts_with_module(
import.crate_lint(),
&full_path,
@@ -1180,11 +1180,17 @@
let mut reexport_error = None;
let mut any_successful_reexport = false;
+ let mut crate_private_reexport = false;
self.r.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
let vis = import.vis.get();
if !binding.vis.is_at_least(vis, &*this) {
reexport_error = Some((ns, binding));
+ if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
+ if binding_def_id.is_top_level_module() {
+ crate_private_reexport = true;
+ }
+ }
} else {
any_successful_reexport = true;
}
@@ -1207,24 +1213,34 @@
import.span,
&msg,
);
- } else if ns == TypeNS {
- struct_span_err!(
- self.r.session,
- import.span,
- E0365,
- "`{}` is private, and cannot be re-exported",
- ident
- )
- .span_label(import.span, format!("re-export of private `{}`", ident))
- .note(&format!("consider declaring type or module `{}` with `pub`", ident))
- .emit();
} else {
- let msg = format!("`{}` is private, and cannot be re-exported", ident);
- let note_msg =
- format!("consider marking `{}` as `pub` in the imported module", ident,);
- struct_span_err!(self.r.session, import.span, E0364, "{}", &msg)
- .span_note(import.span, ¬e_msg)
- .emit();
+ let error_msg = if crate_private_reexport {
+ format!(
+ "`{}` is only public within the crate, and cannot be re-exported outside",
+ ident
+ )
+ } else {
+ format!("`{}` is private, and cannot be re-exported", ident)
+ };
+
+ if ns == TypeNS {
+ let label_msg = if crate_private_reexport {
+ format!("re-export of crate public `{}`", ident)
+ } else {
+ format!("re-export of private `{}`", ident)
+ };
+
+ struct_span_err!(self.r.session, import.span, E0365, "{}", error_msg)
+ .span_label(import.span, label_msg)
+ .note(&format!("consider declaring type or module `{}` with `pub`", ident))
+ .emit();
+ } else {
+ let note_msg =
+ format!("consider marking `{}` as `pub` in the imported module", ident);
+ struct_span_err!(self.r.session, import.span, E0364, "{}", error_msg)
+ .span_note(import.span, ¬e_msg)
+ .emit();
+ }
}
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 95633257..12123c9 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -431,6 +431,10 @@
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
+ fn visit_attribute(&mut self, _: &'ast Attribute) {
+ // We do not want to resolve expressions that appear in attributes,
+ // as they do not correspond to actual code.
+ }
fn visit_item(&mut self, item: &'ast Item) {
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
// Always report errors in items we just entered.
@@ -498,8 +502,8 @@
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
- ForeignItemKind::Fn(box FnKind(_, _, ref generics, _))
- | ForeignItemKind::TyAlias(box TyAliasKind(_, ref generics, ..)) => {
+ ForeignItemKind::Fn(box Fn { ref generics, .. })
+ | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item);
});
@@ -953,8 +957,8 @@
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind {
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, _))
- | ItemKind::Fn(box FnKind(_, _, ref generics, _)) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, .. })
+ | ItemKind::Fn(box Fn { ref generics, .. }) => {
self.compute_num_lifetime_params(item.id, generics);
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item)
@@ -968,7 +972,7 @@
self.resolve_adt(item, generics);
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
ref generics,
ref of_trait,
ref self_ty,
@@ -979,7 +983,7 @@
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
}
- ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref trait_items)) => {
+ ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -994,8 +998,8 @@
});
};
- this.with_trait_items(trait_items, |this| {
- for item in trait_items {
+ this.with_trait_items(items, |this| {
+ for item in items {
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
this.visit_ty(ty);
@@ -1015,10 +1019,10 @@
);
}
}
- AssocItemKind::Fn(box FnKind(_, _, generics, _)) => {
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(this, generics, item);
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, _)) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
walk_assoc_item(this, generics, item);
}
AssocItemKind::MacCall(_) => {
@@ -1338,7 +1342,7 @@
},
);
}
- AssocItemKind::Fn(box FnKind(.., generics, _)) => {
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
@@ -1363,12 +1367,9 @@
},
);
}
- AssocItemKind::TyAlias(box TyAliasKind(
- _,
- generics,
- _,
- _,
- )) => {
+ AssocItemKind::TyAlias(box TyAlias {
+ generics, ..
+ }) => {
debug!("resolve_implementation AssocItemKind::TyAlias");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
@@ -1994,7 +1995,7 @@
if ns == ValueNS {
let item_name = path.last().unwrap().ident;
let traits = self.traits_in_scope(item_name, ns);
- self.r.trait_map.as_mut().unwrap().insert(id, traits);
+ self.r.trait_map.insert(id, traits);
}
if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2479,12 +2480,12 @@
// the field name so that we can do some nice error reporting
// later on in typeck.
let traits = self.traits_in_scope(ident, ValueNS);
- self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
+ self.r.trait_map.insert(expr.id, traits);
}
ExprKind::MethodCall(ref segment, ..) => {
debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
let traits = self.traits_in_scope(segment.ident, ValueNS);
- self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
+ self.r.trait_map.insert(expr.id, traits);
}
_ => {
// Nothing to do.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 7b0dd82..d506931 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -333,7 +333,7 @@
let candidates = self
.r
.lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
- .drain(..)
+ .into_iter()
.filter(|ImportSuggestion { did, .. }| {
match (did, res.and_then(|res| res.opt_def_id())) {
(Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
@@ -1235,9 +1235,7 @@
if assoc_item.ident == ident {
return Some(match &assoc_item.kind {
ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
- ast::AssocItemKind::Fn(box ast::FnKind(_, sig, ..))
- if sig.decl.has_self() =>
- {
+ ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
AssocSuggestion::MethodWithSelf
}
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
@@ -1346,12 +1344,10 @@
} else {
// Search in module.
let mod_path = &path[..path.len() - 1];
- if let PathResult::Module(module) =
+ if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No)
{
- if let ModuleOrUniformRoot::Module(module) = module {
- self.r.add_module_candidates(module, &mut names, &filter_fn);
- }
+ self.r.add_module_candidates(module, &mut names, &filter_fn);
}
}
@@ -1502,6 +1498,7 @@
descr: "module",
path,
accessible: true,
+ note: None,
},
));
} else {
@@ -1552,8 +1549,8 @@
matches!(source, PathSource::TupleStruct(..)) || source.is_call();
if suggest_only_tuple_variants {
// Suggest only tuple variants regardless of whether they have fields and do not
- // suggest path with added parenthesis.
- let mut suggestable_variants = variants
+ // suggest path with added parentheses.
+ let suggestable_variants = variants
.iter()
.filter(|(.., kind)| *kind == CtorKind::Fn)
.map(|(variant, ..)| path_names_to_string(variant))
@@ -1579,7 +1576,7 @@
err.span_suggestions(
span,
&msg,
- suggestable_variants.drain(..),
+ suggestable_variants.into_iter(),
Applicability::MaybeIncorrect,
);
}
@@ -1637,7 +1634,7 @@
);
}
- let mut suggestable_variants_with_placeholders = variants
+ let suggestable_variants_with_placeholders = variants
.iter()
.filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
@@ -1662,7 +1659,7 @@
err.span_suggestions(
span,
msg,
- suggestable_variants_with_placeholders.drain(..),
+ suggestable_variants_with_placeholders.into_iter(),
Applicability::HasPlaceholders,
);
}
@@ -1813,12 +1810,10 @@
let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
!matches!(
p.kind,
- hir::GenericParamKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- ..
- } | hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Elided,
- }
+ hir::GenericParamKind::Type { synthetic: true, .. }
+ | hir::GenericParamKind::Lifetime {
+ kind: hir::LifetimeParamKind::Elided,
+ }
)
}) {
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
@@ -2045,12 +2040,10 @@
if let Some(param) = generics.params.iter().find(|p| {
!matches!(
p.kind,
- hir::GenericParamKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- ..
- } | hir::GenericParamKind::Lifetime {
- kind: hir::LifetimeParamKind::Elided
- }
+ hir::GenericParamKind::Type { synthetic: true, .. }
+ | hir::GenericParamKind::Lifetime {
+ kind: hir::LifetimeParamKind::Elided
+ }
)
}) {
(param.span.shrink_to_lo(), "'a, ".to_string())
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index eb6f302..39e710c 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -540,7 +540,7 @@
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
match tcx.def_kind(def_id) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx
.parent(def_id.to_def_id())
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
@@ -887,10 +887,7 @@
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
.generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .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);
@@ -1057,9 +1054,7 @@
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m);
- let def_id = if let Region::EarlyBound(_, def_id, _) = reg {
- def_id
- } else {
+ let Region::EarlyBound(_, def_id, _) = reg else {
bug!();
};
// We cannot predict what lifetimes are unused in opaque type.
@@ -1372,9 +1367,8 @@
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
})
.enumerate()
.map(|(late_bound_idx, param)| {
@@ -1471,10 +1465,7 @@
let binders_iter = trait_ref
.bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
@@ -1933,20 +1924,18 @@
break;
}
}
- hir::TyKind::Path(ref qpath) => {
- if let QPath::Resolved(_, path) = qpath {
- let last_segment = &path.segments[path.segments.len() - 1];
- let generics = last_segment.args();
- for arg in generics.args.iter() {
- if let GenericArg::Lifetime(lt) = arg {
- if lt.name.ident() == name {
- elide_use = Some(lt.span);
- break;
- }
+ hir::TyKind::Path(QPath::Resolved(_, path)) => {
+ let last_segment = &path.segments[path.segments.len() - 1];
+ let generics = last_segment.args();
+ for arg in generics.args.iter() {
+ if let GenericArg::Lifetime(lt) = arg {
+ if lt.name.ident() == name {
+ elide_use = Some(lt.span);
+ break;
}
}
- break;
}
+ break;
}
_ => {}
}
@@ -2239,19 +2228,14 @@
let binders: Vec<_> = generics
.params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. }
- if self.map.late_bound.contains(¶m.hir_id) =>
- {
- Some(param)
- }
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
+ && self.map.late_bound.contains(¶m.hir_id)
})
.enumerate()
.map(|(late_bound_idx, 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);
- r
+ late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
self.map.late_bound_vars.insert(hir_id, binders);
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9652c48..d17e887 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -13,8 +13,9 @@
#![feature(drain_filter)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
#![recursion_limit = "256"]
@@ -54,13 +55,14 @@
use rustc_middle::span_bug;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
+use rustc_query_system::ich::StableHashingContext;
use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
use rustc_session::lint;
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency};
-use rustc_span::source_map::{CachingSourceMapView, Spanned};
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
@@ -725,23 +727,21 @@
impl AmbiguityKind {
fn descr(self) -> &'static str {
match self {
- AmbiguityKind::Import => "name vs any other name during import resolution",
- AmbiguityKind::BuiltinAttr => "built-in attribute vs any other name",
- AmbiguityKind::DeriveHelper => "derive helper attribute vs any other name",
+ AmbiguityKind::Import => "multiple potential import sources",
+ AmbiguityKind::BuiltinAttr => "a name conflict with a builtin attribute",
+ AmbiguityKind::DeriveHelper => "a name conflict with a derive helper attribute",
AmbiguityKind::MacroRulesVsModularized => {
- "`macro_rules` vs non-`macro_rules` from other module"
+ "a conflict between a `macro_rules` name and a non-`macro_rules` name from another module"
}
AmbiguityKind::GlobVsOuter => {
- "glob import vs any other name from outer scope during import/macro resolution"
+ "a conflict between a name from a glob import and an outer scope during import or macro resolution"
}
- AmbiguityKind::GlobVsGlob => "glob import vs glob import in the same module",
+ AmbiguityKind::GlobVsGlob => "multiple glob imports of a name in the same module",
AmbiguityKind::GlobVsExpanded => {
- "glob import vs macro-expanded name in the same \
- module during import/macro resolution"
+ "a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution"
}
AmbiguityKind::MoreExpandedVsOuter => {
- "macro-expanded name vs less macro-expanded name \
- from outer scope during import/macro resolution"
+ "a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution"
}
}
}
@@ -930,7 +930,7 @@
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
export_map: ExportMap,
- trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
+ trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules.
/// Anonymous modules are pseudo-modules that are implicitly created around items
@@ -988,7 +988,7 @@
non_macro_attr: Lrc<SyntaxExtension>,
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
- unused_macros: FxHashMap<LocalDefId, (NodeId, Span)>,
+ unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>,
proc_macro_stubs: FxHashSet<LocalDefId>,
/// Traces collected during macro resolution and validated when it's complete.
single_segment_macro_resolutions:
@@ -1177,6 +1177,10 @@
&mut self.definitions
}
+ fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
+ StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
+ }
+
fn lint_buffer(&mut self) -> &mut LintBuffer {
&mut self.lint_buffer
}
@@ -1185,8 +1189,8 @@
self.next_node_id()
}
- fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
- std::mem::replace(&mut self.trait_map, None).unwrap()
+ fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<TraitCandidate>> {
+ self.trait_map.remove(&node)
}
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
@@ -1245,37 +1249,6 @@
}
}
-struct ExpandHasher<'a, 'b> {
- source_map: CachingSourceMapView<'a>,
- resolver: &'a Resolver<'b>,
-}
-
-impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> {
- #[inline]
- fn hash_spans(&self) -> bool {
- true
- }
-
- #[inline]
- fn def_span(&self, id: LocalDefId) -> Span {
- self.resolver.def_span(id)
- }
-
- #[inline]
- fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
- self.resolver.def_path_hash(def_id)
- }
-
- #[inline]
- fn span_data_to_lines_and_cols(
- &mut self,
- span: &rustc_span::SpanData,
- ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
- {
- self.source_map.span_data_to_lines_and_cols(span)
- }
-}
-
impl<'a> Resolver<'a> {
pub fn new(
session: &'a Session,
@@ -1363,7 +1336,7 @@
label_res_map: Default::default(),
extern_crate_map: Default::default(),
export_map: FxHashMap::default(),
- trait_map: Some(NodeMap::default()),
+ trait_map: NodeMap::default(),
underscore_disambiguator: 0,
empty_module,
module_map,
@@ -1456,13 +1429,6 @@
self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map)
}
- fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> {
- ExpandHasher {
- source_map: CachingSourceMapView::new(self.session.source_map()),
- resolver: self,
- }
- }
-
pub fn next_node_id(&mut self) -> NodeId {
let next = self
.next_node_id
@@ -2557,19 +2523,29 @@
} else {
(
format!("use of undeclared crate or module `{}`", ident),
- self.find_similarly_named_module_or_crate(
- ident.name,
- &parent_scope.module,
- )
- .map(|sugg| {
- (
- vec![(ident.span, sugg.to_string())],
+ if ident.name == sym::alloc {
+ Some((
+ vec![],
String::from(
- "there is a crate or module with a similar name",
+ "add `extern crate alloc` to use the `alloc` crate",
),
Applicability::MaybeIncorrect,
+ ))
+ } else {
+ self.find_similarly_named_module_or_crate(
+ ident.name,
+ &parent_scope.module,
)
- }),
+ .map(|sugg| {
+ (
+ vec![(ident.span, sugg.to_string())],
+ String::from(
+ "there is a crate or module with a similar name",
+ ),
+ Applicability::MaybeIncorrect,
+ )
+ })
+ },
)
}
} else {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 4f6e23d..28dbce0 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -315,8 +315,13 @@
}
fn check_unused_macros(&mut self) {
- for (_, &(node_id, span)) in self.unused_macros.iter() {
- self.lint_buffer.buffer_lint(UNUSED_MACROS, node_id, span, "unused macro definition");
+ for (_, &(node_id, ident)) in self.unused_macros.iter() {
+ self.lint_buffer.buffer_lint(
+ UNUSED_MACROS,
+ node_id,
+ ident.span,
+ &format!("unused macro definition: `{}`", ident.as_str()),
+ );
}
}
@@ -1128,6 +1133,7 @@
feature,
reason,
issue,
+ None,
is_soft,
span,
soft_handler,
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index f4567b3..f1a5282 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -236,7 +236,7 @@
id,
span,
name: ident.to_string(),
- qualname: format!("{}::{}", qualname, ident.to_string()),
+ qualname: format!("{}::{}", qualname, ident),
value: typ,
parent: None,
children: vec![],
@@ -889,7 +889,7 @@
// Rust uses the id of the pattern for var lookups, so we'll use it too.
if !self.span.filter_generated(ident.span) {
- let qualname = format!("{}${}", ident.to_string(), hir_id);
+ let qualname = format!("{}${}", ident, hir_id);
let id = id_from_hir_id(hir_id, &self.save_ctxt);
let span = self.span_from_span(ident.span);
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 543cd02..c7f8fe3 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -739,6 +739,7 @@
| HirDefKind::ForeignMod
| HirDefKind::LifetimeParam
| HirDefKind::AnonConst
+ | HirDefKind::InlineConst
| HirDefKind::Use
| HirDefKind::Field
| HirDefKind::GlobalAsm
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index e5369b4..df78e1b 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -589,6 +589,13 @@
}
}
+ fn emit_fieldless_enum_variant<const ID: usize>(
+ &mut self,
+ name: &str,
+ ) -> Result<(), Self::Error> {
+ escape_str(self.writer, name)
+ }
+
fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
@@ -885,6 +892,13 @@
}
}
+ fn emit_fieldless_enum_variant<const ID: usize>(
+ &mut self,
+ name: &str,
+ ) -> Result<(), Self::Error> {
+ escape_str(self.writer, name)
+ }
+
fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 6671c7c..96a2231 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -58,6 +58,20 @@
f(self)
}
+ // We put the field index in a const generic to allow the emit_usize to be
+ // compiled into a more efficient form. In practice, the variant index is
+ // known at compile-time, and that knowledge allows much more efficient
+ // codegen than we'd otherwise get. LLVM isn't always able to make the
+ // optimization that would otherwise be necessary here, likely due to the
+ // multiple levels of inlining and const-prop that are needed.
+ #[inline]
+ fn emit_fieldless_enum_variant<const ID: usize>(
+ &mut self,
+ _v_name: &str,
+ ) -> Result<(), Self::Error> {
+ self.emit_usize(ID)
+ }
+
#[inline]
fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
where
@@ -500,8 +514,8 @@
d.read_seq(|d, len| {
assert!(len == N);
let mut v = [0u8; N];
- for x in &mut v {
- *x = d.read_seq_elt(|d| Decodable::decode(d))?;
+ for i in 0..len {
+ v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
}
Ok(v)
})
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ac4bce7..ab3c122 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -37,7 +37,7 @@
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
-/// The different settings that the `-Z strip` flag can have.
+/// The different settings that the `-C strip` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum Strip {
/// Do not strip at all.
@@ -165,6 +165,18 @@
Disabled,
}
+/// Used with `-Z assert-incr-state`.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum IncrementalStateAssertion {
+ /// Found and loaded an existing session directory.
+ ///
+ /// Note that this says nothing about whether any particular query
+ /// will be found to be red or green.
+ Loaded,
+ /// Did not load an existing session directory.
+ NotLoaded,
+}
+
impl LinkerPluginLto {
pub fn enabled(&self) -> bool {
match *self {
@@ -174,6 +186,20 @@
}
}
+/// The different settings that can be enabled via the `-Z location-detail` flag.
+#[derive(Clone, PartialEq, Hash, Debug)]
+pub struct LocationDetail {
+ pub file: bool,
+ pub line: bool,
+ pub column: bool,
+}
+
+impl LocationDetail {
+ pub fn all() -> Self {
+ Self { file: true, line: true, column: true }
+ }
+}
+
#[derive(Clone, PartialEq, Hash, Debug)]
pub enum SwitchWithOptPath {
Enabled(Option<PathBuf>),
@@ -309,9 +335,10 @@
}
/// Parameter to control path trimming.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum TrimmedDefPaths {
/// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
+ #[default]
Never,
/// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
Always,
@@ -319,12 +346,6 @@
GoodPath,
}
-impl Default for TrimmedDefPaths {
- fn default() -> Self {
- Self::Never
- }
-}
-
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
@@ -512,6 +533,7 @@
TlsModels,
TargetSpec,
NativeStaticLibs,
+ StackProtectorStrategies,
}
#[derive(Copy, Clone)]
@@ -564,6 +586,7 @@
pub out_directory: PathBuf,
filestem: String,
pub single_output_file: Option<PathBuf>,
+ pub temps_directory: Option<PathBuf>,
pub outputs: OutputTypes,
}
@@ -578,12 +601,14 @@
out_directory: PathBuf,
out_filestem: String,
single_output_file: Option<PathBuf>,
+ temps_directory: Option<PathBuf>,
extra: String,
outputs: OutputTypes,
) -> Self {
OutputFilenames {
out_directory,
single_output_file,
+ temps_directory,
outputs,
filestem: format!("{}{}", out_filestem, extra),
}
@@ -594,7 +619,14 @@
.get(&flavor)
.and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
- .unwrap_or_else(|| self.temp_path(flavor, None))
+ .unwrap_or_else(|| self.output_path(flavor))
+ }
+
+ /// Gets the output path where a compilation artifact of the given type
+ /// should be placed on disk.
+ pub fn output_path(&self, flavor: OutputType) -> PathBuf {
+ let extension = flavor.extension();
+ self.with_directory_and_extension(&self.out_directory, &extension)
}
/// Gets the path where a compilation artifact of the given type for the
@@ -629,11 +661,17 @@
extension.push_str(ext);
}
- self.with_extension(&extension)
+ let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
+
+ self.with_directory_and_extension(&temps_directory, &extension)
}
pub fn with_extension(&self, extension: &str) -> PathBuf {
- let mut path = self.out_directory.join(&self.filestem);
+ self.with_directory_and_extension(&self.out_directory, extension)
+ }
+
+ fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
+ let mut path = directory.join(&self.filestem);
path.set_extension(extension);
path
}
@@ -674,6 +712,7 @@
impl Default for Options {
fn default() -> Options {
Options {
+ assert_incr_state: None,
crate_types: Vec::new(),
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
@@ -900,7 +939,7 @@
pub(super) fn build_target_config(
opts: &Options,
target_override: Option<Target>,
- sysroot: &PathBuf,
+ sysroot: &Path,
) -> Target {
let target_result = target_override.map_or_else(
|| Target::search(&opts.target_triple, sysroot),
@@ -1067,8 +1106,8 @@
"print",
"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]",
+ target-cpus|target-features|relocation-models|code-models|\
+ tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1484,6 +1523,7 @@
"code-models" => PrintRequest::CodeModels,
"tls-models" => PrintRequest::TlsModels,
"native-static-libs" => PrintRequest::NativeStaticLibs,
+ "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
"target-spec-json" => {
if dopts.unstable_options {
PrintRequest::TargetSpec
@@ -1596,6 +1636,21 @@
}
}
+crate fn parse_assert_incr_state(
+ opt_assertion: &Option<String>,
+ error_format: ErrorOutputType,
+) -> Option<IncrementalStateAssertion> {
+ match opt_assertion {
+ Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
+ Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
+ Some(s) => early_error(
+ error_format,
+ &format!("unexpected incremental state assertion value: {}", s),
+ ),
+ None => None,
+ }
+}
+
fn parse_native_lib_kind(
matches: &getopts::Matches,
kind: &str,
@@ -1985,6 +2040,9 @@
let incremental = cg.incremental.as_ref().map(PathBuf::from);
+ let assert_incr_state =
+ parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
+
if debugging_opts.profile && incremental.is_some() {
early_error(
error_format,
@@ -2149,6 +2207,7 @@
};
Options {
+ assert_incr_state,
crate_types,
optimize: opt_level,
debuginfo,
@@ -2422,7 +2481,7 @@
use super::LdImpl;
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
- LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
+ LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
@@ -2432,7 +2491,9 @@
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
- use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
+ use rustc_target::spec::{
+ RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+ };
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
@@ -2506,6 +2567,7 @@
Edition,
LinkerPluginLto,
SplitDebuginfo,
+ StackProtector,
SwitchWithOptPath,
SymbolManglingVersion,
SourceFileHashAlgorithm,
@@ -2513,6 +2575,7 @@
Option<LdImpl>,
OutputType,
RealFileName,
+ LocationDetail,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 6c86f86..399b616 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,4 +1,5 @@
#![feature(crate_visibility_modifier)]
+#![feature(derive_default_enum)]
#![feature(min_specialization)]
#![feature(once_cell)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b3d36b3..4165e75 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -4,9 +4,10 @@
use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
-
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
-use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
+use rustc_target::spec::{
+ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
@@ -150,6 +151,7 @@
/// If `Some`, enable incremental compilation, using the given
/// directory to store intermediate results.
incremental: Option<PathBuf> [UNTRACKED],
+ assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED],
debugging_opts: DebuggingOptions [SUBSTRUCT],
prints: Vec<PrintRequest> [UNTRACKED],
@@ -219,7 +221,7 @@
/// generated code to parse an option into its respective field in the struct. There are a few
/// hand-written parsers for parsing specific types of values in this module.
macro_rules! options {
- ($struct_name:ident, $stat:ident, $prefix:expr, $outputname:expr,
+ ($struct_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr,
$($( #[$attr:meta] )* $opt:ident : $t:ty = (
$init:expr,
$parse:ident,
@@ -264,13 +266,15 @@
}
pub const $stat: OptionDescrs<$struct_name> =
- &[ $( (stringify!($opt), $opt, desc::$parse, $desc) ),* ];
+ &[ $( (stringify!($opt), $optmod::$opt, desc::$parse, $desc) ),* ];
+ mod $optmod {
$(
- fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
- parse::$parse(&mut redirect_field!(cg.$opt), v)
+ pub(super) fn $opt(cg: &mut super::$struct_name, v: Option<&str>) -> bool {
+ super::parse::$parse(&mut redirect_field!(cg.$opt), v)
}
)*
+ }
) }
@@ -351,8 +355,7 @@
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`, `hwaddress`, `leak`, `memory` or `thread`";
+ pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` 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`";
@@ -368,6 +371,8 @@
"either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
pub const parse_linker_plugin_lto: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+ pub const parse_location_detail: &str =
+ "comma seperated list of location details to track: `file`, `line`, or `column`";
pub const parse_switch_with_opt_path: &str =
"an optional path to the profiling data output directory";
pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
@@ -382,6 +387,8 @@
pub const parse_split_debuginfo: &str =
"one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
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`)";
}
mod parse {
@@ -484,6 +491,25 @@
}
}
+ crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
+ if let Some(v) = v {
+ ld.line = false;
+ ld.file = false;
+ ld.column = false;
+ for s in v.split(',') {
+ match s {
+ "file" => ld.file = true,
+ "line" => ld.line = true,
+ "column" => ld.column = true,
+ _ => return false,
+ }
+ }
+ true
+ } else {
+ false
+ }
+ }
+
crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
match v {
Some(s) => {
@@ -584,6 +610,7 @@
for s in v.split(',') {
*slot |= match s {
"address" => SanitizerSet::ADDRESS,
+ "cfi" => SanitizerSet::CFI,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"thread" => SanitizerSet::THREAD,
@@ -860,7 +887,7 @@
match v {
Some(s) => {
if !slot.is_empty() {
- slot.push_str(",");
+ slot.push(',');
}
slot.push_str(s);
true
@@ -894,10 +921,18 @@
}
true
}
+
+ crate fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
+ match v.and_then(|s| StackProtector::from_str(s).ok()) {
+ Some(ssp) => *slot = ssp,
+ _ => return false,
+ }
+ true
+ }
}
options! {
- CodegenOptions, CG_OPTIONS, "C", "codegen",
+ CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
// This list is in alphabetical order.
//
@@ -992,6 +1027,8 @@
"use soft float ABI (*eabihf targets only) (default: no)"),
split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
"how to handle split-debuginfo, a platform-specific option"),
+ strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
+ "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select target processor (`rustc --print target-cpus` for details)"),
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
@@ -1006,7 +1043,7 @@
}
options! {
- DebuggingOptions, DB_OPTIONS, "Z", "debugging",
+ DebuggingOptions, DB_OPTIONS, dbopts, "Z", "debugging",
// This list is in alphabetical order.
//
@@ -1021,6 +1058,9 @@
"make cfg(version) treat the current version as incomplete (default: no)"),
asm_comments: bool = (false, parse_bool, [TRACKED],
"generate comments into the assembly (may change behavior) (default: no)"),
+ assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
+ "assert that the incremental cache is in given state: \
+ either `loaded` or `not-loaded`."),
ast_json: bool = (false, parse_bool, [UNTRACKED],
"print the AST as JSON and halt (default: no)"),
ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
@@ -1091,8 +1131,6 @@
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
- force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "force overflow checks on or off"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable (default: no)"),
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
@@ -1152,6 +1190,9 @@
"a list LLVM plugins to enable (space separated)"),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
"generate JSON tracing data file from LLVM data (default: no)"),
+ location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
+ "comma seperated list of location details to be tracked when using caller_location \
+ valid options are `file`, `line`, and `column` (default: all)"),
ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate (default: no)"),
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
@@ -1169,7 +1210,7 @@
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
+ "emit noalias metadata for mutable references (default: yes)"),
new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
"use new LLVM pass manager (default: no)"),
nll_facts: bool = (false, parse_bool, [UNTRACKED],
@@ -1190,6 +1231,8 @@
"compile without linking"),
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+ no_unique_section_names: bool = (false, parse_bool, [TRACKED],
+ "do not use unique names for text and data sections when -Z function-sections is used"),
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
"prevent automatic injection of the profiler_builtins crate"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
@@ -1207,6 +1250,8 @@
and set the maximum total size of a const allocation for which this is allowed (default: never)"),
perf_stats: bool = (false, parse_bool, [UNTRACKED],
"print some performance-related statistics (default: no)"),
+ pick_stable_methods_before_any_unstable: bool = (true, parse_bool, [TRACKED],
+ "try to pick stable methods first before picking any unstable methods (default: yes)"),
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
"whether to use the PLT when calling into shared libraries;
only has effect for PIC code on systems with ELF binaries
@@ -1283,7 +1328,7 @@
"specify the events recorded by the self profiler;
for example: `-Z self-profile-events=default,query-keys`
all options: none, all, default, generic-activity, query-provider, query-cache-hit
- query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm"),
+ query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
@@ -1295,6 +1340,8 @@
"exclude spans when debug-printing compiler state (default: no)"),
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
+ stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
+ "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
@@ -1305,6 +1352,8 @@
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
teach: bool = (false, parse_bool, [TRACKED],
"show extended diagnostic help (default: no)"),
+ temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
+ "the directory the intermediate files are written to"),
terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current terminal width"),
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index a007b53..d5b5203 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -119,8 +119,13 @@
pub config: CrateConfig,
pub edition: Edition,
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
- /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
+ /// Places where raw identifiers were used. This is used to avoid complaining about idents
+ /// clashing with keywords in new editions.
pub raw_identifier_spans: Lock<Vec<Span>>,
+ /// Places where identifiers that contain invalid Unicode codepoints but that look like they
+ /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to
+ /// provide a single error per unique incorrect identifier.
+ pub bad_unicode_identifiers: Lock<FxHashMap<Symbol, Vec<Span>>>,
source_map: Lrc<SourceMap>,
pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
/// Contains the spans of block expressions that could have been incomplete based on the
@@ -160,6 +165,7 @@
edition: ExpnId::root().expn_data().edition,
missing_fragment_specifiers: Default::default(),
raw_identifier_spans: Lock::new(Vec::new()),
+ bad_unicode_identifiers: Lock::new(Default::default()),
source_map,
buffered_lints: Lock::new(vec![]),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
@@ -174,9 +180,14 @@
}
}
- pub fn with_silent_emitter() -> Self {
+ pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
- let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
+ let fatal_handler = Handler::with_tty_emitter(ColorConfig::Auto, false, None, None);
+ let handler = Handler::with_emitter(
+ false,
+ None,
+ Box::new(SilentEmitter { fatal_handler, fatal_note }),
+ );
ParseSess::with_span_handler(handler, sm)
}
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index b6ba6cc..5410955 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -27,7 +27,9 @@
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
-use rustc_target::spec::{SanitizerSet, SplitDebuginfo, Target, TargetTriple, TlsModel};
+use rustc_target::spec::{
+ SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+};
use std::cell::{self, RefCell};
use std::env;
@@ -411,7 +413,7 @@
self.diagnostic().abort_if_errors();
}
pub fn compile_status(&self) -> Result<(), ErrorReported> {
- if self.has_errors() {
+ if self.diagnostic().has_errors_or_lint_errors() {
self.diagnostic().emit_stashed_diagnostics();
Err(ErrorReported)
} else {
@@ -672,12 +674,11 @@
pub fn is_nightly_build(&self) -> bool {
self.opts.unstable_features.is_nightly_build()
}
+ pub fn is_sanitizer_cfi_enabled(&self) -> bool {
+ self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI)
+ }
pub fn overflow_checks(&self) -> bool {
- self.opts
- .cg
- .overflow_checks
- .or(self.opts.debugging_opts.force_overflow_checks)
- .unwrap_or(self.opts.debug_assertions)
+ self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions)
}
/// Check whether this compile session and crate type use static crt.
@@ -729,6 +730,14 @@
self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
}
+ pub fn stack_protector(&self) -> StackProtector {
+ if self.target.options.supports_stack_protector {
+ self.opts.debugging_opts.stack_protector
+ } else {
+ StackProtector::None
+ }
+ }
+
pub fn target_can_use_split_dwarf(&self) -> bool {
!self.target.is_like_windows && !self.target.is_like_osx
}
@@ -1398,6 +1407,25 @@
disable it using `-C target-feature=-crt-static`",
);
}
+
+ // LLVM CFI requires LTO.
+ if sess.is_sanitizer_cfi_enabled() {
+ if sess.opts.cg.lto == config::LtoCli::Unspecified
+ || sess.opts.cg.lto == config::LtoCli::No
+ || sess.opts.cg.lto == config::LtoCli::Thin
+ {
+ sess.err("`-Zsanitizer=cfi` requires `-Clto`");
+ }
+ }
+
+ if sess.opts.debugging_opts.stack_protector != StackProtector::None {
+ if !sess.target.options.supports_stack_protector {
+ sess.warn(&format!(
+ "`-Z stack-protector={}` is not supported for target {} and will be ignored",
+ sess.opts.debugging_opts.stack_protector, sess.opts.target_triple
+ ))
+ }
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index aa15feb..d590776 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -709,7 +709,7 @@
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
/// }
- /// n(f);
+ /// n!(f);
/// macro n($j:ident) {
/// use foo::*;
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
@@ -1099,18 +1099,11 @@
OpaqueTy,
Async,
Await,
- ForLoop(ForLoopLoc),
+ ForLoop,
LetElse,
WhileLoop,
}
-/// A location in the desugaring of a `for` loop
-#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
-pub enum ForLoopLoc {
- Head,
- IntoIter,
-}
-
impl DesugaringKind {
/// The description wording should combine well with "desugaring of {}".
pub fn descr(self) -> &'static str {
@@ -1121,7 +1114,7 @@
DesugaringKind::QuestionMark => "operator `?`",
DesugaringKind::TryBlock => "`try` block",
DesugaringKind::OpaqueTy => "`impl Trait`",
- DesugaringKind::ForLoop(_) => "`for` loop",
+ DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::LetElse => "`let...else`",
DesugaringKind::WhileLoop => "`while` loop",
}
diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs
index cea7871..c10968e 100644
--- a/compiler/rustc_span/src/lev_distance.rs
+++ b/compiler/rustc_span/src/lev_distance.rs
@@ -58,34 +58,28 @@
let lookup = &lookup.as_str();
let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
- let (case_insensitive_match, levenshtein_match) = name_vec
+ // 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);
+ }
+ 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:
- // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
- .fold((None, None), |result, (candidate, dist)| {
- (
- if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
- Some(candidate)
- } else {
- result.0
- },
- match result.1 {
- None => Some((candidate, dist)),
- Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
- },
- )
+ // (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) }),
});
- // Priority of matches:
- // 1. Exact case insensitive match
- // 2. Levenshtein distance match
- // 3. Sorted word match
- if let Some(candidate) = case_insensitive_match {
- Some(candidate)
- } else if levenshtein_match.is_some() {
+ if levenshtein_match.is_some() {
levenshtein_match.map(|(candidate, _)| candidate)
} else {
find_match_by_sorted_words(name_vec, lookup)
diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs
index 11822e9..b32f8d3 100644
--- a/compiler/rustc_span/src/lev_distance/tests.rs
+++ b/compiler/rustc_span/src/lev_distance/tests.rs
@@ -31,15 +31,11 @@
assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None);
- let input = vec![Symbol::intern("aAAA")];
- assert_eq!(
- find_best_match_for_name(&input, Symbol::intern("AAAA"), None),
- Some(Symbol::intern("aAAA"))
- );
-
let input = vec![Symbol::intern("AAAA")];
- // Returns None because `lev_distance > max_dist / 3`
- assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None);
+ assert_eq!(
+ find_best_match_for_name(&input, Symbol::intern("aaaa"), None),
+ Some(Symbol::intern("AAAA"))
+ );
let input = vec![Symbol::intern("AAAA")];
assert_eq!(
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 032ae73..66c0114 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -41,7 +41,7 @@
use edition::Edition;
pub mod hygiene;
use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind};
+pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
pub mod def_id;
use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
@@ -194,10 +194,8 @@
encoder.emit_enum(|encoder| match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
- Ok({
- encoder
- .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- })
+ encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ Ok(())
})
}
@@ -206,12 +204,9 @@
// For privacy and build reproducibility, we must not embed host-dependant path in artifacts
// if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
- Ok({
- encoder
- .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- encoder
- .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
- })
+ encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ encoder.emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
+ Ok(())
}),
})
}
@@ -1940,6 +1935,7 @@
#[derive(Debug)]
pub struct SourceFileAndLine {
pub sf: Lrc<SourceFile>,
+ /// Index of line, starting from 0.
pub line: usize,
}
#[derive(Debug)]
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 74958c4..7414d20 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -593,14 +593,19 @@
}
pub fn span_to_margin(&self, sp: Span) -> Option<usize> {
- match self.span_to_prev_source(sp) {
- Err(_) => None,
- Ok(source) => {
- let last_line = source.rsplit_once('\n').unwrap_or(("", &source)).1;
+ Some(self.indentation_before(sp)?.len())
+ }
- Some(last_line.len() - last_line.trim_start().len())
- }
- }
+ pub fn indentation_before(&self, sp: Span) -> Option<String> {
+ self.span_to_source(sp, |src, start_index, _| {
+ let before = &src[..start_index];
+ let last_line = before.rsplit_once('\n').map_or(before, |(_, last)| last);
+ Ok(last_line
+ .split_once(|c: char| !c.is_whitespace())
+ .map_or(last_line, |(indent, _)| indent)
+ .to_string())
+ })
+ .ok()
}
/// Returns the source snippet as `String` before the given `Span`.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 16205ad..247d69d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -269,8 +269,8 @@
__D,
__H,
__S,
- __next,
__try_var,
+ _args,
_d,
_e,
_task_context,
@@ -307,6 +307,7 @@
alloc_layout,
alloc_zeroed,
allocator,
+ allocator_api,
allocator_internals,
allow,
allow_fail,
@@ -327,6 +328,9 @@
as_ptr,
as_str,
asm,
+ asm_const,
+ asm_experimental_arch,
+ asm_sym,
assert,
assert_inhabited,
assert_macro,
@@ -355,7 +359,6 @@
await_macro,
bang,
begin_panic,
- begin_panic_fmt,
bench,
bin,
bind_by_move_pattern_guards,
@@ -408,6 +411,7 @@
cfg_target_thread_local,
cfg_target_vendor,
cfg_version,
+ cfi,
char,
client,
clippy,
@@ -675,6 +679,7 @@
gen_future,
gen_kill,
generator,
+ generator_return,
generator_state,
generators,
generic_arg_infer,
@@ -728,6 +733,7 @@
inlateout,
inline,
inline_const,
+ inline_const_pat,
inout,
instruction_set,
intel,
@@ -1128,7 +1134,6 @@
rustc_partition_reused,
rustc_peek,
rustc_peek_definite_init,
- rustc_peek_indirectly_mutable,
rustc_peek_liveness,
rustc_peek_maybe_init,
rustc_peek_maybe_uninit,
@@ -1143,14 +1148,15 @@
rustc_specialization_trait,
rustc_stable,
rustc_std_internal_symbol,
+ rustc_strict_coherence,
rustc_symbol_name,
- rustc_synthetic,
rustc_test_marker,
rustc_then_this_would_need,
rustc_trivial_field_reads,
rustc_unsafe_specialization_marker,
rustc_variance,
rustdoc,
+ rustdoc_internals,
rustfmt,
rvalue_static_promotion,
s,
@@ -1340,6 +1346,7 @@
type_alias_enum_variants,
type_alias_impl_trait,
type_ascription,
+ type_changing_struct_update,
type_id,
type_length_limit,
type_macros,
@@ -1454,7 +1461,7 @@
}
#[inline]
- pub fn invalid() -> Ident {
+ pub fn empty() -> Ident {
Ident::with_dummy_span(kw::Empty)
}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 220c9f7..bb7b452 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -103,8 +103,9 @@
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
+use rustc_target::abi::call::FnAbi;
use tracing::debug;
@@ -150,6 +151,11 @@
ty::SymbolName::new(tcx, &symbol_name)
}
+/// This function computes the typeid for the given function ABI.
+pub fn typeid_for_fnabi(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+ v0::mangle_typeid_for_fnabi(tcx, fn_abi)
+}
+
/// Computes the symbol name for the given instance. This function will call
/// `compute_instantiating_crate` if it needs to factor the instantiating crate
/// into the symbol name.
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 521730d..0363ddb 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -9,6 +9,7 @@
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_target::abi::call::FnAbi;
use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;
@@ -55,6 +56,41 @@
std::mem::take(&mut cx.out)
}
+pub(super) fn mangle_typeid_for_fnabi(
+ _tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+) -> String {
+ // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
+ // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
+ // associated with a type identifier (i.e., test type membership).
+ //
+ // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
+ // type metadata identifiers for function pointers. The typeinfo name encoding is a
+ // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
+ //
+ // For cross-language LLVM CFI support, a compatible encoding must be used by either
+ //
+ // a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
+ // type encodings[4]), or at least types used at the FFI boundary.
+ // b. Reducing the types to the least common denominator between types used by Clang (or at
+ // least types used at the FFI boundary) and Rust compilers (if even possible).
+ // c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
+ // possibly other compilers).
+ //
+ // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
+ // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
+ // code. Option (c) would require changes to Clang to use the new ABI.
+ //
+ // [1] https://llvm.org/docs/TypeMetadata.html
+ // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
+ // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
+ // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
+ //
+ // FIXME(rcvalle): See comment above.
+ let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
+ format!("typeid{}", arg_count)
+}
+
struct BinderLevel {
/// The range of distances from the root of what's
/// being printed, to the lifetimes in a binder.
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index d9eb299..4768c9e 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -68,8 +68,10 @@
const NonNull = 1 << 3;
const ReadOnly = 1 << 4;
const InReg = 1 << 5;
- // NoAlias on &mut arguments can only be used with LLVM >= 12 due to miscompiles
- // in earlier versions. FIXME: Remove this distinction once possible.
+ // Due to past miscompiles in LLVM, we use a separate attribute for
+ // &mut arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled
+ // with the `-Zmutable-noalias` debugging option.
const NoAliasMutRef = 1 << 6;
}
}
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 99699c5..bff1324 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -189,6 +189,7 @@
S390x,
SpirV,
Wasm32,
+ Wasm64,
Bpf,
}
@@ -212,6 +213,7 @@
"s390x" => Ok(Self::S390x),
"spirv" => Ok(Self::SpirV),
"wasm32" => Ok(Self::Wasm32),
+ "wasm64" => Ok(Self::Wasm64),
"bpf" => Ok(Self::Bpf),
_ => Err(()),
}
@@ -318,7 +320,7 @@
InlineAsmArch::SpirV => {
Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
- InlineAsmArch::Wasm32 => {
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
InlineAsmArch::Bpf => {
@@ -529,7 +531,9 @@
}
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
- InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
+ Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?)
+ }
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
})
}
@@ -725,7 +729,7 @@
spirv::fill_reg_map(arch, has_feature, target, &mut map);
map
}
- InlineAsmArch::Wasm32 => {
+ InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
let mut map = wasm::regclass_map();
wasm::fill_reg_map(arch, has_feature, target, &mut map);
map
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index dc91f12..f01ff02 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -2,11 +2,11 @@
pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
- base.cpu = "apple-a12".to_string();
+ base.cpu = "apple-a14".to_string();
base.max_atomic_width = Some(128);
// FIXME: The leak sanitizer currently fails the tests, see #88132.
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
@@ -14,14 +14,13 @@
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
- let arch = "aarch64";
- let llvm_target = super::apple_base::macos_llvm_target(&arch);
+ let llvm_target = super::apple_base::macos_llvm_target("arm64");
Target {
llvm_target,
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
- arch: arch.to_string(),
+ arch: "aarch64".to_string(),
options: TargetOptions {
mcount: "\u{1}mcount".to_string(),
frame_pointer: FramePointer::NonLeaf,
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
index 71ee6de..a393858 100644
--- a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
@@ -8,6 +8,7 @@
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
options: TargetOptions {
+ features: "+outline-atomics".to_string(),
max_atomic_width: Some(128),
mcount: "\u{1}_mcount".to_string(),
endian: Endian::Big,
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
index e05360e..e75100f 100644
--- a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -12,6 +12,7 @@
arch: "aarch64".to_string(),
options: TargetOptions {
abi: "ilp32".to_string(),
+ features: "+outline-atomics".to_string(),
mcount: "\u{1}_mcount".to_string(),
endian: Endian::Big,
..base
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
index 56d71df..05e0c65 100644
--- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
@@ -8,7 +8,7 @@
arch: "aarch64".to_string(),
options: TargetOptions {
max_atomic_width: Some(128),
- supported_sanitizers: SanitizerSet::ADDRESS,
+ supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI,
..super::fuchsia_base::opts()
},
}
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index 409cab7..1e9abbb 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -14,7 +14,7 @@
// 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::HWADDRESS,
+ supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
..super::android_base::opts()
},
}
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
index 0caecd2..03ee7ba 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -9,6 +9,7 @@
options: TargetOptions {
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::MEMORY
| SanitizerSet::THREAD,
..super::freebsd_base::opts()
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 3e92ecb..850381f 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -7,9 +7,11 @@
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
options: TargetOptions {
+ features: "+outline-atomics".to_string(),
mcount: "\u{1}_mcount".to_string(),
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::THREAD
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
index 8522405..1c931d5 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
@@ -8,6 +8,7 @@
arch: "aarch64".to_string(),
options: TargetOptions {
abi: "ilp32".to_string(),
+ features: "+outline-atomics".to_string(),
max_atomic_width: Some(128),
mcount: "\u{1}_mcount".to_string(),
..super::linux_gnu_base::opts()
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index a21b784..db6aee5 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -13,8 +13,10 @@
// warnings about the usage of ELF TLS.
//
// Here we detect what version is being requested, defaulting to 10.7. ELF
- // TLS is flagged as enabled if it looks to be supported.
- let version = macos_deployment_target();
+ // TLS is flagged as enabled if it looks to be supported. The architecture
+ // only matters for default deployment target which is 11.0 for ARM64 and
+ // 10.7 for everything else.
+ let has_elf_tls = macos_deployment_target("x86_64") >= (10, 7);
TargetOptions {
os: os.to_string(),
@@ -31,7 +33,7 @@
has_rpath: true,
dll_suffix: ".dylib".to_string(),
archive_format: "darwin".to_string(),
- has_elf_tls: version >= (10, 7),
+ has_elf_tls,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
eh_frame_header: false,
@@ -63,12 +65,17 @@
.and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}
-fn macos_deployment_target() -> (u32, u32) {
- deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
+fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
+ if arch == "arm64" { (11, 0) } else { (10, 7) }
+}
+
+fn macos_deployment_target(arch: &str) -> (u32, u32) {
+ deployment_target("MACOSX_DEPLOYMENT_TARGET")
+ .unwrap_or_else(|| macos_default_deployment_target(arch))
}
pub fn macos_llvm_target(arch: &str) -> String {
- let (major, minor) = macos_deployment_target();
+ let (major, minor) = macos_deployment_target(arch);
format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}
diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
index 01f5c19..afe8bbb 100644
--- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
+++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, RelocModel, Target, TargetOptions};
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
///
@@ -36,7 +36,6 @@
features: "+vfp2".to_string(),
pre_link_args,
exe_suffix: ".elf".to_string(),
- panic_strategy: PanicStrategy::Abort,
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
index c55a46e..ce3dad2 100644
--- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
@@ -8,17 +8,14 @@
);
TargetOptions {
- os: "hermit".to_string(),
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
disable_redzone: true,
linker: Some("rust-lld".to_owned()),
executables: true,
- has_elf_tls: true,
pre_link_args,
panic_strategy: PanicStrategy::Abort,
position_independent_executables: true,
static_position_independent_executables: true,
- tls_model: TlsModel::InitialExec,
..Default::default()
}
}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ff5dfa3..0d49c7f 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -602,6 +602,7 @@
const MEMORY = 1 << 2;
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
+ const CFI = 1 << 5;
}
}
@@ -612,6 +613,7 @@
fn as_str(self) -> Option<&'static str> {
Some(match self {
SanitizerSet::ADDRESS => "address",
+ SanitizerSet::CFI => "cfi",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::THREAD => "thread",
@@ -644,6 +646,7 @@
fn into_iter(self) -> Self::IntoIter {
[
SanitizerSet::ADDRESS,
+ SanitizerSet::CFI,
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
SanitizerSet::THREAD,
@@ -709,6 +712,59 @@
}
}
+/// Controls use of stack canaries.
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
+pub enum StackProtector {
+ /// Disable stack canary generation.
+ None,
+
+ /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see
+ /// llvm/docs/LangRef.rst). This triggers stack canary generation in
+ /// functions which contain an array of a byte-sized type with more than
+ /// eight elements.
+ Basic,
+
+ /// On LLVM, mark all generated LLVM functions with the `sspstrong`
+ /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary
+ /// generation in functions which either contain an array, or which take
+ /// the address of a local variable.
+ Strong,
+
+ /// Generate stack canaries in all functions.
+ All,
+}
+
+impl StackProtector {
+ fn as_str(&self) -> &'static str {
+ match self {
+ StackProtector::None => "none",
+ StackProtector::Basic => "basic",
+ StackProtector::Strong => "strong",
+ StackProtector::All => "all",
+ }
+ }
+}
+
+impl FromStr for StackProtector {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<StackProtector, ()> {
+ Ok(match s {
+ "none" => StackProtector::None,
+ "basic" => StackProtector::Basic,
+ "strong" => StackProtector::Strong,
+ "all" => StackProtector::All,
+ _ => return Err(()),
+ })
+ }
+}
+
+impl fmt::Display for StackProtector {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
macro_rules! supported_targets {
( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
$(mod $module;)+
@@ -954,6 +1010,8 @@
("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
+
+ ("x86_64-unknown-none", x86_64_unknown_none),
}
/// Warnings encountered when parsing the target `json`.
@@ -1352,6 +1410,13 @@
/// Minimum number of bits in #[repr(C)] enum. Defaults to 32.
pub c_enum_min_bits: u64,
+
+ /// Whether or not the DWARF `.debug_aranges` section should be generated.
+ pub generate_arange_section: bool,
+
+ /// Whether the target supports stack canary checks. `true` by default,
+ /// since this is most common among tier 1 and tier 2 targets.
+ pub supports_stack_protector: bool,
}
impl Default for TargetOptions {
@@ -1457,6 +1522,8 @@
supported_sanitizers: SanitizerSet::empty(),
default_adjusted_cabi: None,
c_enum_min_bits: 32,
+ generate_arange_section: true,
+ supports_stack_protector: true,
}
}
}
@@ -1522,6 +1589,7 @@
AmdGpuKernel => self.arch == "amdgcn",
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
+ Thiscall { .. } => self.arch == "x86",
// On windows these fall-back to platform native calling convention (C) when the
// architecture is not supported.
//
@@ -1552,15 +1620,13 @@
// > convention is used.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
- Stdcall { .. } | Fastcall | Thiscall { .. } | 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 | Thiscall { .. } if self.arch == "x86" => 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 | Thiscall { .. } | Vectorcall => return None,
+ Stdcall { .. } | Fastcall | Vectorcall => return None,
})
}
@@ -1805,6 +1871,7 @@
for s in a {
base.$key_name |= match s.as_string() {
Some("address") => SanitizerSet::ADDRESS,
+ Some("cfi") => SanitizerSet::CFI,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("thread") => SanitizerSet::THREAD,
@@ -2042,6 +2109,8 @@
key!(supported_sanitizers, SanitizerSet)?;
key!(default_adjusted_cabi, Option<Abi>)?;
key!(c_enum_min_bits, u64);
+ key!(generate_arange_section, bool);
+ key!(supports_stack_protector, bool);
if base.is_builtin {
// This can cause unfortunate ICEs later down the line.
@@ -2066,7 +2135,7 @@
/// JSON decoding.
pub fn search(
target_triple: &TargetTriple,
- sysroot: &PathBuf,
+ sysroot: &Path,
) -> Result<(Target, TargetWarnings), String> {
use rustc_serialize::json;
use std::env;
@@ -2281,6 +2350,8 @@
target_option_val!(split_debuginfo);
target_option_val!(supported_sanitizers);
target_option_val!(c_enum_min_bits);
+ target_option_val!(generate_arange_section);
+ target_option_val!(supports_stack_protector);
if let Some(abi) = self.default_adjusted_cabi {
d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 083262c..ba32a31 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -44,6 +44,10 @@
// produce kernel functions that call other kernel functions.
// This behavior is not supported by PTX ISA.
merge_functions: MergeFunctions::Disabled,
+
+ // The LLVM backend does not support stack canaries for this target
+ supports_stack_protector: false,
+
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 86b1a75..69a404e 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -37,7 +37,7 @@
is_like_emscripten: true,
panic_strategy: PanicStrategy::Unwind,
post_link_args,
- families: vec!["unix".to_string()],
+ families: vec!["unix".to_string(), "wasm".to_string()],
..options
};
Target {
diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
index fb6526c..6b7dfbb 100644
--- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
@@ -23,11 +23,15 @@
// For now this target just never has an entry symbol no matter the output
// type, so unconditionally pass this.
clang_args.push("-Wl,--no-entry".to_string());
- options
- .pre_link_args
- .get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm))
- .unwrap()
- .push("--no-entry".to_string());
+
+ let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap();
+ lld_args.push("--no-entry".to_string());
+ lld_args.push("-mwasm64".to_string());
+
+ // Any engine that implements wasm64 will surely implement the rest of these
+ // features since they were all merged into the official spec by the time
+ // wasm64 was designed.
+ options.features = "+bulk-memory,+mutable-globals,+sign-ext,+nontrapping-fptoint".to_string();
Target {
llvm_target: "wasm64-unknown-unknown".to_string(),
diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs
index 4c954a1..24e9c62 100644
--- a/compiler/rustc_target/src/spec/wasm_base.rs
+++ b/compiler/rustc_target/src/spec/wasm_base.rs
@@ -128,6 +128,12 @@
// gdb scripts don't work on wasm blobs
emit_debug_gdb_scripts: false,
+ // There's more discussion of this at
+ // https://bugs.llvm.org/show_bug.cgi?id=52442 but the general result is
+ // that this isn't useful for wasm and has tricky issues with
+ // representation, so this is disabled.
+ generate_arange_section: false,
+
..Default::default()
}
}
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index 60fd429..22fdaab 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -13,7 +13,8 @@
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index aa65ebe..c253c0c 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -6,7 +6,7 @@
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
llvm_target: "x86_64-fuchsia".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
index 34b6d29..6aa0728 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
@@ -8,7 +8,7 @@
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index b5fc15f..24cc7ae 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -7,7 +7,8 @@
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-freebsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
index ec196a7..79ccf63 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -5,7 +5,7 @@
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
// LLVM does not currently have a separate illumos target,
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 085079e..c2484f2 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,8 +7,11 @@
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index 5ad243a..a5e7980 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -8,8 +8,11 @@
// 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::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index 9ba8628..bdb2be4 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -7,8 +7,11 @@
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs
new file mode 100644
index 0000000..722409d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs
@@ -0,0 +1,41 @@
+// Generic x86-64 target for bare-metal code - Floating point disabled
+//
+// Can be used in conjunction with the `target-feature` and
+// `target-cpu` compiler flags to opt-in more hardware-specific
+// features.
+
+use super::{
+ CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType,
+ Target, TargetOptions,
+};
+
+pub fn target() -> Target {
+ let opts = TargetOptions {
+ cpu: "x86-64".to_string(),
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+ stack_probes: StackProbeType::Call,
+ position_independent_executables: true,
+ static_position_independent_executables: true,
+ relro_level: RelroLevel::Full,
+ relocation_model: RelocModel::Pic,
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker: Some("rust-lld".to_owned()),
+ features:
+ "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
+ .to_string(),
+ executables: true,
+ disable_redzone: true,
+ panic_strategy: PanicStrategy::Abort,
+ code_model: Some(CodeModel::Kernel),
+ ..Default::default()
+ };
+ Target {
+ llvm_target: "x86_64-unknown-none-elf".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+ .to_string(),
+ arch: "x86_64".to_string(),
+ options: opts,
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 53afe4c..4c80483 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -152,11 +152,12 @@
},
cause,
);
- if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+ let errors = fulfillcx.select_where_possible(&self.infcx);
+ if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
return None;
}
let obligations = fulfillcx.pending_obligations();
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 017a7c4..1820e33 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -14,9 +14,11 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(drain_filter)]
+#![feature(derive_default_enum)]
#![feature(hash_drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index c220546..75d57d7 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1,61 +1,14 @@
-use crate::traits::{self, ObligationCause, PredicateObligation};
+use crate::traits;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::free_regions::FreeRegionRelations;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, InferCtxt, InferOk};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
use rustc_span::Span;
-use std::ops::ControlFlow;
-
-/// Whether member constraints should be generated for all opaque types
-#[derive(Debug)]
-pub enum GenerateMemberConstraints {
- /// The default, used by typeck
- WhenRequired,
- /// The borrow checker needs member constraints in any case where we don't
- /// have a `'static` bound. This is because the borrow checker has more
- /// flexibility in the values of regions. For example, given `f<'a, 'b>`
- /// the borrow checker can have an inference variable outlive `'a` and `'b`,
- /// but not be equal to `'static`.
- IfNoStaticBound,
-}
-
pub trait InferCtxtExt<'tcx> {
- fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
- &self,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T>;
-
- fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
-
- fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
- &self,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- mode: GenerateMemberConstraints,
- free_region_relations: &FRR,
- );
-
- /*private*/
- fn generate_member_constraint(
- &self,
- concrete_ty: Ty<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- first_own_region_index: usize,
- );
-
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
@@ -65,416 +18,6 @@
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
- /// Replaces all opaque types in `value` with fresh inference variables
- /// and creates appropriate obligations. For example, given the input:
- ///
- /// impl Iterator<Item = impl Debug>
- ///
- /// this method would create two type variables, `?0` and `?1`. It would
- /// return the type `?0` but also the obligations:
- ///
- /// ?0: Iterator<Item = ?1>
- /// ?1: Debug
- ///
- /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
- /// info about the `impl Iterator<..>` type and `?1` to info about
- /// the `impl Debug` type.
- ///
- /// # Parameters
- ///
- /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
- /// is defined
- /// - `body_id` -- the body-id with which the resulting obligations should
- /// be associated
- /// - `param_env` -- the in-scope parameter environment to be used for
- /// obligations
- /// - `value` -- the value within which we are instantiating opaque types
- /// - `value_span` -- the span where the value came from, used in error reporting
- fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
- &self,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T> {
- debug!(
- "instantiate_opaque_types(value={:?}, body_id={:?}, \
- param_env={:?}, value_span={:?})",
- value, body_id, param_env, value_span,
- );
- let mut instantiator =
- Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
- let value = instantiator.instantiate_opaque_types_in_map(value);
- InferOk { value, obligations: instantiator.obligations }
- }
-
- /// Given the map `opaque_types` containing the opaque
- /// `impl Trait` types whose underlying, hidden types are being
- /// inferred, this method adds constraints to the regions
- /// appearing in those underlying hidden types to ensure that they
- /// at least do not refer to random scopes within the current
- /// function. These constraints are not (quite) sufficient to
- /// guarantee that the regions are actually legal values; that
- /// final condition is imposed after region inference is done.
- ///
- /// # The Problem
- ///
- /// Let's work through an example to explain how it works. Assume
- /// the current function is as follows:
- ///
- /// ```text
- /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
- /// ```
- ///
- /// Here, we have two `impl Trait` types whose values are being
- /// inferred (the `impl Bar<'a>` and the `impl
- /// Bar<'b>`). Conceptually, this is sugar for a setup where we
- /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
- /// the return type of `foo`, we *reference* those definitions:
- ///
- /// ```text
- /// type Foo1<'x> = impl Bar<'x>;
- /// type Foo2<'x> = impl Bar<'x>;
- /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
- /// // ^^^^ ^^
- /// // | |
- /// // | substs
- /// // def_id
- /// ```
- ///
- /// As indicating in the comments above, each of those references
- /// is (in the compiler) basically a substitution (`substs`)
- /// applied to the type of a suitable `def_id` (which identifies
- /// `Foo1` or `Foo2`).
- ///
- /// Now, at this point in compilation, what we have done is to
- /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
- /// fresh inference variables C1 and C2. We wish to use the values
- /// of these variables to infer the underlying types of `Foo1` and
- /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
- /// constraints like:
- ///
- /// ```text
- /// for<'a> (Foo1<'a> = C1)
- /// for<'b> (Foo1<'b> = C2)
- /// ```
- ///
- /// For these equation to be satisfiable, the types `C1` and `C2`
- /// can only refer to a limited set of regions. For example, `C1`
- /// can only refer to `'static` and `'a`, and `C2` can only refer
- /// to `'static` and `'b`. The job of this function is to impose that
- /// constraint.
- ///
- /// Up to this point, C1 and C2 are basically just random type
- /// inference variables, and hence they may contain arbitrary
- /// regions. In fact, it is fairly likely that they do! Consider
- /// this possible definition of `foo`:
- ///
- /// ```text
- /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
- /// (&*x, &*y)
- /// }
- /// ```
- ///
- /// Here, the values for the concrete types of the two impl
- /// traits will include inference variables:
- ///
- /// ```text
- /// &'0 i32
- /// &'1 i32
- /// ```
- ///
- /// Ordinarily, the subtyping rules would ensure that these are
- /// sufficiently large. But since `impl Bar<'a>` isn't a specific
- /// type per se, we don't get such constraints by default. This
- /// is where this function comes into play. It adds extra
- /// constraints to ensure that all the regions which appear in the
- /// inferred type are regions that could validly appear.
- ///
- /// This is actually a bit of a tricky constraint in general. We
- /// want to say that each variable (e.g., `'0`) can only take on
- /// values that were supplied as arguments to the opaque type
- /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
- /// scope. We don't have a constraint quite of this kind in the current
- /// region checker.
- ///
- /// # The Solution
- ///
- /// We generally prefer to make `<=` constraints, since they
- /// integrate best into the region solver. To do that, we find the
- /// "minimum" of all the arguments that appear in the substs: that
- /// is, some region which is less than all the others. In the case
- /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
- /// all). Then we apply that as a least bound to the variables
- /// (e.g., `'a <= '0`).
- ///
- /// In some cases, there is no minimum. Consider this example:
- ///
- /// ```text
- /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
- /// ```
- ///
- /// Here we would report a more complex "in constraint", like `'r
- /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
- /// the hidden type).
- ///
- /// # Constrain regions, not the hidden concrete type
- ///
- /// Note that generating constraints on each region `Rc` is *not*
- /// the same as generating an outlives constraint on `Tc` iself.
- /// For example, if we had a function like this:
- ///
- /// ```rust
- /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
- /// (x, y)
- /// }
- ///
- /// // Equivalent to:
- /// type FooReturn<'a, T> = impl Foo<'a>;
- /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
- /// ```
- ///
- /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
- /// is an inference variable). If we generated a constraint that
- /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
- /// but this is not necessary, because the opaque type we
- /// create will be allowed to reference `T`. So we only generate a
- /// constraint that `'0: 'a`.
- ///
- /// # The `free_region_relations` parameter
- ///
- /// The `free_region_relations` argument is used to find the
- /// "minimum" of the regions supplied to a given opaque type.
- /// It must be a relation that can answer whether `'a <= 'b`,
- /// where `'a` and `'b` are regions that appear in the "substs"
- /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
- ///
- /// Note that we do not impose the constraints based on the
- /// generic regions from the `Foo1` definition (e.g., `'x`). This
- /// is because the constraints we are imposing here is basically
- /// the concern of the one generating the constraining type C1,
- /// which is the current function. It also means that we can
- /// take "implied bounds" into account in some cases:
- ///
- /// ```text
- /// trait SomeTrait<'a, 'b> { }
- /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
- /// ```
- ///
- /// Here, the fact that `'b: 'a` is known only because of the
- /// implied bounds from the `&'a &'b u32` parameter, and is not
- /// "inherent" to the opaque type definition.
- ///
- /// # Parameters
- ///
- /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
- /// - `free_region_relations` -- something that can be used to relate
- /// the free regions (`'a`) that appear in the impl trait.
- fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) {
- let opaque_types = self.inner.borrow().opaque_types.clone();
- for (opaque_type_key, opaque_defn) in opaque_types {
- self.constrain_opaque_type(
- opaque_type_key,
- &opaque_defn,
- GenerateMemberConstraints::WhenRequired,
- free_region_relations,
- );
- }
- }
-
- /// See `constrain_opaque_types` for documentation.
- #[instrument(level = "debug", skip(self, free_region_relations))]
- fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
- &self,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- mode: GenerateMemberConstraints,
- free_region_relations: &FRR,
- ) {
- let def_id = opaque_type_key.def_id;
-
- let tcx = self.tcx;
-
- let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
-
- debug!(?concrete_ty);
-
- let first_own_region = match opaque_defn.origin {
- hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
- // We lower
- //
- // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
- //
- // into
- //
- // type foo::<'p0..'pn>::Foo<'q0..'qm>
- // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
- //
- // For these types we only iterate over `'l0..lm` below.
- tcx.generics_of(def_id).parent_count
- }
- // These opaque type inherit all lifetime parameters from their
- // parent, so we have to check them all.
- hir::OpaqueTyOrigin::TyAlias => 0,
- };
-
- let span = tcx.def_span(def_id);
-
- // Check if the `impl Trait` bounds include region bounds.
- // For example, this would be true for:
- //
- // fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
- //
- // but false for:
- //
- // fn foo<'c>() -> impl Trait<'c>
- //
- // unless `Trait` was declared like:
- //
- // trait Trait<'c>: 'c
- //
- // in which case it would be true.
- //
- // This is used during regionck to decide whether we need to
- // impose any additional constraints to ensure that region
- // variables in `concrete_ty` wind up being constrained to
- // something from `substs` (or, at minimum, things that outlive
- // the fn body). (Ultimately, writeback is responsible for this
- // check.)
- let bounds = tcx.explicit_item_bounds(def_id);
- debug!("{:#?}", bounds);
- let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs));
- debug!("{:#?}", bounds);
- let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
-
- let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds);
- if !required_region_bounds.is_empty() {
- for required_region in required_region_bounds {
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx,
- op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
- });
- }
- if let GenerateMemberConstraints::IfNoStaticBound = mode {
- self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
- return;
- }
-
- // There were no `required_region_bounds`,
- // so we have to search for a `least_region`.
- // Go through all the regions used as arguments to the
- // opaque type. These are the parameters to the opaque
- // type; so in our example above, `substs` would contain
- // `['a]` for the first impl trait and `'b` for the
- // second.
- let mut least_region = None;
-
- for subst_arg in &opaque_type_key.substs[first_own_region..] {
- let subst_region = match subst_arg.unpack() {
- GenericArgKind::Lifetime(r) => r,
- GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
- };
-
- // Compute the least upper bound of it with the other regions.
- debug!(?least_region);
- debug!(?subst_region);
- match least_region {
- None => least_region = Some(subst_region),
- Some(lr) => {
- if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) {
- // keep the current least region
- } else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) {
- // switch to `subst_region`
- least_region = Some(subst_region);
- } else {
- // There are two regions (`lr` and
- // `subst_region`) which are not relatable. We
- // can't find a best choice. Therefore,
- // instead of creating a single bound like
- // `'r: 'a` (which is our preferred choice),
- // we will create a "in bound" like `'r in
- // ['a, 'b, 'c]`, where `'a..'c` are the
- // regions that appear in the impl trait.
-
- return self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
- }
- }
- }
-
- let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
- debug!(?least_region);
-
- if let GenerateMemberConstraints::IfNoStaticBound = mode {
- if least_region != tcx.lifetimes.re_static {
- self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
- }
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx,
- op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
- });
- }
-
- /// As a fallback, we sometimes generate an "in constraint". For
- /// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be
- /// related, we would generate a constraint `'r in ['a, 'b,
- /// 'static]` for each region `'r` that appears in the hidden type
- /// (i.e., it must be equal to `'a`, `'b`, or `'static`).
- ///
- /// `conflict1` and `conflict2` are the two region bounds that we
- /// detected which were unrelated. They are used for diagnostics.
- fn generate_member_constraint(
- &self,
- concrete_ty: Ty<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- first_own_region: usize,
- ) {
- // Create the set of choice regions: each region in the hidden
- // type can be equal to any of the region parameters of the
- // opaque type definition.
- let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
- opaque_type_key.substs[first_own_region..]
- .iter()
- .filter_map(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => Some(r),
- GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
- })
- .chain(std::iter::once(self.tcx.lifetimes.re_static))
- .collect(),
- );
-
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx: self.tcx,
- op: |r| {
- self.member_constraint(
- opaque_type_key.def_id,
- opaque_defn.definition_span,
- concrete_ty,
- r,
- &choice_regions,
- )
- },
- });
- }
-
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
@@ -490,7 +33,7 @@
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
- /// `constrain_opaque_types`. Read that comment for more context.
+ /// `constrain_opaque_type`. Read that comment for more context.
///
/// # Parameters
///
@@ -536,83 +79,6 @@
}
}
-// Visitor that requires that (almost) all regions in the type visited outlive
-// `least_region`. We cannot use `push_outlives_components` because regions in
-// closure signatures are not included in their outlives components. We need to
-// ensure all regions outlive the given bound so that we don't end up with,
-// say, `ReVar` appearing in a return type and causing ICEs when other
-// functions end up with region constraints involving regions from other
-// functions.
-//
-// We also cannot use `for_each_free_region` because for closures it includes
-// the regions parameters from the enclosing item.
-//
-// 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>,
- op: OP,
-}
-
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
-where
- OP: FnMut(ty::Region<'tcx>),
-{
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
- fn visit_binder<T: TypeFoldable<'tcx>>(
- &mut self,
- t: &ty::Binder<'tcx, T>,
- ) -> ControlFlow<Self::BreakTy> {
- t.as_ref().skip_binder().visit_with(self);
- ControlFlow::CONTINUE
- }
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match *r {
- // ignore bound regions, keep visiting
- ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
- _ => {
- (self.op)(r);
- ControlFlow::CONTINUE
- }
- }
- }
-
- 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) {
- return ControlFlow::CONTINUE;
- }
-
- match ty.kind() {
- ty::Closure(_, ref substs) => {
- // Skip lifetime parameters of the enclosing item(s)
-
- substs.as_closure().tupled_upvars_ty().visit_with(self);
- substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
- }
-
- ty::Generator(_, ref substs, _) => {
- // Skip lifetime parameters of the enclosing item(s)
- // Also skip the witness type, because that has no free regions.
-
- substs.as_generator().tupled_upvars_ty().visit_with(self);
- substs.as_generator().return_ty().visit_with(self);
- substs.as_generator().yield_ty().visit_with(self);
- substs.as_generator().resume_ty().visit_with(self);
- }
- _ => {
- ty.super_visit_with(self);
- }
- }
-
- ControlFlow::CONTINUE
- }
-}
-
struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -855,235 +321,6 @@
}
}
-struct Instantiator<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value_span: Span,
- obligations: Vec<PredicateObligation<'tcx>>,
-}
-
-impl<'a, 'tcx> Instantiator<'a, 'tcx> {
- fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
- let tcx = self.infcx.tcx;
- value.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| {
- if ty.references_error() {
- return tcx.ty_error();
- } else if let ty::Opaque(def_id, substs) = ty.kind() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- 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 def_scope_default = || {
- let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
- parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
- };
- let (in_definition_scope, origin) =
- match tcx.hir().expect_item(opaque_hir_id).kind {
- // Anonymous `impl Trait`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(parent),
- origin,
- ..
- }) => (parent == parent_def_id.to_def_id(), origin),
- // Named `type Foo = impl Bar;`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: None,
- origin,
- ..
- }) => (
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
- origin,
- ),
- _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
- };
- if in_definition_scope {
- let opaque_type_key =
- OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
- }
-
- debug!(
- "instantiate_opaque_types_in_map: \
- encountered opaque outside its definition scope \
- def_id={:?}",
- def_id,
- );
- }
- }
-
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
- }
-
- #[instrument(skip(self), level = "debug")]
- fn fold_opaque_ty(
- &mut self,
- ty: Ty<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- origin: hir::OpaqueTyOrigin,
- ) -> Ty<'tcx> {
- let infcx = self.infcx;
- let tcx = infcx.tcx;
- let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
- // Use the same type variable if the exact same opaque type appears more
- // than once in the return type (e.g., if it's passed to a type alias).
- if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
- debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
- return opaque_defn.concrete_ty;
- }
-
- let ty_var = infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span: self.value_span,
- });
-
- // Ideally, we'd get the span where *this specific `ty` came
- // from*, but right now we just use the span from the overall
- // value being folded. In simple cases like `-> impl Foo`,
- // these are the same span, but not in cases like `-> (impl
- // Foo, impl Bar)`.
- let definition_span = self.value_span;
-
- {
- let mut infcx = self.infcx.inner.borrow_mut();
- infcx.opaque_types.insert(
- OpaqueTypeKey { def_id, substs },
- OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
- );
- infcx.opaque_types_vars.insert(ty_var, ty);
- }
-
- debug!("generated new type inference var {:?}", ty_var.kind());
-
- let item_bounds = tcx.explicit_item_bounds(def_id);
-
- self.obligations.reserve(item_bounds.len());
- for (predicate, _) in item_bounds {
- debug!(?predicate);
- let predicate = predicate.subst(tcx, substs);
- debug!(?predicate);
-
- // 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,
- ObligationCause::misc(self.value_span, self.body_id),
- 0,
- &mut self.obligations,
- ),
- _ => ty,
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- });
- 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.
- 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);
-
- // Require that the predicate holds for the concrete type.
- debug!(?predicate);
- self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
- }
-
- ty_var
- }
-}
-
-/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
-///
-/// Example:
-/// ```rust
-/// pub mod foo {
-/// pub mod bar {
-/// pub trait Bar { .. }
-///
-/// pub type Baz = impl Bar;
-///
-/// fn f1() -> Baz { .. }
-/// }
-///
-/// fn f2() -> bar::Baz { .. }
-/// }
-/// ```
-///
-/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
-/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
-/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
-fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
- let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
- // Named opaque types can be defined by any siblings or children of siblings.
- 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);
- }
- // Syntactically, we are allowed to define the concrete type if:
- let res = hir_id == scope;
- trace!(
- "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
- tcx.hir().find(hir_id),
- tcx.hir().get(opaque_hir_id),
- res
- );
- res
-}
-
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 622c9ed..54f7b91 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -187,9 +187,11 @@
// an additional sanity check.
let mut fulfill = FulfillmentContext::new();
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
- fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| {
- panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e)
- });
+ let errors = fulfill.select_all_or_error(&infcx);
+
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
let body_id_map: FxHashMap<_, _> = infcx
.inner
@@ -286,6 +288,8 @@
substs: infcx.tcx.mk_substs_trait(ty, &[]),
},
constness: ty::BoundConstness::NotConst,
+ // Auto traits are positive
+ polarity: ty::ImplPolarity::Positive,
}));
let computed_preds = param_env.caller_bounds().iter();
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index ec62ee4..2ccb253 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -49,34 +49,32 @@
self.obligations.insert(obligation);
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
- if self.obligations.is_empty() {
- Ok(())
- } else {
- let errors = self
- .obligations
- .iter()
- .map(|obligation| FulfillmentError {
- obligation: obligation.clone(),
- code: FulfillmentErrorCode::CodeAmbiguity,
- // FIXME - does Chalk have a notation of 'root obligation'?
- // This is just for diagnostics, so it's okay if this is wrong
- root_obligation: obligation.clone(),
- })
- .collect();
- Err(errors)
+ if !errors.is_empty() {
+ return errors;
+ }
}
+
+ // any remaining obligations are errors
+ self.obligations
+ .iter()
+ .map(|obligation| FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeAmbiguity,
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation.clone(),
+ })
+ .collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new();
@@ -147,7 +145,7 @@
}
}
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index f06f0e3..bdd4fdd 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -120,7 +120,8 @@
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
- if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 668a74b..42d3194 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -5,9 +5,12 @@
//! [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::traits::select::IntercrateAmbiguityCause;
use crate::traits::SkipLeakCheck;
-use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
+use crate::traits::{
+ self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
+};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::Subst;
@@ -158,6 +161,19 @@
b_def_id: DefId,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Option<OverlapResult<'tcx>> {
+ fn loose_check(selcx: &mut SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ !selcx.predicate_may_hold_fatal(o)
+ }
+
+ fn strict_check(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)
+ }
+
// For the purposes of this check, we don't bring any placeholder
// types into scope; instead, we replace the generic types with
// fresh type variables, and hence we do our evaluations in an
@@ -184,8 +200,29 @@
debug!("overlap: unification check succeeded");
- // Are any of the obligations unsatisfiable? If so, no overlap.
+ // There's no overlap if obligations are unsatisfiable or if the obligation negated is
+ // satisfied.
+ //
+ // For example, given these two impl headers:
+ //
+ // `impl<'a> From<&'a str> for Box<dyn Error>`
+ // `impl<E> From<E> for Box<dyn Error> where E: Error`
+ //
+ // So we have:
+ //
+ // `Box<dyn Error>: From<&'?a str>`
+ // `Box<dyn Error>: From<?E>`
+ //
+ // After equating the two headers:
+ //
+ // `Box<dyn Error> = Box<dyn Error>`
+ // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
+ //
+ // 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.
let infcx = selcx.infcx();
+ let tcx = infcx.tcx;
let opt_failing_obligation = a_impl_header
.predicates
.iter()
@@ -199,7 +236,17 @@
predicate: p,
})
.chain(obligations)
- .find(|o| !selcx.predicate_may_hold_fatal(o));
+ .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).
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1193d10..6b5d37c 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -80,9 +80,8 @@
Concrete,
}
let mut failure_kind = FailureKind::Concrete;
- walk_abstract_const::<!, _>(tcx, ct, |node| match node.root() {
+ walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
Node::Leaf(leaf) => {
- let leaf = leaf.subst(tcx, ct.substs);
if leaf.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
} else if leaf.definitely_has_param_types_or_consts(tcx) {
@@ -92,7 +91,6 @@
ControlFlow::CONTINUE
}
Node::Cast(_, _, ty) => {
- let ty = ty.subst(tcx, ct.substs);
if ty.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
} else if ty.definitely_has_param_types_or_consts(tcx) {
@@ -153,7 +151,7 @@
if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
match infcx.tcx.def_kind(uv.def.did) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic {
@@ -187,8 +185,8 @@
pub struct AbstractConst<'tcx> {
// FIXME: Consider adding something like `IndexSlice`
// and use this here.
- pub inner: &'tcx [Node<'tcx>],
- pub substs: SubstsRef<'tcx>,
+ inner: &'tcx [Node<'tcx>],
+ substs: SubstsRef<'tcx>,
}
impl<'tcx> AbstractConst<'tcx> {
@@ -218,8 +216,14 @@
}
#[inline]
- pub fn root(self) -> Node<'tcx> {
- self.inner.last().copied().unwrap()
+ pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
+ let node = self.inner.last().copied().unwrap();
+ match node {
+ Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)),
+ Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)),
+ // Don't perform substitution on the following as they can't directly contain generic params
+ Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
+ }
}
}
@@ -491,7 +495,7 @@
// we want to look into them or treat them as opaque projections.
//
// Right now we do neither of that and simply always fail to unify them.
- DefKind::AnonConst => (),
+ DefKind::AnonConst | DefKind::InlineConst => (),
_ => return Ok(None),
}
@@ -542,7 +546,7 @@
f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
) -> ControlFlow<R> {
f(ct)?;
- let root = ct.root();
+ let root = ct.root(tcx);
match root {
Node::Leaf(_) => ControlFlow::CONTINUE,
Node::Binop(_, l, r) => {
@@ -570,16 +574,14 @@
// We substitute generics repeatedly to allow AbstractConsts to unify where a
// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
- while let Node::Leaf(a_ct) = a.root() {
- let a_ct = a_ct.subst(tcx, a.substs);
+ while let Node::Leaf(a_ct) = a.root(tcx) {
match AbstractConst::from_const(tcx, a_ct) {
Ok(Some(a_act)) => a = a_act,
Ok(None) => break,
Err(_) => return true,
}
}
- while let Node::Leaf(b_ct) = b.root() {
- let b_ct = b_ct.subst(tcx, b.substs);
+ while let Node::Leaf(b_ct) = b.root(tcx) {
match AbstractConst::from_const(tcx, b_ct) {
Ok(Some(b_act)) => b = b_act,
Ok(None) => break,
@@ -587,10 +589,8 @@
}
}
- match (a.root(), b.root()) {
+ match (a.root(tcx), b.root(tcx)) {
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
- let a_ct = a_ct.subst(tcx, a.substs);
- let b_ct = b_ct.subst(tcx, b.substs);
if a_ct.ty != b_ct.ty {
return false;
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 225ff5e..f8df0e2 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -34,6 +34,7 @@
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
use on_unimplemented::InferCtxtExt as _;
use suggestions::InferCtxtExt as _;
@@ -241,6 +242,15 @@
let mut span = obligation.cause.span;
let mut err = match *error {
+ SelectionError::Ambiguous(ref impls) => {
+ let mut err = self.tcx.sess.struct_span_err(
+ obligation.cause.span,
+ &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
+ );
+ self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
+ err.emit();
+ return;
+ }
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formedness checking, see if we
// can get a better error message by performing HIR-based well-formedness checking.
@@ -256,19 +266,16 @@
}
}
if let ObligationCauseCode::CompareImplMethodObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
}
| ObligationCauseCode::CompareImplTypeObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
} = obligation.cause.code
{
self.report_extra_impl_obligation(
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
&format!("`{}`", obligation.predicate),
@@ -1138,6 +1145,13 @@
obligation: &PredicateObligation<'tcx>,
);
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ );
+
fn maybe_suggest_unsized_generics(
&self,
err: &mut DiagnosticBuilder<'tcx>,
@@ -1475,6 +1489,9 @@
}
}
}
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ self.get_parent_trait_ref(&parent_code)
+ }
_ => None,
}
}
@@ -1549,11 +1566,8 @@
?predicate, ?obligation.cause.code,
);
- // Ambiguity errors are often caused as fallout from earlier
- // errors. So just ignore them if this infcx is tainted.
- if self.is_tainted_by_errors() {
- return;
- }
+ // Ambiguity errors are often caused as fallout from earlier errors.
+ // We ignore them if this `infcx` is tainted in some cases below.
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
@@ -1601,10 +1615,19 @@
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
- self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
+ if !self.is_tainted_by_errors() {
+ self.emit_inference_failure_err(
+ body_id,
+ span,
+ subst,
+ vec![],
+ ErrorCode::E0282,
+ )
.emit();
+ }
return;
}
+
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
let mut err = self.emit_inference_failure_err(
body_id,
@@ -1613,7 +1636,29 @@
impl_candidates,
ErrorCode::E0283,
);
- err.note(&format!("cannot satisfy `{}`", predicate));
+
+ let obligation = Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ trait_ref.to_poly_trait_predicate(),
+ );
+ let mut selcx = SelectionContext::with_query_mode(
+ &self,
+ crate::traits::TraitQueryMode::Standard,
+ );
+ match selcx.select_from_obligation(&obligation) {
+ Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
+ self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ }
+ _ => {
+ if self.is_tainted_by_errors() {
+ err.cancel();
+ return;
+ }
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ }
+
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
} else if let (
@@ -1674,7 +1719,10 @@
ty::PredicateKind::WellFormed(arg) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
- if arg.references_error() || self.tcx.sess.has_errors() {
+ if arg.references_error()
+ || self.tcx.sess.has_errors()
+ || self.is_tainted_by_errors()
+ {
return;
}
@@ -1682,7 +1730,10 @@
}
ty::PredicateKind::Subtype(data) => {
- if data.references_error() || self.tcx.sess.has_errors() {
+ if data.references_error()
+ || self.tcx.sess.has_errors()
+ || self.is_tainted_by_errors()
+ {
// no need to overload user in such cases
return;
}
@@ -1694,7 +1745,7 @@
ty::PredicateKind::Projection(data) => {
let self_ty = data.projection_ty.self_ty();
let ty = data.ty;
- if predicate.references_error() {
+ if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
if self_ty.needs_infer() && ty.needs_infer() {
@@ -1722,7 +1773,7 @@
}
_ => {
- if self.tcx.sess.has_errors() {
+ if self.tcx.sess.has_errors() || self.is_tainted_by_errors() {
return;
}
let mut err = struct_span_err!(
@@ -1740,6 +1791,96 @@
err.emit();
}
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ ) {
+ let mut spans = vec![];
+ let mut crates = vec![];
+ let mut post = vec![];
+ for def_id in impls {
+ match self.tcx.span_of_impl(*def_id) {
+ Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
+ post.push(header);
+ }
+ }
+ }
+ }
+ let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
+ crate_names.sort();
+ crate_names.dedup();
+ post.sort();
+ post.dedup();
+
+ if self.is_tainted_by_errors()
+ && crate_names.len() == 1
+ && crate_names[0] == "`core`"
+ && spans.len() == 0
+ {
+ // Avoid complaining about other inference issues for expressions like
+ // `42 >> 1`, where the types are still `{integer}`, but we want to
+ // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+ err.cancel();
+ return;
+ }
+ let post = if post.len() > 4 {
+ format!(
+ ":\n{}\nand {} more",
+ post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
+ post.len() - 4,
+ )
+ } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+ format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
+ } else if post.len() == 1 {
+ format!(": `{}`", post[0])
+ } else {
+ String::new()
+ };
+
+ match (spans.len(), crates.len(), crate_names.len()) {
+ (0, 0, 0) => {
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ (0, _, 1) => {
+ err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+ }
+ (0, _, _) => {
+ err.note(&format!(
+ "{} in the following crates: {}{}",
+ msg,
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ (_, 0, 0) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ }
+ (_, 1, 1) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ err.note(
+ &format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
+ );
+ }
+ _ => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ err.note(&format!(
+ "and more `impl`s found in the following crates: {}{}",
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ }
+ }
+
/// Returns `true` if the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply(
@@ -1856,23 +1997,31 @@
let sized_trait = self.tcx.lang_items().sized_trait();
debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause);
- let param = generics
- .params
- .iter()
- .filter(|param| param.span == span)
- .filter(|param| {
- // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
- // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
- param
- .bounds
- .iter()
- .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
- })
- .next();
+ let param = generics.params.iter().filter(|param| param.span == span).find(|param| {
+ // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+ // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+ param
+ .bounds
+ .iter()
+ .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
+ });
let param = match param {
Some(param) => param,
_ => return,
};
+ let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id();
+ let preds = generics.where_clause.predicates.iter();
+ let explicitly_sized = preds
+ .filter_map(|pred| match pred {
+ hir::WherePredicate::BoundPredicate(bp) => Some(bp),
+ _ => None,
+ })
+ .filter(|bp| bp.is_param_bound(param_def_id))
+ .flat_map(|bp| bp.bounds)
+ .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
+ if explicitly_sized {
+ return;
+ }
debug!("maybe_suggest_unsized_generics: param={:?}", param);
match node {
hir::Node::Item(
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 1a8f863..a90140a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -27,7 +27,7 @@
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::fmt;
@@ -151,7 +151,7 @@
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: &ty::TypeckResults<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
);
@@ -290,27 +290,25 @@
} else {
// Trivial case: `T` needs an extra bound: `T: Bound`.
let (sp, suggestion) = match (
- generics.params.iter().find(|p| {
- !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), .. })
- }),
+ generics
+ .params
+ .iter()
+ .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, Some((ident, []))) => (
- ident.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
- (_, Some((_, [.., bounds]))) => (
- bounds.span().shrink_to_hi(),
- format!(" + {}", trait_ref.print_only_trait_path().to_string()),
- ),
- (Some(_), Some((_, []))) => (
- generics.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
+ (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()))
+ }
};
err.span_suggestion_verbose(
@@ -687,7 +685,7 @@
&obligation.cause.code
{
parent_code.clone()
- } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) =
+ } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
span.ctxt().outer_expn_data().kind
{
Lrc::new(obligation.cause.code.clone())
@@ -709,36 +707,29 @@
}
let param_env = obligation.param_env;
- let trait_ref = poly_trait_ref.skip_binder();
-
- let found_ty = trait_ref.self_ty();
- let found_ty_str = found_ty.to_string();
- let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty);
- let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]);
- let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty);
- let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
// Try to apply the original trait binding obligation by borrowing.
- let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
- new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
- expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
blacklist: &[DefId]|
-> bool {
- if blacklist.contains(&expected_trait_ref.def_id()) {
+ if blacklist.contains(&old_ref.def_id()) {
return false;
}
- let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
- ObligationCause::dummy(),
- param_env,
- new_imm_trait_ref.without_const().to_predicate(self.tcx),
- ));
-
- let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
- ObligationCause::dummy(),
- param_env,
- new_mut_trait_ref.without_const().to_predicate(self.tcx),
- ));
+ let orig_ty = old_ref.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 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));
if imm_result || mut_result {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -750,8 +741,8 @@
let msg = format!(
"the trait bound `{}: {}` is not satisfied",
- found_ty_str,
- expected_trait_ref.print_only_trait_path(),
+ orig_ty.to_string(),
+ old_ref.print_only_trait_path(),
);
if has_custom_message {
err.note(&msg);
@@ -767,15 +758,14 @@
span,
&format!(
"expected an implementor of trait `{}`",
- expected_trait_ref.print_only_trait_path(),
+ old_ref.print_only_trait_path(),
),
);
// This if is to prevent a special edge-case
if matches!(
span.ctxt().outer_expn_data().kind,
- ExpnKind::Root
- | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
) {
// We don't want a borrowing suggestion on the fields in structs,
// ```
@@ -810,21 +800,11 @@
};
if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code {
- let expected_trait_ref = obligation.parent_trait_ref;
- let new_imm_trait_ref = poly_trait_ref
- .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs));
- let new_mut_trait_ref = poly_trait_ref
- .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs));
- return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
+ try_borrowing(obligation.parent_trait_ref, &[])
} else if let ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ItemObligation(_) = &*code
{
- return try_borrowing(
- poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)),
- poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)),
- *poly_trait_ref,
- &never_suggest_borrow[..],
- );
+ try_borrowing(*poly_trait_ref, &never_suggest_borrow[..])
} else {
false
}
@@ -1038,13 +1018,11 @@
let hir = self.tcx.hir();
let parent_node = hir.get_parent_node(obligation.cause.body_id);
let node = hir.find(parent_node);
- let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
+ let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(sig, _, body_id),
..
})) = node
- {
- (sig, body_id)
- } else {
+ else {
return false;
};
let body = hir.body(*body_id);
@@ -1427,6 +1405,9 @@
while let Some(code) = next_code {
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
match code {
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ next_code = Some(parent_code.as_ref());
+ }
ObligationCauseCode::DerivedObligation(derived_obligation)
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
| ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
@@ -1465,11 +1446,7 @@
}
// Only continue if a generator was found.
- debug!(
- "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
- target_ty={:?}",
- generator, trait_ref, target_ty
- );
+ debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
(Some(generator_did), Some(trait_ref), Some(target_ty)) => {
(generator_did, trait_ref, target_ty)
@@ -1479,16 +1456,8 @@
let span = self.tcx.def_span(generator_did);
- // Do not ICE on closure typeck (#66868).
- if !generator_did.is_local() {
- return false;
- }
-
- // Get the typeck results from the infcx if the generator is the function we are
- // currently type-checking; otherwise, get them by performing a query.
- // This is needed to avoid cycles.
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
- let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+ let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
debug!(
"maybe_note_obligation_cause_for_async_await: generator_did={:?} \
generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
@@ -1497,14 +1466,6 @@
in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
span
);
- let query_typeck_results;
- let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
- _ => {
- query_typeck_results = self.tcx.typeck(generator_did.expect_local());
- &query_typeck_results
- }
- };
let generator_body = generator_did
.as_local()
@@ -1547,51 +1508,59 @@
let mut interior_or_upvar_span = None;
let mut interior_extra_info = None;
- if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
- interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
- let upvar_ty = typeck_results.node_type(*upvar_id);
- let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
- if ty_matches(ty::Binder::dummy(upvar_ty)) {
- Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
- } else {
- None
- }
- });
+ // Get the typeck results from the infcx if the generator is the function we are currently
+ // type-checking; otherwise, get them by performing a query. This is needed to avoid
+ // cycles. If we can't use resolved types because the generator comes from another crate,
+ // we still provide a targeted error but without all the relevant spans.
+ let query_typeck_results;
+ let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+ _ if generator_did.is_local() => {
+ query_typeck_results = self.tcx.typeck(generator_did.expect_local());
+ Some(&query_typeck_results)
+ }
+ _ => None, // Do not ICE on closure typeck (#66868).
};
+ if let Some(typeck_results) = typeck_results {
+ if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
+ interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = typeck_results.node_type(*upvar_id);
+ let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
+ if ty_matches(ty::Binder::dummy(upvar_ty)) {
+ Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ } else {
+ None
+ }
+ });
+ };
- // The generator interior types share the same binders
- 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))
- },
- )
- {
- // Check to see if any awaited expressions have the target type.
- let from_awaited_ty = visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- let ty = typeck_results.expr_ty_adjusted(&await_expr);
- debug!(
- "maybe_note_obligation_cause_for_async_await: await_expr={:?}",
- await_expr
- );
- ty_matches(ty::Binder::dummy(ty))
- })
- .map(|expr| expr.span);
- let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
+ // The generator interior types share the same binders
+ 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))
+ },
+ )
+ {
+ // Check to see if any awaited expressions have the target type.
+ let from_awaited_ty = visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+ })
+ .map(|expr| expr.span);
+ let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
+ cause;
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
- interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
- };
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
+ interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
+ };
+ } else {
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
- debug!(
- "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
- generator_interior_types={:?}",
- interior_or_upvar_span, typeck_results.generator_interior_types
- );
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
self.note_obligation_cause_for_async_await(
err,
@@ -1622,7 +1591,7 @@
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: &ty::TypeckResults<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
) {
@@ -1833,7 +1802,7 @@
// Look at the last interior type to get a span for the `.await`.
debug!(
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
- typeck_results.generator_interior_types
+ typeck_results.as_ref().map(|t| &t.generator_interior_types)
);
explain_yield(interior_span, yield_span, scope_span);
}
@@ -1854,10 +1823,14 @@
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
// ```
//
- let is_region_borrow = typeck_results
- .expr_adjustments(expr)
- .iter()
- .any(|adj| adj.is_region_borrow());
+ let is_region_borrow = if let Some(typeck_results) = typeck_results {
+ typeck_results
+ .expr_adjustments(expr)
+ .iter()
+ .any(|adj| adj.is_region_borrow())
+ } else {
+ false
+ };
// ```rust
// struct Foo(*const u8);
@@ -1870,15 +1843,16 @@
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
_ => false,
};
-
- if (typeck_results.is_method_call(e) && is_region_borrow)
- || is_raw_borrow_inside_fn_like_call
- {
- err.span_help(
- parent_span,
- "consider moving this into a `let` \
+ if let Some(typeck_results) = typeck_results {
+ if (typeck_results.is_method_call(e) && is_region_borrow)
+ || is_raw_borrow_inside_fn_like_call
+ {
+ err.span_help(
+ parent_span,
+ "consider moving this into a `let` \
binding to create a shorter lived borrow",
- );
+ );
+ }
}
}
}
@@ -1983,15 +1957,9 @@
region, object_ty,
));
}
- ObligationCauseCode::ItemObligation(item_def_id) => {
- let item_name = tcx.def_path_str(item_def_id);
- let msg = format!("required by `{}`", item_name);
- let sp = tcx
- .hir()
- .span_if_local(item_def_id)
- .unwrap_or_else(|| tcx.def_span(item_def_id));
- let sp = tcx.sess.source_map().guess_head_span(sp);
- err.span_note(sp, &msg);
+ ObligationCauseCode::ItemObligation(_item_def_id) => {
+ // We hold the `DefId` of the item introducing the obligation, but displaying it
+ // doesn't add user usable information. It always point at an associated item.
}
ObligationCauseCode::BindingObligation(item_def_id, span) => {
let item_name = tcx.def_path_str(item_def_id);
@@ -2363,11 +2331,8 @@
)
});
}
- ObligationCauseCode::CompareImplMethodObligation {
- item_name,
- trait_item_def_id,
- ..
- } => {
+ ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => {
+ let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
"the requirement `{}` appears on the impl method `{}` but not on the \
corresponding trait method",
@@ -2392,9 +2357,8 @@
}
err.span_note(assoc_span, &msg);
}
- ObligationCauseCode::CompareImplTypeObligation {
- item_name, trait_item_def_id, ..
- } => {
+ ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => {
+ let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
"the requirement `{}` appears on the associated impl type `{}` but not on the \
corresponding associated trait type",
@@ -2484,13 +2448,7 @@
obligation.param_env,
);
- let item_def_id = self
- .tcx
- .associated_items(future_trait)
- .in_definition_order()
- .next()
- .unwrap()
- .def_id;
+ let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
// `<T as Future>::Output`
let projection_ty = ty::ProjectionTy {
// `T`
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 465d146..e121837 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -126,10 +126,7 @@
}
/// Attempts to select obligations using `selcx`.
- fn select(
- &mut self,
- selcx: &mut SelectionContext<'a, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
@@ -163,7 +160,7 @@
errors.len()
);
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
}
@@ -223,41 +220,36 @@
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_with_constness_where_possible(infcx, constness)?;
+ ) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_with_constness_where_possible(infcx, constness);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx)
}
@@ -266,7 +258,7 @@
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx)
}
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index cedd1aa..fa8890fc 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -33,7 +33,8 @@
| ty::Char
| ty::RawPtr(..)
| ty::Never
- | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
+ | ty::Ref(_, _, hir::Mutability::Not)
+ | ty::Array(..) => return Ok(()),
ty::Adt(adt, substs) => (adt, substs),
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index b31d6d6..4bc22d5 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -65,7 +65,8 @@
pub use self::structural_match::search_for_structural_match_violation;
pub use self::structural_match::NonStructuralMatchTy;
pub use self::util::{
- elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs,
+ elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
+ elaborate_trait_ref, elaborate_trait_refs,
};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{
@@ -81,9 +82,14 @@
pub use rustc_infer::traits::*;
/// Whether to skip the leak check, as part of a future compatibility warning step.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+///
+/// The "default" for skip-leak-check corresponds to the current
+/// behavior (do not skip the leak check) -- not the behavior we are
+/// transitioning into.
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub enum SkipLeakCheck {
Yes,
+ #[default]
No,
}
@@ -93,15 +99,6 @@
}
}
-/// The "default" for skip-leak-check corresponds to the current
-/// behavior (do not skip the leak check) -- not the behavior we are
-/// transitioning into.
-impl Default for SkipLeakCheck {
- fn default() -> Self {
- SkipLeakCheck::No
- }
-}
-
/// The mode that trait queries run in.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TraitQueryMode {
@@ -180,8 +177,8 @@
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
@@ -189,12 +186,12 @@
);
true
}
- Err(e) => {
+ errors => {
debug!(
- "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
- ty,
- infcx.tcx.def_path_str(def_id),
- e
+ ?ty,
+ bound = %infcx.tcx.def_path_str(def_id),
+ ?errors,
+ "type_known_to_meet_bound_modulo_regions"
);
false
}
@@ -410,7 +407,10 @@
}
debug!("fully_normalize: select_all_or_error start");
- fulfill_cx.select_all_or_error(infcx)?;
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
@@ -441,7 +441,9 @@
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
- fulfill_cx.select_all_or_error(&infcx).is_err()
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ !errors.is_empty()
});
debug!("impossible_predicates = {:?}", result);
result
@@ -748,6 +750,9 @@
) -> usize {
let (trait_to_be_found, trait_owning_vtable) = key;
+ // #90177
+ let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
+
let vtable_segment_callback = {
let mut vtable_base = 0;
@@ -757,7 +762,7 @@
vtable_base += COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
- if trait_ref == trait_to_be_found {
+ if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
return ControlFlow::Break(vtable_base);
}
vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
@@ -804,6 +809,7 @@
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 0bb00df..afc5465 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -647,9 +647,7 @@
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
- let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
- (u, cu)
- } else {
+ let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
return false;
};
@@ -839,14 +837,13 @@
// constants which are not considered const evaluatable.
use rustc_middle::thir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
- const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
- Node::Leaf(leaf) => {
- let leaf = leaf.subst(self.tcx, ct.substs);
- self.visit_const(leaf)
- }
- Node::Cast(_, _, ty) => self.visit_ty(ty),
- Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
- ControlFlow::CONTINUE
+ const_evaluatable::walk_abstract_const(self.tcx, ct, |node| {
+ match node.root(self.tcx) {
+ Node::Leaf(leaf) => self.visit_const(leaf),
+ Node::Cast(_, _, ty) => self.visit_ty(ty),
+ Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+ ControlFlow::CONTINUE
+ }
}
})
} else {
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 209fd83..85ca4db 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -164,9 +164,7 @@
) -> Result<Option<Self>, ErrorReported> {
let attrs = tcx.get_attrs(impl_def_id);
- let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) {
- item
- } else {
+ let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
return Ok(None);
};
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index db8a6d9..4a23206 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -20,6 +20,7 @@
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::InferCtxtExt as _;
+use rustc_data_structures::sso::SsoHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
@@ -944,9 +945,14 @@
Normalized { value: projected_ty, obligations: projected_obligations }
};
+ let mut deduped: SsoHashSet<_> = Default::default();
let mut canonical =
SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
+
result.obligations.drain_filter(|projected_obligation| {
+ if !deduped.insert(projected_obligation.clone()) {
+ return true;
+ }
// If any global obligations always apply, considering regions, then we don't
// need to include them. The `is_global` check rules out inference variables,
// so there's no need for the caller of `opt_normalize_projection_type`
@@ -1734,7 +1740,7 @@
ty: ret_type,
});
- confirm_param_env_candidate(selcx, obligation, predicate, false)
+ confirm_param_env_candidate(selcx, obligation, predicate, true)
}
fn confirm_param_env_candidate<'cx, 'tcx>(
@@ -1754,8 +1760,18 @@
);
let cache_projection = cache_entry.projection_ty;
- let obligation_projection = obligation.predicate;
let mut nested_obligations = Vec::new();
+ let obligation_projection = obligation.predicate;
+ let obligation_projection = ensure_sufficient_stack(|| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_projection,
+ &mut nested_obligations,
+ )
+ });
let cache_projection = if potentially_unnormalized_candidate {
ensure_sufficient_stack(|| {
normalize_with_depth_to(
@@ -1771,6 +1787,8 @@
cache_projection
};
+ debug!(?cache_projection, ?obligation_projection);
+
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index b5398f8..0a85676 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -77,10 +77,11 @@
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
- if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
- &format!("errors selecting obligation during MIR typeck: {:?}", e),
+ &format!("errors selecting obligation during MIR typeck: {:?}", errors),
);
}
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index 7751dd8..e0098cc 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -44,6 +44,7 @@
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: predicate.constness,
+ polarity: predicate.polarity,
})
})
.to_predicate(infcx.tcx),
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 856ea43..0ff3611 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -18,7 +18,7 @@
use crate::traits::coherence::Conflict;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{util, SelectionResult};
-use crate::traits::{ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
use super::BuiltinImplConditions;
use super::IntercrateAmbiguityCause;
@@ -121,7 +121,7 @@
return Ok(None);
}
- let mut candidates = candidate_set.vec;
+ let candidates = candidate_set.vec;
debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
@@ -134,6 +134,8 @@
// candidate which assumes $0 == int, one that assumes `$0 ==
// usize`, etc. This spells an ambiguity.
+ let mut candidates = self.filter_impls(candidates, stack.obligation);
+
// If there is more than one candidate, first winnow them down
// by considering extra conditions (nested obligations and so
// forth). We don't winnow if there is exactly one
@@ -149,7 +151,7 @@
// Instead, we select the right impl now but report "`Bar` does
// not implement `Clone`".
if candidates.len() == 1 {
- return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
+ return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
}
// Winnow, but record the exact outcome of evaluation, which
@@ -195,7 +197,15 @@
// and report ambiguity.
if i > 1 {
debug!("multiple matches, ambig");
- return Ok(None);
+ return Err(Ambiguous(
+ candidates
+ .into_iter()
+ .filter_map(|c| match c.candidate {
+ SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
+ _ => None,
+ })
+ .collect(),
+ ));
}
}
}
@@ -223,7 +233,7 @@
}
// Just one candidate left.
- self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
+ self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
}
#[instrument(skip(self, stack), level = "debug")]
@@ -254,68 +264,75 @@
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
-
- // Other bounds. Consider both in-scope bounds from fn decl
- // and applicable impls. There is a certain set of precedence rules here.
- let def_id = obligation.predicate.def_id();
- let lang_items = self.tcx().lang_items();
-
- if lang_items.copy_trait() == Some(def_id) {
- debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
-
- // User-defined copy impls are permitted, but only for
- // structs and enums.
+ // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
+ // There are no compiler built-in rules for this.
+ if obligation.polarity() == ty::ImplPolarity::Negative {
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates);
-
- // For other types, we'll use the builtin rules.
- let copy_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
- } else if lang_items.discriminant_kind_trait() == Some(def_id) {
- // `DiscriminantKind` is automatically implemented for every type.
- candidates.vec.push(DiscriminantKindCandidate);
- } else if lang_items.pointee_trait() == Some(def_id) {
- // `Pointee` is automatically implemented for every type.
- candidates.vec.push(PointeeCandidate);
- } else if lang_items.sized_trait() == Some(def_id) {
- // Sized is never implementable by end-users, it is
- // always automatically computed.
- let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
- } 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
- {
- if self.is_in_const_context {
- self.assemble_const_drop_candidates(obligation, &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)
- }
} else {
- if lang_items.clone_trait() == Some(def_id) {
- // Same builtin conditions as `Copy`, i.e., every type which has builtin support
- // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
- // types have builtin support for `Clone`.
- let clone_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
+
+ // Other bounds. Consider both in-scope bounds from fn decl
+ // and applicable impls. There is a certain set of precedence rules here.
+ let def_id = obligation.predicate.def_id();
+ let lang_items = self.tcx().lang_items();
+
+ if lang_items.copy_trait() == Some(def_id) {
+ debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
+
+ // User-defined copy impls are permitted, but only for
+ // structs and enums.
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+
+ // For other types, we'll use the builtin rules.
+ let copy_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
+ } else if lang_items.discriminant_kind_trait() == Some(def_id) {
+ // `DiscriminantKind` is automatically implemented for every type.
+ candidates.vec.push(DiscriminantKindCandidate);
+ } else if lang_items.pointee_trait() == Some(def_id) {
+ // `Pointee` is automatically implemented for every type.
+ candidates.vec.push(PointeeCandidate);
+ } else if lang_items.sized_trait() == Some(def_id) {
+ // Sized is never implementable by end-users, it is
+ // always automatically computed.
+ let sized_conditions = self.sized_conditions(obligation);
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
+ } 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
+ {
+ if self.is_in_const_context {
+ 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)
+ }
+ } else {
+ if lang_items.clone_trait() == Some(def_id) {
+ // Same builtin conditions as `Copy`, i.e., every type which has builtin support
+ // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
+ // types have builtin support for `Clone`.
+ let clone_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+ }
+
+ self.assemble_generator_candidates(obligation, &mut candidates);
+ self.assemble_closure_candidates(obligation, &mut candidates);
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
- self.assemble_generator_candidates(obligation, &mut candidates);
- self.assemble_closure_candidates(obligation, &mut candidates);
- self.assemble_fn_pointer_candidates(obligation, &mut candidates);
- self.assemble_candidates_from_impls(obligation, &mut candidates);
- self.assemble_candidates_from_object_ty(obligation, &mut candidates);
- }
-
- self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
- self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
- // Auto implementations have lower priority, so we only
- // consider triggering a default if there is no other impl that can apply.
- if candidates.vec.is_empty() {
- self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
+ self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
+ // Auto implementations have lower priority, so we only
+ // consider triggering a default if there is no other impl that can apply.
+ if candidates.vec.is_empty() {
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ }
}
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
@@ -376,7 +393,7 @@
for bound in matching_bounds {
let wc = self.evaluate_where_clause(stack, bound.value)?;
if wc.may_apply() {
- candidates.vec.push(ParamCandidate(bound));
+ candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
}
}
@@ -716,9 +733,7 @@
cause.clone(),
);
- let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() {
- data
- } else {
+ let ty::Dynamic(data, ..) = normalized_ty.kind() else {
return None;
};
@@ -896,9 +911,10 @@
}
}
- fn assemble_const_drop_candidates(
+ fn assemble_const_drop_candidates<'a>(
&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)];
@@ -907,7 +923,7 @@
let mut noreturn = false;
self.check_recursion_depth(depth, obligation)?;
- let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
+ 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 {
@@ -915,15 +931,32 @@
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 copy_candidates);
+ 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 copy_candidates);
- if !copy_candidates.vec.is_empty() {
+ 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!(?copy_candidates.vec, "assemble_const_drop_candidates - copy");
+ debug!(?new_candidates.vec, "assemble_const_drop_candidates");
match ty.kind() {
ty::Int(_)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index a36cb13..2f1f797 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -58,8 +58,8 @@
}
ParamCandidate(param) => {
- let obligations = self.confirm_param_candidate(obligation, param.value);
- Ok(ImplSource::Param(obligations, param.constness))
+ let obligations = self.confirm_param_candidate(obligation, param.0.value);
+ Ok(ImplSource::Param(obligations, param.0.constness))
}
ImplCandidate(impl_def_id) => {
@@ -620,23 +620,37 @@
_ => bug!("closure candidate for non-closure {:?}", obligation),
};
+ let obligation_predicate = obligation.predicate.to_poly_trait_ref();
+ let Normalized { value: obligation_predicate, mut obligations } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_predicate,
+ )
+ });
+
let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
- let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
- normalize_with_depth(
- self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- trait_ref,
- )
- });
+ let Normalized { value: trait_ref, obligations: trait_ref_obligations } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ trait_ref,
+ )
+ });
debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
+ obligations.extend(trait_ref_obligations);
obligations.extend(self.confirm_poly_trait_refs(
obligation.cause.clone(),
obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
+ obligation_predicate,
trait_ref,
)?);
@@ -948,52 +962,24 @@
let tail_field_ty = tcx.type_of(tail_field.did);
let mut unsizing_params = GrowableBitSet::new_empty();
- if tcx.features().relaxed_struct_unsize {
- for arg in tail_field_ty.walk(tcx) {
+ for arg in tail_field_ty.walk(tcx) {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.insert(i);
+ }
+ }
+
+ // Ensure none of the other fields mention the parameters used
+ // in unsizing.
+ for field in prefix_fields {
+ for arg in tcx.type_of(field.did).walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
+ unsizing_params.remove(i);
}
}
+ }
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.remove(i);
- }
- }
- }
-
- if unsizing_params.is_empty() {
- return Err(Unimplemented);
- }
- } else {
- let mut found = false;
- for arg in tail_field_ty.walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
- found = true;
- }
- }
- if !found {
- return Err(Unimplemented);
- }
-
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- // FIXME(eddyb) cache this (including computing `unsizing_params`)
- // by putting it in a query; it would only need the `DefId` as it
- // looks at declared field types, not anything substituted.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- if unsizing_params.contains(i) {
- return Err(Unimplemented);
- }
- }
- }
- }
+ if unsizing_params.is_empty() {
+ return Err(Unimplemented);
}
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 85502a3..2aa2146 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -20,7 +20,7 @@
use super::Selection;
use super::SelectionResult;
use super::TraitQueryMode;
-use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
+use super::{ErrorReporting, Overflow, SelectionError};
use super::{ObligationCause, PredicateObligation, TraitObligation};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@@ -320,10 +320,7 @@
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
- match pred.constness {
- ty::BoundConstness::ConstIfConst if self.is_in_const_context => true,
- _ => false,
- }
+ matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
}
/// Returns `true` if the predicate is considered `const` to
@@ -357,18 +354,16 @@
&mut self,
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
- debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
- let pec = &ProvisionalEvaluationCache::default();
- let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
- let candidate = match self.candidate_from_obligation(&stack) {
+ let candidate = match self.select_from_obligation(obligation) {
Err(SelectionError::Overflow) => {
// In standard mode, overflow must have been caught and reported
// earlier.
assert!(self.query_mode == TraitQueryMode::Canonical);
return Err(SelectionError::Overflow);
}
+ Err(SelectionError::Ambiguous(_)) => {
+ return Ok(None);
+ }
Err(e) => {
return Err(e);
}
@@ -391,6 +386,18 @@
}
}
+ crate fn select_from_obligation(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+ let pec = &ProvisionalEvaluationCache::default();
+ let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+ self.candidate_from_obligation(&stack)
+ }
+
///////////////////////////////////////////////////////////////////////////
// EVALUATION
//
@@ -709,7 +716,11 @@
debug!(?fresh_trait_ref);
- if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
+ if let Some(result) = self.check_evaluation_cache(
+ obligation.param_env,
+ fresh_trait_ref,
+ obligation.polarity(),
+ ) {
debug!(?result, "CACHE HIT");
return Ok(result);
}
@@ -739,12 +750,19 @@
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
debug!(?result, "CACHE MISS");
- self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+ self.insert_evaluation_cache(
+ obligation.param_env,
+ fresh_trait_ref,
+ obligation.polarity(),
+ dep_node,
+ result,
+ );
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
self.insert_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
+ obligation.polarity(),
dep_node,
provisional_result.max(result),
);
@@ -855,34 +873,39 @@
// precise still.
let unbound_input_types =
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
- // This check was an imperfect workaround for a bug in the old
- // intercrate mode; it should be removed when that goes away.
- if unbound_input_types && self.intercrate {
- debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
- // Heuristics: show the diagnostics when there are no candidates in crate.
- if self.intercrate_ambiguity_causes.is_some() {
- debug!("evaluate_stack: intercrate_ambiguity_causes is some");
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let cause =
- with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc: trait_ref.print_only_trait_path().to_string(),
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
+
+ if stack.obligation.polarity() != ty::ImplPolarity::Negative {
+ // This check was an imperfect workaround for a bug in the old
+ // intercrate mode; it should be removed when that goes away.
+ if unbound_input_types && self.intercrate {
+ debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let cause = with_no_trimmed_paths(|| {
+ IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc: trait_ref.print_only_trait_path().to_string(),
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ }
});
- debug!(?cause, "evaluate_stack: pushing cause");
- self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ debug!(?cause, "evaluate_stack: pushing cause");
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
}
+ return Ok(EvaluatedToAmbig);
}
- return Ok(EvaluatedToAmbig);
}
+
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
@@ -899,6 +922,7 @@
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+ Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
@@ -977,6 +1001,7 @@
&self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ polarity: ty::ImplPolarity,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
@@ -988,17 +1013,19 @@
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
- if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) {
+ if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
+ {
return Some(res);
}
}
- self.infcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx)
+ self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
}
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ polarity: ty::ImplPolarity,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
@@ -1023,13 +1050,17 @@
// FIXME: Due to #50507 this overwrites the different values
// This should be changed to use HashMapExt::insert_same
// when that is fixed
- self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+ self.tcx().evaluation_cache.insert(
+ (param_env.and(trait_ref), polarity),
+ dep_node,
+ result,
+ );
return;
}
}
debug!(?trait_ref, ?result, "insert_evaluation_cache");
- self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+ self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
}
/// For various reasons, it's possible for a subobligation
@@ -1094,67 +1125,89 @@
(result, dep_node)
}
+ /// filter_impls filters constant trait obligations and candidates that have a positive impl
+ /// for a negative goal and a negative impl for a positive goal
#[instrument(level = "debug", skip(self))]
fn filter_impls(
&mut self,
+ candidates: Vec<SelectionCandidate<'tcx>>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Vec<SelectionCandidate<'tcx>> {
+ let tcx = self.tcx();
+ let mut result = Vec::with_capacity(candidates.len());
+
+ for candidate in candidates {
+ // Respect const trait obligations
+ if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+ match candidate {
+ // const impl
+ ImplCandidate(def_id)
+ if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+ // const param
+ ParamCandidate((
+ ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+ _,
+ )) => {}
+ // auto trait impl
+ AutoImplCandidate(..) => {}
+ // generator, this will raise error in other places
+ // or ignore error with const_async_blocks feature
+ GeneratorCandidate => {}
+ // FnDef where the function is const
+ FnPointerCandidate { is_const: true } => {}
+ ConstDropCandidate => {}
+ _ => {
+ // reject all other types of candidates
+ continue;
+ }
+ }
+ }
+
+ if let ImplCandidate(def_id) = candidate {
+ if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+ || obligation.polarity() == tcx.impl_polarity(def_id)
+ || self.allow_negative_impls
+ {
+ result.push(candidate);
+ }
+ } else {
+ result.push(candidate);
+ }
+ }
+
+ result
+ }
+
+ /// filter_reservation_impls filter reservation impl for any goal as ambiguous
+ #[instrument(level = "debug", skip(self))]
+ fn filter_reservation_impls(
+ &mut self,
candidate: SelectionCandidate<'tcx>,
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
let tcx = self.tcx();
- // Respect const trait obligations
- if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
- match candidate {
- // const impl
- ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
- // const param
- ParamCandidate(ty::ConstnessAnd {
- constness: ty::BoundConstness::ConstIfConst,
- ..
- }) => {}
- // auto trait impl
- AutoImplCandidate(..) => {}
- // generator, this will raise error in other places
- // or ignore error with const_async_blocks feature
- GeneratorCandidate => {}
- // FnDef where the function is const
- FnPointerCandidate { is_const: true } => {}
- ConstDropCandidate => {}
- _ => {
- // reject all other types of candidates
- return Err(Unimplemented);
- }
- }
- }
- // Treat negative impls as unimplemented, and reservation impls as ambiguity.
+ // Treat reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
- match tcx.impl_polarity(def_id) {
- ty::ImplPolarity::Negative if !self.allow_negative_impls => {
- return Err(Unimplemented);
- }
- ty::ImplPolarity::Reservation => {
- if let Some(intercrate_ambiguity_clauses) =
- &mut self.intercrate_ambiguity_causes
- {
- let attrs = tcx.get_attrs(def_id);
- let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
- let value = attr.and_then(|a| a.value_str());
- if let Some(value) = value {
- debug!(
- "filter_impls: \
+ if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
+ if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
+ let attrs = tcx.get_attrs(def_id);
+ let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
+ let value = attr.and_then(|a| a.value_str());
+ if let Some(value) = value {
+ debug!(
+ "filter_reservation_impls: \
reservation impl ambiguity on {:?}",
- def_id
- );
- intercrate_ambiguity_clauses.push(
- IntercrateAmbiguityCause::ReservationImpl {
- message: value.to_string(),
- },
- );
- }
+ def_id
+ );
+ intercrate_ambiguity_clauses.push(
+ IntercrateAmbiguityCause::ReservationImpl {
+ message: value.to_string(),
+ },
+ );
}
- return Ok(None);
}
- _ => {}
- };
+ return Ok(None);
+ }
}
Ok(Some(candidate))
}
@@ -1162,7 +1215,7 @@
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
debug!("is_knowable(intercrate={:?})", self.intercrate);
- if !self.intercrate {
+ if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
return None;
}
@@ -1219,14 +1272,14 @@
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx
.selection_cache
- .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
{
return Some(res);
}
}
self.infcx
.selection_cache
- .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
}
/// Determines whether can we safely cache the result
@@ -1286,7 +1339,7 @@
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
tcx.selection_cache.insert(
- param_env.and(trait_ref).with_constness(pred.constness),
+ (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
@@ -1297,7 +1350,7 @@
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert(
- param_env.and(trait_ref).with_constness(pred.constness),
+ (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
@@ -1491,8 +1544,9 @@
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
- let is_global =
- |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
+ let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
+ cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
+ };
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// and `DiscriminantKindCandidate` to anything else.
@@ -1523,10 +1577,14 @@
| ConstDropCandidate,
) => false,
- (ParamCandidate(other), ParamCandidate(victim)) => {
+ (
+ ParamCandidate((other, other_polarity)),
+ ParamCandidate((victim, victim_polarity)),
+ ) => {
let same_except_bound_vars = other.value.skip_binder()
== victim.value.skip_binder()
&& other.constness == victim.constness
+ && other_polarity == victim_polarity
&& !other.value.skip_binder().has_escaping_bound_vars();
if same_except_bound_vars {
// See issue #84398. In short, we can generate multiple ParamCandidates which are
@@ -1537,6 +1595,7 @@
other.value.bound_vars().len() <= victim.value.bound_vars().len()
} else if other.value == victim.value
&& victim.constness == ty::BoundConstness::NotConst
+ && other_polarity == victim_polarity
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
@@ -1566,11 +1625,11 @@
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
- ) => !is_global(&cand.value),
+ ) => !is_global(&cand.0.value),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.value)
+ is_global(&cand.0.value)
}
(
ImplCandidate(_)
@@ -1586,7 +1645,7 @@
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
+ is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
@@ -1800,7 +1859,8 @@
| ty::Char
| ty::RawPtr(..)
| ty::Never
- | ty::Ref(_, _, hir::Mutability::Not) => {
+ | ty::Ref(_, _, hir::Mutability::Not)
+ | ty::Array(..) => {
// Implementations provided in libcore
None
}
@@ -1813,11 +1873,6 @@
| ty::Foreign(..)
| ty::Ref(_, _, hir::Mutability::Mut) => None,
- ty::Array(element_ty, _) => {
- // (*) binder moved here
- Where(obligation.predicate.rebind(vec![element_ty]))
- }
-
ty::Tuple(tys) => {
// (*) binder moved here
Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 88aca79..b64c555 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -225,8 +225,18 @@
for oblig in obligations.chain(more_obligations) {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
- match fulfill_cx.select_all_or_error(infcx) {
- Err(errors) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
+ debug!(
+ "fulfill_implication: an impl for {:?} specializes {:?}",
+ source_trait_ref, target_trait_ref
+ );
+
+ // Now resolve the *substitution* we built for the target earlier, replacing
+ // the inference variables inside with whatever we got from fulfillment.
+ Ok(infcx.resolve_vars_if_possible(target_substs))
+ }
+ errors => {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
@@ -238,17 +248,6 @@
);
Err(())
}
-
- Ok(()) => {
- debug!(
- "fulfill_implication: an impl for {:?} specializes {:?}",
- source_trait_ref, target_trait_ref
- );
-
- // Now resolve the *substitution* we built for the target earlier, replacing
- // the inference variables inside with whatever we got from fulfillment.
- Ok(infcx.resolve_vars_if_possible(target_substs))
- }
}
})
}
@@ -292,6 +291,11 @@
sg
}
+// This function is only used when
+// encountering errors and inlining
+// it negatively impacts perf.
+#[cold]
+#[inline(never)]
fn report_overlap_conflict(
tcx: TyCtxt<'_>,
overlap: OverlapError,
@@ -444,8 +448,12 @@
match used_to_be_allowed {
None => {
sg.has_errored = true;
- let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
- decorate(LintDiagnosticBuilder::new(err));
+ if overlap.with_impl.is_local() || !tcx.orphan_check_crate(()).contains(&impl_def_id) {
+ let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
+ decorate(LintDiagnosticBuilder::new(err));
+ } else {
+ tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check");
+ }
}
Some(kind) => {
let lint = match kind {
@@ -464,7 +472,7 @@
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
/// string.
-fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
use std::fmt::Write;
let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index ac8bab0..3d71382 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -17,6 +17,7 @@
Dynamic,
Foreign,
Opaque,
+ Closure,
Generator,
Projection,
}
@@ -102,7 +103,7 @@
//
// 2. We are sometimes doing future-incompatibility lints for
// now, so we do not want unconditional errors here.
- fulfillment_cx.select_all_or_error(infcx).is_ok()
+ fulfillment_cx.select_all_or_error(infcx).is_empty()
}
/// This implements the traversal over the structure of a given type to try to
@@ -154,6 +155,9 @@
ty::Projection(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Projection);
}
+ ty::Closure(..) => {
+ return ControlFlow::Break(NonStructuralMatchTy::Closure);
+ }
ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Generator);
}
@@ -197,7 +201,7 @@
// First check all contained types and then tell the caller to continue searching.
return ty.super_visit_with(self);
}
- ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
+ ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
bug!("unexpected type during structural-match checking: {:?}", ty);
}
ty::Error(_) => {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index ed49abb..6d2323a 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -9,7 +9,9 @@
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
-pub use rustc_infer::traits::util::*;
+pub use rustc_infer::traits::{self, util::*};
+
+use std::iter;
///////////////////////////////////////////////////////////////////////////
// `TraitAliasExpander` iterator
@@ -229,11 +231,16 @@
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);
- generic_bounds.predicates.into_iter().map(move |predicate| Obligation {
- cause: cause.clone(),
- recursion_depth,
- param_env,
- predicate,
+ iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| {
+ let cause = match cause.code {
+ traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new(
+ cause.span,
+ cause.body_id,
+ traits::BindingObligation(def_id, span),
+ ),
+ _ => cause.clone(),
+ };
+ Obligation { cause, recursion_depth, param_env, predicate }
})
}
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index cb47ba9..2a66684 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -709,7 +709,12 @@
iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
.map(|((pred, span), origin_def_id)| {
- let cause = self.cause(traits::BindingObligation(origin_def_id, span));
+ let code = if span.is_dummy() {
+ traits::MiscObligation
+ } else {
+ traits::BindingObligation(origin_def_id, span)
+ };
+ let cause = self.cause(code);
traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
})
.filter(|pred| !pred.has_escaping_bound_vars())
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 37e0073..92f2760 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -128,9 +128,9 @@
// Ensure that those obligations that we had to solve
// get solved *here*.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => Ok(implied_bounds),
- Err(_) => Err(NoSolution),
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => Ok(implied_bounds),
+ _ => Err(NoSolution),
}
}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 87b729f..13ffb2a 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -362,7 +362,7 @@
let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
match self_ty.kind() {
_ if is_copy => (),
- ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
+ ty::Closure(..) | ty::Tuple(..) => {}
_ => return Ok(None),
};
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 3f66e5b..595b623 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -17,7 +17,8 @@
// needs drop.
let adt_has_dtor =
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
- let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
+ let res =
+ drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some();
debug!("needs_drop_raw({:?}) = {:?}", query, res);
res
@@ -27,10 +28,15 @@
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
- let res =
- drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
- .next()
- .is_some();
+ let res = drop_tys_helper(
+ tcx,
+ query.value,
+ query.param_env,
+ adt_consider_insignificant_dtor(tcx),
+ true,
+ )
+ .next()
+ .is_some();
debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
res
}
@@ -141,9 +147,9 @@
Ok(tys) => tys,
};
for required_ty in tys {
- let subst_ty =
+ let required =
tcx.normalize_erasing_regions(self.param_env, required_ty);
- queue_type(self, subst_ty);
+ queue_type(self, required);
}
}
ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
@@ -186,16 +192,39 @@
ty: Ty<'tcx>,
param_env: rustc_middle::ty::ParamEnv<'tcx>,
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+ only_significant: bool,
) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
+ fn with_query_cache<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ iter: impl IntoIterator<Item = Ty<'tcx>>,
+ only_significant: bool,
+ ) -> NeedsDropResult<Vec<Ty<'tcx>>> {
+ iter.into_iter().try_fold(Vec::new(), |mut vec, subty| {
+ match subty.kind() {
+ ty::Adt(adt_id, subst) => {
+ for subty in if only_significant {
+ tcx.adt_significant_drop_tys(adt_id.did)?
+ } else {
+ tcx.adt_drop_tys(adt_id.did)?
+ } {
+ vec.push(subty.subst(tcx, subst));
+ }
+ }
+ _ => vec.push(subty),
+ };
+ Ok(vec)
+ })
+ }
+
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
- return Ok(Vec::new().into_iter());
+ Ok(Vec::new())
} else if let Some(dtor_info) = adt_has_dtor(adt_def) {
match dtor_info {
DtorType::Significant => {
debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
- return Err(AlwaysRequiresDrop);
+ Err(AlwaysRequiresDrop)
}
DtorType::Insignificant => {
debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
@@ -203,22 +232,27 @@
// Since the destructor is insignificant, we just want to make sure all of
// the passed in type parameters are also insignificant.
// Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
- return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
+ with_query_cache(tcx, substs.types(), only_significant)
}
}
} else if adt_def.is_union() {
debug!("drop_tys_helper: `{:?}` is a union", adt_def);
- return Ok(Vec::new().into_iter());
+ Ok(Vec::new())
+ } else {
+ with_query_cache(
+ tcx,
+ adt_def.all_fields().map(|field| {
+ let r = tcx.type_of(field.did).subst(tcx, substs);
+ debug!(
+ "drop_tys_helper: Subst into {:?} with {:?} gettng {:?}",
+ field, substs, r
+ );
+ r
+ }),
+ only_significant,
+ )
}
- Ok(adt_def
- .all_fields()
- .map(|field| {
- let r = tcx.type_of(field.did).subst(tcx, substs);
- debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
- r
- })
- .collect::<Vec<_>>()
- .into_iter())
+ .map(|v| v.into_iter())
};
NeedsDropTypes::new(tcx, param_env, ty, adt_components)
@@ -252,20 +286,24 @@
// significant.
let adt_has_dtor =
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
- drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
+ // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_substs)`
+ drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor, false)
.collect::<Result<Vec<_>, _>>()
.map(|components| tcx.intern_type_list(&components))
}
-
+// If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed
+// a `tcx.make_ty(def, identity_substs)` and as such it is legal to substitue the generic parameters
+// of the ADT into the outputted `ty`s.
fn adt_significant_drop_tys(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
drop_tys_helper(
tcx,
- tcx.type_of(def_id),
+ tcx.type_of(def_id), // identical to `tcx.make_adt(def, identity_substs)`
tcx.param_env(def_id),
adt_consider_insignificant_dtor(tcx),
+ true,
)
.collect::<Result<Vec<_>, _>>()
.map(|components| tcx.intern_type_list(&components))
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 7512403..af3706f 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,7 +1,6 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
@@ -490,11 +489,11 @@
let node = tcx.hir().get(hir_id);
- let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
+ let fn_kind = node.fn_kind().unwrap_or_else(|| {
bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
});
- fn_like.asyncness()
+ fn_kind.asyncness()
}
/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 91dbbec..f11c93e 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -559,6 +559,7 @@
impl<CTX> HashStable<CTX> for InferTy {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
use InferTy::*;
+ discriminant(self).hash_stable(ctx, hasher);
match self {
TyVar(v) => v.as_u32().hash_stable(ctx, hasher),
IntVar(v) => v.index.hash_stable(ctx, hasher),
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 5befe44..e8bd038 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -344,7 +344,7 @@
"reorder the arguments: {}: `<{}>`",
param_types_present
.into_iter()
- .map(|ord| format!("{}s", ord.to_string()))
+ .map(|ord| format!("{}s", ord))
.collect::<Vec<String>>()
.join(", then "),
ordered_params
@@ -464,16 +464,7 @@
.params
.iter()
.filter(|param| {
- matches!(
- param.kind,
- ty::GenericParamDefKind::Type {
- synthetic: Some(
- hir::SyntheticTyParamKind::ImplTrait
- | hir::SyntheticTyParamKind::FromAttr
- ),
- ..
- }
- )
+ matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
})
.count()
} else {
@@ -672,6 +663,17 @@
err.span_label(span, "explicit generic argument not allowed");
}
+ err.note(
+ "see issue #83701 <https://github.com/rust-lang/rust/issues/83701> \
+ for more information",
+ );
+ if tcx.sess.is_nightly_build() {
+ err.help(
+ "add `#![feature(explicit_generic_args_with_impl_trait)]` \
+ to the crate attributes to enable",
+ );
+ }
+
err.emit();
}
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 889b687..da751f2 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1916,9 +1916,7 @@
debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
- let self_ty = if let Some(ty) = opt_self_ty {
- ty
- } else {
+ let Some(self_ty) = opt_self_ty else {
let path_str = tcx.def_path_str(trait_def_id);
let def_id = self.item_def_id();
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 6a231e7..a816031 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -6,7 +6,6 @@
use rustc_infer::traits::Obligation;
use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
use rustc_span::{MultiSpan, Span};
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -531,6 +530,7 @@
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
},
constness: t.constness,
+ polarity: t.polarity,
}));
let obl = Obligation::new(
o.cause.clone(),
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 06c4209..635ed93 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -300,7 +300,7 @@
let end = callee_span.shrink_to_hi();
err.multipart_suggestion(
"if you meant to create this closure and immediately call it, surround the \
- closure with parenthesis",
+ closure with parentheses",
vec![(start, "(".to_string()), (end, ")".to_string())],
Applicability::MaybeIncorrect,
);
@@ -349,9 +349,12 @@
ty::FnPtr(sig) => (sig, None),
ref t => {
let mut unit_variant = None;
+ let mut removal_span = call_expr.span;
if let ty::Adt(adt_def, ..) = t {
if adt_def.is_enum() {
if let hir::ExprKind::Call(expr, _) = call_expr.kind {
+ removal_span =
+ expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
unit_variant =
self.tcx.sess.source_map().span_to_snippet(expr.span).ok();
}
@@ -379,14 +382,13 @@
);
if let Some(ref path) = unit_variant {
- err.span_suggestion(
- call_expr.span,
+ err.span_suggestion_verbose(
+ removal_span,
&format!(
- "`{}` is a unit variant, you need to write it \
- without the parenthesis",
+ "`{}` is a unit variant, you need to write it without the parentheses",
path
),
- path.to_string(),
+ String::new(),
Applicability::MachineApplicable,
);
}
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 78849b2..511a2d7 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -436,11 +436,8 @@
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).
// Can/should be extended in the future.
- let needs_parens = !has_parens
- && match self.expr.kind {
- hir::ExprKind::Cast(..) => true,
- _ => false,
- };
+ let needs_parens =
+ !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
if needs_parens {
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 6631621..bb1d974 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -21,7 +21,6 @@
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_ty_utils::representability::{self, Representability};
@@ -372,16 +371,26 @@
let param_env = tcx.param_env(item_def_id);
for field in fields {
let field_ty = field.ty(tcx, substs);
- // We are currently checking the type this field came from, so it must be local.
- let field_span = tcx.hir().span_if_local(field.did).unwrap();
if field_ty.needs_drop(tcx, param_env) {
+ let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
+ // We are currently checking the type this field came from, so it must be local.
+ Some(Node::Field(field)) => (field.span, field.ty.span),
+ _ => unreachable!("mir field has to correspond to hir field"),
+ };
struct_span_err!(
tcx.sess,
field_span,
E0740,
"unions may not contain fields that need dropping"
)
- .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type")
+ .multipart_suggestion_verbose(
+ "wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped",
+ vec![
+ (ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")),
+ (ty_span.shrink_to_hi(), ">".into()),
+ ],
+ Applicability::MaybeIncorrect,
+ )
.emit();
return false;
}
@@ -664,8 +673,9 @@
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
// Finally, resolve all regions. This catches wily misuses of
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 410ac24..4a41552 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -92,7 +92,7 @@
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
- self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
+ self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
@@ -257,8 +257,7 @@
if is_gen {
// Check that we deduce the signature from the `<_ as std::ops::Generator>::Return`
// associated item and not yield.
- let return_assoc_item =
- self.tcx.associated_items(gen_trait).in_definition_order().nth(1).unwrap().def_id;
+ let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
if return_assoc_item != projection.projection_def_id() {
debug!("deduce_sig_from_projection: not return assoc item of generator");
return None;
@@ -694,8 +693,7 @@
// The `Future` trait has only one associted item, `Output`,
// so check that this is what we see.
- let output_assoc_item =
- self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id;
+ let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0];
if output_assoc_item != predicate.projection_ty.item_def_id {
span_bug!(
cause_span,
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index a87318f..77f7ccc 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -185,9 +185,10 @@
debug!("coerce: unsize not object safe");
return Err(TypeError::ObjectUnsafeCoercion(did));
}
- Err(_) => {}
+ Err(error) => {
+ debug!(?error, "coerce: unsize failed");
+ }
}
- debug!("coerce: unsize failed");
// Examine the supertype and consider auto-borrowing.
match *b.kind() {
@@ -521,9 +522,7 @@
let traits =
(self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());
- let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
- (u, cu)
- } else {
+ let (Some(unsize_did), Some(coerce_unsized_did)) = traits else {
debug!("missing Unsize or CoerceUnsized traits");
return Err(TypeError::Mismatch);
};
@@ -951,7 +950,7 @@
};
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
fcx.register_predicate_obligations(self, ok.obligations);
- fcx.select_where_possible(&self).is_ok()
+ fcx.select_where_possible(&self).is_empty()
})
}
@@ -1459,7 +1458,7 @@
cause,
expected,
found,
- coercion_error,
+ coercion_error.clone(),
fcx,
parent_id,
expression.map(|expr| (expr, blk_id)),
@@ -1473,7 +1472,7 @@
cause,
expected,
found,
- coercion_error,
+ coercion_error.clone(),
fcx,
id,
None,
@@ -1484,7 +1483,12 @@
}
}
_ => {
- err = fcx.report_mismatched_types(cause, expected, found, coercion_error);
+ err = fcx.report_mismatched_types(
+ cause,
+ expected,
+ found,
+ coercion_error.clone(),
+ );
}
}
@@ -1493,7 +1497,14 @@
}
if let Some(expr) = expression {
- fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None);
+ fcx.emit_coerce_suggestions(
+ &mut err,
+ expr,
+ found,
+ expected,
+ None,
+ coercion_error,
+ );
}
err.emit_unless(unsized_return);
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 5e12497..fdc5d16 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -92,7 +92,6 @@
impl_m_span,
impl_m_hir_id,
ObligationCauseCode::CompareImplMethodObligation {
- item_name: impl_m.ident.name,
impl_item_def_id: impl_m.def_id,
trait_item_def_id: trait_m.def_id,
},
@@ -211,12 +210,8 @@
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
let param_env =
ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
- let param_env = traits::normalize_param_env_or_error(
- tcx,
- impl_m.def_id,
- param_env,
- normalize_cause.clone(),
- );
+ let param_env =
+ traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
tcx.infer_ctxt().enter(|infcx| {
let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
@@ -227,12 +222,15 @@
let mut selcx = traits::SelectionContext::new(&infcx);
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
- for predicate in impl_m_own_bounds.predicates {
+ for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+ let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
+ traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
inh.register_predicates(obligations);
- inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
+ let mut cause = cause.clone();
+ cause.make_mut().span = span;
+ inh.register_predicate(traits::Obligation::new(cause, param_env, predicate));
}
// We now need to check that the signature of the impl method is
@@ -276,6 +274,12 @@
let sub_result = infcx.at(&cause, param_env).sup(trait_fty, impl_fty).map(
|InferOk { obligations, .. }| {
+ // FIXME: We'd want to keep more accurate spans than "the method signature" when
+ // processing the comparison between the trait and impl fn, but we sadly lose them
+ // and point at the whole signature when a trait bound or specific input or output
+ // type would be more appropriate. In other places we have a `Vec<Span>`
+ // corresponding to their `Vec<Predicate>`, but we don't have that here.
+ // Fixing this would improve the output of test `issue-83765.rs`.
inh.register_predicates(obligations);
},
);
@@ -386,8 +390,9 @@
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
@@ -448,6 +453,7 @@
Ok(())
}
+#[instrument(level = "debug", skip(infcx))]
fn extract_spans_for_error_reporting<'a, 'tcx>(
infcx: &infer::InferCtxt<'a, 'tcx>,
terr: &TypeError<'_>,
@@ -601,10 +607,7 @@
.params
.iter()
.filter_map(|p| match p.kind {
- GenericParamKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- ..
- } => Some(p.span),
+ GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
_ => None,
})
.collect();
@@ -621,10 +624,7 @@
.params
.iter()
.filter_map(|p| match p.kind {
- GenericParamKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- ..
- } => Some(p.span),
+ GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
_ => None,
})
.collect();
@@ -817,7 +817,7 @@
match (impl_synthetic, trait_synthetic) {
// The case where the impl method uses `impl Trait` but the trait method uses
// explicit generics
- (Some(hir::SyntheticTyParamKind::ImplTrait), None) => {
+ (true, false) => {
err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
(|| {
// try taking the name from the trait impl
@@ -858,7 +858,7 @@
}
// The case where the trait method uses `impl Trait`, but the impl method uses
// explicit generics.
- (None, Some(hir::SyntheticTyParamKind::ImplTrait)) => {
+ (false, true) => {
err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
(|| {
let impl_m = impl_m.def_id.as_local()?;
@@ -1088,8 +1088,9 @@
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return;
}
@@ -1159,7 +1160,6 @@
impl_ty_span,
impl_ty_hir_id,
ObligationCauseCode::CompareImplTypeObligation {
- item_name: impl_ty.ident.name,
impl_item_def_id: impl_ty.def_id,
trait_item_def_id: trait_ty.def_id,
},
@@ -1204,8 +1204,9 @@
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
@@ -1384,12 +1385,13 @@
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 mk_cause = |span| {
- ObligationCause::new(
- impl_ty_span,
- impl_ty_hir_id,
- ObligationCauseCode::BindingObligation(trait_ty.def_id, span),
- )
+ let mk_cause = |span: Span| {
+ let code = if span.is_dummy() {
+ traits::MiscObligation
+ } else {
+ traits::BindingObligation(trait_ty.def_id, span)
+ };
+ ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
};
let obligations = tcx
@@ -1421,10 +1423,10 @@
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) =
- inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
- {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors =
+ inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 5403659..12cd7ad 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -10,6 +10,7 @@
use rustc_hir::{is_range_literal, Node};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
+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;
@@ -27,8 +28,10 @@
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);
+ 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);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
@@ -144,9 +147,9 @@
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
- let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+ let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
- self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
+ self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, e);
(expected, Some(err))
}
@@ -155,15 +158,121 @@
&self,
err: &mut DiagnosticBuilder<'_>,
expr: &hir::Expr<'_>,
+ error: TypeError<'_>,
) {
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
- if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
- self.tcx.hir().find(parent)
- {
- if init.hir_id == expr.hir_id {
+ match (self.tcx.hir().find(parent), error) {
+ (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
+ if init.hir_id == expr.hir_id =>
+ {
// Point at `let` assignment type.
err.span_label(ty.span, "expected due to this");
}
+ (
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Assign(lhs, rhs, _), ..
+ })),
+ TypeError::Sorts(ExpectedFound { expected, .. }),
+ ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
+ // We ignore closures explicitly because we already point at them elsewhere.
+ // Point at the assigned-to binding.
+ let mut primary_span = lhs.span;
+ let mut secondary_span = lhs.span;
+ let mut post_message = "";
+ match lhs.kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path {
+ res:
+ hir::def::Res::Def(
+ hir::def::DefKind::Static | hir::def::DefKind::Const,
+ def_id,
+ ),
+ ..
+ },
+ )) => {
+ if let Some(hir::Node::Item(hir::Item {
+ ident,
+ kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
+ ..
+ })) = self.tcx.hir().get_if_local(*def_id)
+ {
+ primary_span = ty.span;
+ secondary_span = ident.span;
+ post_message = " type";
+ }
+ }
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: hir::def::Res::Local(hir_id), .. },
+ )) => {
+ if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) {
+ let parent = self.tcx.hir().get_parent_node(pat.hir_id);
+ primary_span = pat.span;
+ secondary_span = pat.span;
+ match self.tcx.hir().find(parent) {
+ Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
+ primary_span = ty.span;
+ post_message = " type";
+ }
+ Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
+ primary_span = init.span;
+ post_message = " value";
+ }
+ Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
+ primary_span = *ty_span;
+ post_message = " parameter type";
+ }
+ _ => {}
+ }
+ }
+ }
+ _ => {}
+ }
+
+ if primary_span != secondary_span
+ && self
+ .tcx
+ .sess
+ .source_map()
+ .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
+ {
+ // We are pointing at the binding's type or initializer value, but it's pattern
+ // is in a different line, so we point at both.
+ err.span_label(secondary_span, "expected due to the type of this binding");
+ err.span_label(primary_span, &format!("expected due to this{}", post_message));
+ } else if post_message == "" {
+ // We are pointing at either the assignment lhs or the binding def pattern.
+ err.span_label(primary_span, "expected due to the type of this binding");
+ } else {
+ // We are pointing at the binding's type or initializer value.
+ err.span_label(primary_span, &format!("expected due to this{}", post_message));
+ }
+
+ if !lhs.is_syntactic_place_expr() {
+ // We already emitted E0070 "invalid left-hand side of assignment", so we
+ // silence this.
+ err.delay_as_bug();
+ }
+ }
+ _ => {}
+ }
+ }
+
+ 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,
+ );
}
}
@@ -181,7 +290,50 @@
return;
}
- let mut compatible_variants = expected_adt
+ // If the expression is of type () and it's the return expression of a block,
+ // we suggest adding a separate return expression instead.
+ // (To avoid things like suggesting `Ok(while .. { .. })`.)
+ if expr_ty.is_unit() {
+ if let Some(hir::Node::Block(&hir::Block {
+ span: block_span, expr: Some(e), ..
+ })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
+ {
+ if e.hir_id == expr.hir_id {
+ if let Some(span) = expr.span.find_ancestor_inside(block_span) {
+ let return_suggestions =
+ if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) {
+ vec!["Ok(())".to_string()]
+ } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did)
+ {
+ vec!["None".to_string(), "Some(())".to_string()]
+ } else {
+ return;
+ };
+ if let Some(indent) =
+ self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
+ {
+ // Add a semicolon, except after `}`.
+ let semicolon =
+ match self.tcx.sess.source_map().span_to_snippet(span) {
+ Ok(s) if s.ends_with('}') => "",
+ _ => ";",
+ };
+ err.span_suggestions(
+ span.shrink_to_hi(),
+ "try adding an expression at the end of the block",
+ return_suggestions
+ .into_iter()
+ .map(|r| format!("{}\n{}{}", semicolon, indent, r)),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ let compatible_variants: Vec<String> = expected_adt
.variants
.iter()
.filter(|variant| variant.fields.len() == 1)
@@ -202,19 +354,33 @@
None
}
})
- .peekable();
+ .collect();
- if compatible_variants.peek().is_some() {
- if let Ok(expr_text) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
- let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text));
- let msg = "try using a variant of the expected enum";
- err.span_suggestions(
- expr.span,
- msg,
- suggestions,
- Applicability::MaybeIncorrect,
- );
- }
+ 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| {
+ vec![
+ (expr.span.shrink_to_lo(), format!("{}(", variant)),
+ (expr.span.shrink_to_hi(), ")".to_string()),
+ ]
+ }),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
@@ -428,7 +594,7 @@
(&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(_) = replace_prefix(&src, "b\"", "\"") {
+ if replace_prefix(&src, "b\"", "\"").is_some() {
let pos = sp.lo() + BytePos(1);
return Some((
sp.with_hi(pos),
@@ -444,7 +610,7 @@
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(_) = replace_prefix(&src, "\"", "b\"") {
+ if replace_prefix(&src, "\"", "b\"").is_some() {
return Some((
sp.shrink_to_lo(),
"consider adding a leading `b`",
@@ -743,9 +909,7 @@
return false;
}
- let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
- src
- } else {
+ let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else {
return false;
};
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 9e2460b..4b4d293 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -113,9 +113,10 @@
}
}
- if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
// this could be reached when we get lazy normalization
- infcx.report_fulfillment_errors(errors, None, false);
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 2d0a406..eb997b0 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -30,15 +30,17 @@
use rustc_hir as hir;
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_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty;
+use rustc_infer::infer::InferOk;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
+use rustc_middle::ty::relate::expected_found_bool;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::Ty;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{AdtKind, Visibility};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc_session::parse::feature_err;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
@@ -323,7 +325,9 @@
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
- ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
+ ExprKind::ConstBlock(ref anon_const) => {
+ self.check_expr_const_block(anon_const, expected, expr)
+ }
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
@@ -829,7 +833,7 @@
&self,
lhs: &'tcx hir::Expr<'tcx>,
err_code: &'static str,
- expr_span: &Span,
+ op_span: Span,
) {
if lhs.is_syntactic_place_expr() {
return;
@@ -837,11 +841,58 @@
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
let mut err = self.tcx.sess.struct_span_err_with_code(
- *expr_span,
+ op_span,
"invalid left-hand side of assignment",
DiagnosticId::Error(err_code.into()),
);
err.span_label(lhs.span, "cannot assign to this expression");
+
+ let mut parent = self.tcx.hir().get_parent_node(lhs.hir_id);
+ while let Some(node) = self.tcx.hir().find(parent) {
+ match node {
+ hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::Loop(
+ hir::Block {
+ expr:
+ Some(hir::Expr {
+ kind:
+ hir::ExprKind::Match(expr, ..) | hir::ExprKind::If(expr, ..),
+ ..
+ }),
+ ..
+ },
+ _,
+ hir::LoopSource::While,
+ _,
+ ),
+ ..
+ }) => {
+ // 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,
+ );
+ if !self.sess().features_untracked().destructuring_assignment {
+ // We already emit an E0658 with a suggestion for `while let`, this is
+ // redundant output.
+ err.delay_as_bug();
+ }
+ break;
+ }
+ hir::Node::Item(_)
+ | hir::Node::ImplItem(_)
+ | hir::Node::TraitItem(_)
+ | hir::Node::Crate(_) => break,
+ _ => {
+ parent = self.tcx.hir().get_parent_node(parent);
+ }
+ }
+ }
+
err.emit();
}
@@ -949,7 +1000,7 @@
} else {
(Applicability::MaybeIncorrect, false)
};
- if !lhs.is_syntactic_place_expr() {
+ if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
let hir = self.tcx.hir();
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
@@ -961,7 +1012,7 @@
"let ".to_string(),
applicability,
);
- }
+ };
}
if eq {
err.span_suggestion_verbose(
@@ -982,7 +1033,7 @@
return self.tcx.ty_error();
}
- self.check_lhs_assignable(lhs, "E0070", span);
+ self.check_lhs_assignable(lhs, "E0070", *span);
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
@@ -1166,6 +1217,24 @@
self.tcx.mk_array(element_ty, args.len() as u64)
}
+ fn check_expr_const_block(
+ &self,
+ anon_const: &'tcx hir::AnonConst,
+ expected: Expectation<'tcx>,
+ _expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ 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);
+ crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ let ty = fcx.check_expr_with_expectation(&body.value, expected);
+ fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+ fcx.write_ty(anon_const.hir_id, ty);
+ ty
+ }
+
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
@@ -1262,49 +1331,17 @@
.emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
}
- let error_happened = self.check_expr_struct_fields(
+ self.check_expr_struct_fields(
adt_ty,
expected,
expr.hir_id,
qpath.span(),
variant,
fields,
- base_expr.is_none(),
+ base_expr,
expr.span,
);
- if let Some(base_expr) = base_expr {
- // If check_expr_struct_fields hit an error, do not attempt to populate
- // the fields with the base_expr. This could cause us to hit errors later
- // when certain fields are assumed to exist that in fact do not.
- if !error_happened {
- self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
- match adt_ty.kind() {
- ty::Adt(adt, substs) if adt.is_struct() => {
- let fru_field_types = adt
- .non_enum_variant()
- .fields
- .iter()
- .map(|f| {
- self.normalize_associated_types_in(
- expr.span,
- f.ty(self.tcx, substs),
- )
- })
- .collect();
- self.typeck_results
- .borrow_mut()
- .fru_field_types_mut()
- .insert(expr.hir_id, fru_field_types);
- }
- _ => {
- self.tcx
- .sess
- .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
- }
- }
- }
- }
self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
adt_ty
}
@@ -1317,9 +1354,9 @@
span: Span,
variant: &'tcx ty::VariantDef,
ast_fields: &'tcx [hir::ExprField<'tcx>],
- check_completeness: bool,
+ base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
expr_span: Span,
- ) -> bool {
+ ) {
let tcx = self.tcx;
let adt_ty_hint = self
@@ -1394,7 +1431,116 @@
)
.emit();
}
- } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
+ }
+
+ // If check_expr_struct_fields hit an error, do not attempt to populate
+ // the fields with the base_expr. This could cause us to hit errors later
+ // when certain fields are assumed to exist that in fact do not.
+ if error_happened {
+ return;
+ }
+
+ if let Some(base_expr) = base_expr {
+ // FIXME: We are currently creating two branches here in order to maintain
+ // consistency. But they should be merged as much as possible.
+ let fru_tys = if self.tcx.features().type_changing_struct_update {
+ let base_ty = self.check_expr(base_expr);
+ match adt_ty.kind() {
+ ty::Adt(adt, substs) if adt.is_struct() => {
+ match base_ty.kind() {
+ ty::Adt(base_adt, base_subs) if adt == base_adt => {
+ variant
+ .fields
+ .iter()
+ .map(|f| {
+ let fru_ty = self.normalize_associated_types_in(
+ expr_span,
+ self.field_ty(base_expr.span, f, base_subs),
+ );
+ let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+ if let Some(_) = remaining_fields.remove(&ident) {
+ let target_ty =
+ self.field_ty(base_expr.span, f, substs);
+ let cause = self.misc(base_expr.span);
+ match self
+ .at(&cause, self.param_env)
+ .sup(target_ty, fru_ty)
+ {
+ Ok(InferOk { obligations, value: () }) => {
+ self.register_predicates(obligations)
+ }
+ // FIXME: Need better diagnostics for `FieldMisMatch` error
+ Err(_) => self
+ .report_mismatched_types(
+ &cause,
+ target_ty,
+ fru_ty,
+ FieldMisMatch(
+ variant.ident.name,
+ ident.name,
+ ),
+ )
+ .emit(),
+ }
+ }
+ fru_ty
+ })
+ .collect()
+ }
+ _ => {
+ return self
+ .report_mismatched_types(
+ &self.misc(base_expr.span),
+ adt_ty,
+ base_ty,
+ Sorts(expected_found_bool(true, adt_ty, base_ty)),
+ )
+ .emit();
+ }
+ }
+ }
+ _ => {
+ return self
+ .tcx
+ .sess
+ .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+ }
+ }
+ } else {
+ self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
+ let base_ty = self.check_expr(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,
+ };
+ if self.tcx.sess.is_nightly_build() && same_adt {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::type_changing_struct_update,
+ base_expr.span,
+ "type changing struct updating is experimental",
+ )
+ .emit();
+ }
+ });
+ match adt_ty.kind() {
+ ty::Adt(adt, substs) if adt.is_struct() => variant
+ .fields
+ .iter()
+ .map(|f| {
+ self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
+ })
+ .collect(),
+ _ => {
+ return self
+ .tcx
+ .sess
+ .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+ }
+ }
+ };
+ self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
+ } else if kind_name != "union" && !remaining_fields.is_empty() {
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
});
@@ -1405,8 +1551,6 @@
self.report_missing_fields(adt_ty, span, remaining_fields);
}
}
-
- error_happened
}
fn check_struct_fields_on_error(
@@ -1632,7 +1776,7 @@
.filter_map(|field| {
// ignore already set fields and private fields from non-local crates
if skip.iter().any(|&x| x == field.ident.name)
- || (!variant.def_id.is_local() && field.vis != Visibility::Public)
+ || (!variant.def_id.is_local() && !field.vis.is_public())
{
None
} else {
@@ -1928,7 +2072,7 @@
fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) {
let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
let generic_param = generics.type_param(¶m, self.tcx);
- if let ty::GenericParamDefKind::Type { synthetic: Some(..), .. } = generic_param.kind {
+ if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind {
return;
}
let param_def_id = generic_param.def_id;
@@ -2058,8 +2202,7 @@
) -> Option<(&Vec<ty::FieldDef>, SubstsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
- let mut autoderef = self.autoderef(span, base_t);
- while let Some((base_t, _)) = autoderef.next() {
+ for (base_t, _) in self.autoderef(span, base_t) {
match base_t.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
let fields = &base_def.non_enum_variant().fields;
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
index 296e453..e5da33d 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -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).map(|v| *v);
+ 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 ac4bb65..142a0a8 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -35,7 +35,6 @@
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
@@ -587,38 +586,6 @@
}
}
- /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
- /// type/region parameter was instantiated (`substs`), creates and registers suitable
- /// trait/region obligations.
- ///
- /// For example, if there is a function:
- ///
- /// ```
- /// fn foo<'a,T:'a>(...)
- /// ```
- ///
- /// and a reference:
- ///
- /// ```
- /// let f = foo;
- /// ```
- ///
- /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
- /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
- pub fn add_obligations_for_parameters(
- &self,
- cause: traits::ObligationCause<'tcx>,
- predicates: ty::InstantiatedPredicates<'tcx>,
- ) {
- assert!(!predicates.has_escaping_bound_vars());
-
- debug!("add_obligations_for_parameters(predicates={:?})", predicates);
-
- for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
- self.register_predicate(obligation);
- }
- }
-
// FIXME(arielb1): use this instead of field.ty everywhere
// Only for fields! Returns <none> for methods>
// Indifferent to privacy flags
@@ -643,11 +610,12 @@
#[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) {
- if let Err(errors) = self
+ let errors = self
.fulfillment_cx
.borrow_mut()
- .select_all_with_constness_or_error(&self, self.inh.constness)
- {
+ .select_all_with_constness_or_error(&self, self.inh.constness);
+
+ if !errors.is_empty() {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
@@ -658,13 +626,13 @@
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
- let result = self
+ let mut result = self
.fulfillment_cx
.borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness);
- if let Err(mut errors) = result {
- mutate_fulfillment_errors(&mut errors);
- self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+ if !result.is_empty() {
+ mutate_fulfillment_errors(&mut result);
+ self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
}
}
@@ -794,14 +762,17 @@
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
- self.save_and_restore_in_snapshot_flag(|_| {
+ let errors = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
- })
- .map_err(|_| ())?;
+ });
+
+ if !errors.is_empty() {
+ return Err(());
+ }
}
Err(_) => return Err(()),
}
@@ -949,7 +920,7 @@
let mut err = rustc_errors::struct_span_err!(
self.sess(),
self_ty.span,
- E0783,
+ E0782,
"{}",
msg,
);
@@ -1519,20 +1490,14 @@
/// Add all the obligations that are required, substituting and normalized appropriately.
#[tracing::instrument(level = "debug", skip(self, span, def_id, substs))]
- fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
- let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
+ crate fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+ let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
- for (i, mut obligation) in traits::predicates_for_generics(
+ for obligation in traits::predicates_for_generics(
traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
self.param_env,
bounds,
- )
- .enumerate()
- {
- // This makes the error point at the bound, but we want to point at the argument
- if let Some(span) = spans.get(i) {
- obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
- }
+ ) {
self.register_predicate(obligation);
}
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 5515223..74d7f0a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -370,6 +370,8 @@
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
+ final_arg_types.push((i, checked_ty, coerce_ty));
+
// Cause selection errors caused by resolving a single argument to point at the
// argument and not the call. This is otherwise redundant with the `demand_coerce`
// call immediately after, but it lets us customize the span pointed to in the
@@ -377,38 +379,20 @@
let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
coerce_ty,
|errors| {
- // This is not coming from a macro or a `derive`.
- if sp.desugaring_kind().is_none()
- && !arg.span.from_expansion()
- // Do not change the spans of `async fn`s.
- && !matches!(
- expr.kind,
- hir::ExprKind::Call(
- hir::Expr {
- kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)),
- ..
- },
- _
- )
- ) {
- for error in errors {
- error.obligation.cause.make_mut().span = arg.span;
- let code = error.obligation.cause.code.clone();
- error.obligation.cause.make_mut().code =
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: arg.hir_id,
- call_hir_id: expr.hir_id,
- parent_code: Lrc::new(code),
- };
- }
- }
+ self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+ self.point_at_arg_instead_of_call_if_possible(
+ errors,
+ &final_arg_types,
+ expr,
+ sp,
+ args,
+ );
},
);
// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
- final_arg_types.push((i, checked_ty, coerce_ty));
// 3. Relate the expected type and the formal one,
// if the expected type was used for the coercion.
@@ -525,10 +509,7 @@
self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
// Check bounds on type arguments used in the path.
- let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
- let cause =
- traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
- self.add_obligations_for_parameters(cause, bounds);
+ self.add_required_obligations(path_span, did, substs);
Some((variant, ty))
} else {
@@ -756,6 +737,24 @@
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+ if expected_ty == self.tcx.types.bool {
+ // If this is caused by a missing `let` in a `while let`,
+ // silence this redundant error, as we already emit E0070.
+ let parent = self.tcx.hir().get_parent_node(blk.hir_id);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ match self.tcx.hir().find(parent) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
+ ..
+ })) => {
+ err.delay_as_bug();
+ }
+ _ => {}
+ }
+ }
}
if let Some(fn_span) = fn_span {
err.span_label(
@@ -973,45 +972,79 @@
continue;
}
- if let ty::PredicateKind::Trait(predicate) =
- error.obligation.predicate.kind().skip_binder()
- {
- // Collect the argument position for all arguments that could have caused this
- // `FulfillmentError`.
- 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)))
- .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 == predicate.self_ty().into()) {
- Some(i)
- } else {
- None
- }
- })
- .collect::<Vec<usize>>();
+ // Peel derived obligation, because it's the type that originally
+ // started this inference chain that matters, not the one we wound
+ // up with at the end.
+ fn unpeel_to_top(
+ mut code: Lrc<ObligationCauseCode<'_>>,
+ ) -> Lrc<ObligationCauseCode<'_>> {
+ let mut result_code = code.clone();
+ loop {
+ let parent = match &*code {
+ ObligationCauseCode::BuiltinDerivedObligation(c)
+ | ObligationCauseCode::ImplDerivedObligation(c)
+ | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
+ _ => break,
+ };
+ result_code = std::mem::replace(&mut code, parent);
+ }
+ result_code
+ }
+ let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(Lrc::new(error.obligation.cause.code.clone())) {
+ ObligationCauseCode::BuiltinDerivedObligation(code) |
+ ObligationCauseCode::ImplDerivedObligation(code) |
+ ObligationCauseCode::DerivedObligation(code) => {
+ code.parent_trait_ref.self_ty().skip_binder().into()
+ }
+ _ if let ty::PredicateKind::Trait(predicate) =
+ error.obligation.predicate.kind().skip_binder() => {
+ predicate.self_ty().into()
+ }
+ _ => continue,
+ };
+ let self_ = self.resolve_vars_if_possible(self_);
- // Both checked and coerced types could have matched, thus we need to remove
- // duplicates.
+ // Collect the argument position for all arguments that could have caused this
+ // `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)))
+ .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 }
+ })
+ .collect::<Vec<usize>>();
- // We sort primitive type usize here and can use unstable sort
- referenced_in.sort_unstable();
- referenced_in.dedup();
+ // Both checked and coerced types could have matched, thus we need to remove
+ // duplicates.
- if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
- // We make sure that only *one* argument matches the obligation failure
- // and we assign the obligation's span to its expression's.
- error.obligation.cause.make_mut().span = args[ref_in].span;
- let code = error.obligation.cause.code.clone();
- error.obligation.cause.make_mut().code =
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: args[ref_in].hir_id,
- call_hir_id: expr.hir_id,
- parent_code: Lrc::new(code),
- };
+ // We sort primitive type usize here and can use unstable sort
+ referenced_in.sort_unstable();
+ referenced_in.dedup();
+
+ if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+ // Do not point at the inside of a macro.
+ // That would often result in poor error messages.
+ if args[ref_in].span.from_expansion() {
+ return;
+ }
+ // We make sure that only *one* argument matches the obligation failure
+ // and we assign the obligation's span to its expression's.
+ error.obligation.cause.make_mut().span = args[ref_in].span;
+ let code = error.obligation.cause.code.clone();
+ error.obligation.cause.make_mut().code =
+ ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id: args[ref_in].hir_id,
+ call_hir_id: expr.hir_id,
+ parent_code: Lrc::new(code),
+ };
+ } else if error.obligation.cause.make_mut().span == call_sp {
+ // Make function calls point at the callee, not the whole thing.
+ if let hir::ExprKind::Call(callee, _) = expr.kind {
+ error.obligation.cause.make_mut().span = callee.span;
}
}
}
@@ -1027,34 +1060,32 @@
call_expr: &'tcx hir::Expr<'tcx>,
) {
if let hir::ExprKind::Call(path, _) = &call_expr.kind {
- if let hir::ExprKind::Path(qpath) = &path.kind {
- if let hir::QPath::Resolved(_, path) = &qpath {
- for error in errors {
- if let ty::PredicateKind::Trait(predicate) =
- error.obligation.predicate.kind().skip_binder()
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &path.kind {
+ for error in errors {
+ if let ty::PredicateKind::Trait(predicate) =
+ error.obligation.predicate.kind().skip_binder()
+ {
+ // If any of the type arguments in this path segment caused the
+ // `FulfillmentError`, point at its span (#61860).
+ for arg in path
+ .segments
+ .iter()
+ .filter_map(|seg| seg.args.as_ref())
+ .flat_map(|a| a.args.iter())
{
- // If any of the type arguments in this path segment caused the
- // `FulfillmentError`, point at its span (#61860).
- for arg in path
- .segments
- .iter()
- .filter_map(|seg| seg.args.as_ref())
- .flat_map(|a| a.args.iter())
- {
- if let hir::GenericArg::Type(hir_ty) = &arg {
- if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
- &hir_ty.kind
- {
- // Avoid ICE with associated types. As this is best
- // effort only, it's ok to ignore the case. It
- // would trigger in `is_send::<T::AssocType>();`
- // from `typeck-default-trait-impl-assoc-type.rs`.
- } else {
- let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
- let ty = self.resolve_vars_if_possible(ty);
- if ty == predicate.self_ty() {
- error.obligation.cause.make_mut().span = hir_ty.span;
- }
+ if let hir::GenericArg::Type(hir_ty) = &arg {
+ if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
+ &hir_ty.kind
+ {
+ // Avoid ICE with associated types. As this is best
+ // effort only, it's ok to ignore the case. It
+ // would trigger in `is_send::<T::AssocType>();`
+ // from `typeck-default-trait-impl-assoc-type.rs`.
+ } else {
+ let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
+ let ty = self.resolve_vars_if_possible(ty);
+ if ty == predicate.self_ty() {
+ error.obligation.cause.make_mut().span = hir_ty.span;
}
}
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index dcc635a..6c7d3a0 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -14,6 +14,7 @@
use rustc_middle::ty::{self, Binder, Ty};
use rustc_span::symbol::{kw, sym};
+use rustc_middle::ty::subst::GenericArgKind;
use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -232,48 +233,72 @@
let is_struct_pat_shorthand_field =
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
- 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);
- if receiver.ends_with(&method_call) {
- None // do not suggest code that is already there (#53348)
- } else {
- let method_call_list = [".to_vec()", ".to_string()"];
- let mut sugg = if receiver.ends_with(".clone()")
- && method_call_list.contains(&method_call.as_str())
- {
- let max_len = receiver.rfind('.').unwrap();
- vec![(
- expr.span,
- format!("{}{}", &receiver[..max_len], method_call),
- )]
+ 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);
+ if receiver.ends_with(&method_call) {
+ None // do not suggest code that is already there (#53348)
} else {
- if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
- vec![
- (expr.span.shrink_to_lo(), "(".to_string()),
- (expr.span.shrink_to_hi(), format!("){}", method_call)),
- ]
+ let method_call_list = [".to_vec()", ".to_string()"];
+ let mut sugg = if receiver.ends_with(".clone()")
+ && method_call_list.contains(&method_call.as_str())
+ {
+ let max_len = receiver.rfind('.').unwrap();
+ vec![(
+ expr.span,
+ format!("{}{}", &receiver[..max_len], method_call),
+ )]
} else {
- vec![(expr.span.shrink_to_hi(), method_call)]
+ if expr.precedence().order()
+ < ExprPrecedence::MethodCall.order()
+ {
+ vec![
+ (expr.span.shrink_to_lo(), "(".to_string()),
+ (expr.span.shrink_to_hi(), format!("){}", method_call)),
+ ]
+ } else {
+ vec![(expr.span.shrink_to_hi(), method_call)]
+ }
+ };
+ if is_struct_pat_shorthand_field {
+ sugg.insert(
+ 0,
+ (expr.span.shrink_to_lo(), format!("{}: ", receiver)),
+ );
}
- };
- if is_struct_pat_shorthand_field {
- sugg.insert(
- 0,
- (expr.span.shrink_to_lo(), format!("{}: ", receiver)),
+ Some(sugg)
+ }
+ })
+ .peekable();
+ if suggestions.peek().is_some() {
+ err.multipart_suggestions(
+ "try using a conversion method",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ } else if found.to_string().starts_with("Option<")
+ && expected.to_string() == "Option<&str>"
+ {
+ if let ty::Adt(_def, subst) = found.kind() {
+ if subst.len() != 0 {
+ if let GenericArgKind::Type(ty) = subst[0].unpack() {
+ let peeled = ty.peel_refs().to_string();
+ if peeled == "String" {
+ let ref_cnt = ty.to_string().len() - peeled.len();
+ let result = format!(".map(|x| &*{}x)", "*".repeat(ref_cnt));
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ "try converting the passed type into a `&str`",
+ result,
+ Applicability::MaybeIncorrect,
);
}
- Some(sugg)
}
- })
- .peekable();
- if suggestions.peek().is_some() {
- err.multipart_suggestions(
- "try using a conversion method",
- suggestions,
- Applicability::MaybeIncorrect,
- );
+ }
}
}
}
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index b0cb844..6314f2a 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -324,9 +324,10 @@
sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
sym::discriminant_value => {
- let assoc_items =
- tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
- let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
+ let assoc_items = tcx.associated_item_def_ids(
+ tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
+ );
+ let discriminant_def_id = assoc_items[0];
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
(
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index dc54f63f..dabfe92 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -120,7 +120,12 @@
// We won't add these if we encountered an illegal sized bound, so that we can use
// a custom error in that case.
if illegal_sized_bound.is_none() {
- self.add_obligations(self.tcx.mk_fn_ptr(method_sig), all_substs, method_predicates);
+ self.add_obligations(
+ self.tcx.mk_fn_ptr(method_sig),
+ all_substs,
+ method_predicates,
+ pick.item.def_id,
+ );
}
// Create the final `MethodCallee`.
@@ -162,7 +167,7 @@
match &pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
- let region = self.next_region_var(infer::Autoref(self.span, pick.item));
+ let region = self.next_region_var(infer::Autoref(self.span));
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
let mutbl = match mutbl {
hir::Mutability::Not => AutoBorrowMutability::Not,
@@ -471,16 +476,23 @@
fty: Ty<'tcx>,
all_substs: SubstsRef<'tcx>,
method_predicates: ty::InstantiatedPredicates<'tcx>,
+ def_id: DefId,
) {
debug!(
- "add_obligations: fty={:?} all_substs={:?} method_predicates={:?}",
- fty, all_substs, method_predicates
+ "add_obligations: fty={:?} all_substs={:?} method_predicates={:?} def_id={:?}",
+ fty, all_substs, method_predicates, def_id
);
- self.add_obligations_for_parameters(
- traits::ObligationCause::misc(self.span, self.body_id),
+ // FIXME: could replace with the following, but we already calculated `method_predicates`,
+ // so we just call `predicates_for_generics` directly to avoid redoing work.
+ // `self.add_required_obligations(self.span, def_id, &all_substs);`
+ for obligation in traits::predicates_for_generics(
+ traits::ObligationCause::new(self.span, self.body_id, traits::ItemObligation(def_id)),
+ self.param_env,
method_predicates,
- );
+ ) {
+ self.register_predicate(obligation);
+ }
// this is a projection from a trait reference, so we have to
// make sure that the trait reference inputs are well-formed.
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index f0f2470..dbc1d4e 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -12,6 +12,7 @@
pub use self::MethodError::*;
use crate::check::FnCtxt;
+use crate::ObligationCause;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
@@ -71,7 +72,8 @@
#[derive(Debug)]
pub struct NoMatchData<'tcx> {
pub static_candidates: Vec<CandidateSource>,
- pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+ pub unsatisfied_predicates:
+ Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
pub out_of_scope_traits: Vec<DefId>,
pub lev_candidate: Option<ty::AssocItem>,
pub mode: probe::Mode,
@@ -80,7 +82,11 @@
impl<'tcx> NoMatchData<'tcx> {
pub fn new(
static_candidates: Vec<CandidateSource>,
- unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+ unsatisfied_predicates: Vec<(
+ ty::Predicate<'tcx>,
+ Option<ty::Predicate<'tcx>>,
+ Option<ObligationCause<'tcx>>,
+ )>,
out_of_scope_traits: Vec<DefId>,
lev_candidate: Option<ty::AssocItem>,
mode: probe::Mode,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 6eeb28e..9fd7e8c 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -78,7 +78,8 @@
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
/// for error reporting
- unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+ unsatisfied_predicates:
+ Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
is_suggestion: IsSuggestion,
@@ -92,7 +93,7 @@
}
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
// some metadata on top of a `ty::AssocItem` (without substs).
@@ -132,7 +133,7 @@
import_ids: SmallVec<[LocalDefId; 1]>,
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
enum CandidateKind<'tcx> {
InherentImplCandidate(
SubstsRef<'tcx>,
@@ -204,6 +205,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 self_ty: Ty<'tcx>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -1101,13 +1103,37 @@
}
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
- let steps = self.steps.clone();
+ let mut unstable_candidates = Vec::new();
+ let pick = self.pick_all_method(Some(&mut unstable_candidates));
- // find the first step that works
+ // In this case unstable picking is done by `pick_method`.
+ if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable {
+ return pick;
+ }
+
+ match pick {
+ // Emit a lint if there are unstable candidates alongside the stable ones.
+ //
+ // We suppress warning if we're picking the method only because it is a
+ // suggestion.
+ Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => {
+ self.emit_unstable_name_collision_hint(p, &unstable_candidates);
+ pick
+ }
+ Some(_) => pick,
+ None => self.pick_all_method(None),
+ }
+ }
+
+ fn pick_all_method(
+ &mut self,
+ mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+ ) -> Option<PickResult<'tcx>> {
+ let steps = self.steps.clone();
steps
.iter()
.filter(|step| {
- debug!("pick_core: step={:?}", step);
+ debug!("pick_all_method: step={:?}", step);
// skip types that are from a type error or that would require dereferencing
// a raw pointer
!step.self_ty.references_error() && !step.from_unsafe_deref
@@ -1123,11 +1149,30 @@
.unwrap_or_else(|_| {
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
});
- self.pick_by_value_method(step, self_ty).or_else(|| {
- self.pick_autorefd_method(step, self_ty, hir::Mutability::Not)
- .or_else(|| self.pick_autorefd_method(step, self_ty, hir::Mutability::Mut))
- .or_else(|| self.pick_const_ptr_method(step, self_ty))
- })
+ self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
+ .or_else(|| {
+ self.pick_autorefd_method(
+ step,
+ self_ty,
+ hir::Mutability::Not,
+ unstable_candidates.as_deref_mut(),
+ )
+ .or_else(|| {
+ self.pick_autorefd_method(
+ step,
+ self_ty,
+ hir::Mutability::Mut,
+ unstable_candidates.as_deref_mut(),
+ )
+ })
+ .or_else(|| {
+ self.pick_const_ptr_method(
+ step,
+ self_ty,
+ unstable_candidates.as_deref_mut(),
+ )
+ })
+ })
})
.next()
}
@@ -1142,12 +1187,13 @@
&mut self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
+ unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
if step.unsize {
return None;
}
- self.pick_method(self_ty).map(|r| {
+ self.pick_method(self_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
@@ -1170,6 +1216,7 @@
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
mutbl: hir::Mutability,
+ unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
let tcx = self.tcx;
@@ -1177,7 +1224,7 @@
let region = tcx.lifetimes.re_erased;
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
- self.pick_method(autoref_ty).map(|r| {
+ 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 {
@@ -1196,6 +1243,7 @@
&mut self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
+ unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
// Don't convert an unsized reference to ptr
if step.unsize {
@@ -1209,7 +1257,7 @@
let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
- self.pick_method(const_ptr_ty).map(|r| {
+ self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
@@ -1218,8 +1266,8 @@
})
}
- fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
- debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
+ fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
+ debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
let mut possibly_unsatisfied_predicates = Vec::new();
let mut unstable_candidates = Vec::new();
@@ -1241,7 +1289,7 @@
//
// We suppress warning if we're picking the method only because it is a
// suggestion.
- self.emit_unstable_name_collision_hint(p, &unstable_candidates, self_ty);
+ self.emit_unstable_name_collision_hint(p, &unstable_candidates);
}
}
return Some(pick);
@@ -1251,7 +1299,7 @@
debug!("searching unstable candidates");
let res = self.consider_candidates(
self_ty,
- unstable_candidates.into_iter().map(|(c, _)| c),
+ unstable_candidates.iter().map(|(c, _)| c),
&mut possibly_unsatisfied_predicates,
None,
);
@@ -1261,6 +1309,42 @@
res
}
+ fn pick_method(
+ &mut self,
+ self_ty: Ty<'tcx>,
+ mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+ ) -> Option<PickResult<'tcx>> {
+ if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable {
+ return self.pick_method_with_unstable(self_ty);
+ }
+
+ debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
+
+ let mut possibly_unsatisfied_predicates = Vec::new();
+
+ for (kind, candidates) in
+ &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
+ {
+ debug!("searching {} candidates", kind);
+ let res = self.consider_candidates(
+ self_ty,
+ candidates.iter(),
+ &mut possibly_unsatisfied_predicates,
+ unstable_candidates.as_deref_mut(),
+ );
+ if let Some(pick) = res {
+ return Some(pick);
+ }
+ }
+
+ // `pick_method` may be called twice for the same self_ty if no stable methods
+ // match. Only extend once.
+ if unstable_candidates.is_some() {
+ self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+ }
+ None
+ }
+
fn consider_candidates<'b, ProbesIter>(
&self,
self_ty: Ty<'tcx>,
@@ -1268,11 +1352,13 @@
possibly_unsatisfied_predicates: &mut Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
+ Option<ObligationCause<'tcx>>,
)>,
- unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
+ unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>>
where
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
+ 'tcx: 'b,
{
let mut applicable_candidates: Vec<_> = probes
.clone()
@@ -1285,7 +1371,9 @@
debug!("applicable_candidates: {:?}", applicable_candidates);
if applicable_candidates.len() > 1 {
- if let Some(pick) = self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
+ if let Some(pick) =
+ self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates[..])
+ {
return Some(Ok(pick));
}
}
@@ -1295,7 +1383,7 @@
if let stability::EvalResult::Deny { feature, .. } =
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
{
- uc.push((p, feature));
+ uc.push((p.clone(), feature));
return false;
}
true
@@ -1309,7 +1397,7 @@
applicable_candidates.pop().map(|(probe, status)| {
if status == ProbeResult::Match {
- Ok(probe.to_unadjusted_pick())
+ Ok(probe.to_unadjusted_pick(self_ty))
} else {
Err(MethodError::BadReturnType)
}
@@ -1319,8 +1407,7 @@
fn emit_unstable_name_collision_hint(
&self,
stable_pick: &Pick<'_>,
- unstable_candidates: &[(&Candidate<'tcx>, Symbol)],
- self_ty: Ty<'tcx>,
+ unstable_candidates: &[(Candidate<'tcx>, Symbol)],
) {
self.tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
@@ -1351,7 +1438,7 @@
"use the fully qualified path to the associated const",
format!(
"<{} as {}>::{}",
- self_ty,
+ stable_pick.self_ty,
self.tcx.def_path_str(def_id),
stable_pick.item.ident
),
@@ -1412,6 +1499,7 @@
possibly_unsatisfied_predicates: &mut Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
+ Option<ObligationCause<'tcx>>,
)>,
) -> ProbeResult {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
@@ -1423,8 +1511,8 @@
.sup(probe.xform_self_ty, self_ty)
{
Ok(InferOk { obligations, value: () }) => obligations,
- Err(_) => {
- debug!("--> cannot relate self-types");
+ Err(err) => {
+ debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
};
@@ -1473,7 +1561,11 @@
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
- possibly_unsatisfied_predicates.push((o.predicate, None));
+ possibly_unsatisfied_predicates.push((
+ o.predicate,
+ None,
+ Some(o.cause),
+ ));
}
}
}
@@ -1519,8 +1611,11 @@
} else {
Some(predicate)
};
- possibly_unsatisfied_predicates
- .push((nested_predicate, p));
+ possibly_unsatisfied_predicates.push((
+ nested_predicate,
+ p,
+ Some(obligation.cause.clone()),
+ ));
}
}
}
@@ -1528,7 +1623,7 @@
// Some nested subobligation of this predicate
// failed.
let predicate = self.resolve_vars_if_possible(predicate);
- possibly_unsatisfied_predicates.push((predicate, None));
+ possibly_unsatisfied_predicates.push((predicate, None, None));
}
}
false
@@ -1547,7 +1642,7 @@
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
- possibly_unsatisfied_predicates.push((o.predicate, None));
+ possibly_unsatisfied_predicates.push((o.predicate, None, Some(o.cause)));
}
}
@@ -1591,6 +1686,7 @@
/// use, so it's ok to just commit to "using the method from the trait Foo".
fn collapse_candidates_to_trait_pick(
&self,
+ self_ty: Ty<'tcx>,
probes: &[(&Candidate<'tcx>, ProbeResult)],
) -> Option<Pick<'tcx>> {
// Do all probes correspond to the same trait?
@@ -1610,6 +1706,7 @@
import_ids: probes[0].0.import_ids.clone(),
autoderefs: 0,
autoref_or_ptr_adjustment: None,
+ self_ty,
})
}
@@ -1828,7 +1925,7 @@
}
impl<'tcx> Candidate<'tcx> {
- fn to_unadjusted_pick(&self) -> Pick<'tcx> {
+ fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> {
Pick {
item: self.item,
kind: match self.kind {
@@ -1852,6 +1949,7 @@
import_ids: self.import_ids.clone(),
autoderefs: 0,
autoref_or_ptr_adjustment: None,
+ self_ty,
}
}
}
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 183ebc5..ca174ed 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -15,9 +15,11 @@
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, MultiSpan, Span};
+use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{FulfillmentError, Obligation};
+use rustc_trait_selection::traits::{
+ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
+};
use std::cmp::Ordering;
use std::iter;
@@ -317,6 +319,10 @@
.span_to_snippet(lit.span)
.unwrap_or_else(|_| "<numeric literal>".to_owned());
+ // If this is a floating point literal that ends with '.',
+ // get rid of it to stop this from becoming a member access.
+ let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
+
err.span_suggestion(
lit.span,
&format!(
@@ -324,7 +330,7 @@
like `{}`",
concrete_type
),
- format!("{}_{}", snippet, concrete_type),
+ format!("{snippet}_{concrete_type}"),
Applicability::MaybeIncorrect,
);
}
@@ -478,6 +484,26 @@
let mut label_span_not_found = || {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ let is_string_or_ref_str = match actual.kind() {
+ ty::Ref(_, ty, _) => {
+ ty.is_str()
+ || matches!(
+ ty.kind(),
+ ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
+ )
+ }
+ ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
+ _ => false,
+ };
+ if is_string_or_ref_str && item_name.name == sym::iter {
+ err.span_suggestion_verbose(
+ item_name.span,
+ "because of the in-memory representation of `&str`, to obtain \
+ an `Iterator` over each of its codepoint use method `chars`",
+ String::from("chars"),
+ Applicability::MachineApplicable,
+ );
+ }
if let ty::Adt(adt, _) = rcvr_ty.kind() {
let mut inherent_impls_candidate = self
.tcx
@@ -678,27 +704,39 @@
if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
(self_ty.kind(), parent_pred.kind().skip_binder())
{
- if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
- let node = def.did.as_local().map(|def_id| {
+ let node = match p.trait_ref.self_ty().kind() {
+ ty::Param(_) => {
+ // Account for `fn` items like in `issue-35677.rs` to
+ // suggest restricting its type params.
+ let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
+ hir_id: self.body_id,
+ });
+ Some(
+ self.tcx
+ .hir()
+ .get(self.tcx.hir().local_def_id_to_hir_id(did)),
+ )
+ }
+ ty::Adt(def, _) => def.did.as_local().map(|def_id| {
self.tcx
.hir()
.get(self.tcx.hir().local_def_id_to_hir_id(def_id))
- });
- if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
- if let Some(g) = kind.generics() {
- let key = match g.where_clause.predicates {
- [.., pred] => (pred.span().shrink_to_hi(), false),
- [] => (
- g.where_clause
- .span_for_predicates_or_empty_place(),
- true,
- ),
- };
- type_params
- .entry(key)
- .or_insert_with(FxHashSet::default)
- .insert(obligation.to_owned());
- }
+ }),
+ _ => None,
+ };
+ if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+ if let Some(g) = kind.generics() {
+ let key = match g.where_clause.predicates {
+ [.., pred] => (pred.span().shrink_to_hi(), false),
+ [] => (
+ g.where_clause.span_for_predicates_or_empty_place(),
+ true,
+ ),
+ };
+ type_params
+ .entry(key)
+ .or_insert_with(FxHashSet::default)
+ .insert(obligation.to_owned());
}
}
}
@@ -767,22 +805,109 @@
_ => None,
}
};
+
+ // Find all the requirements that come from a local `impl` block.
+ let mut skip_list: FxHashSet<_> = Default::default();
+ let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+ for (data, p, parent_p) in unsatisfied_predicates
+ .iter()
+ .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+ .filter_map(|(p, parent, c)| match c.code {
+ ObligationCauseCode::ImplDerivedObligation(ref data) => {
+ Some((data, p, parent))
+ }
+ _ => None,
+ })
+ {
+ let parent_trait_ref = data.parent_trait_ref;
+ let parent_def_id = parent_trait_ref.def_id();
+ let path = parent_trait_ref.print_only_trait_path();
+ let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+ let mut candidates = vec![];
+ self.tcx.for_each_relevant_impl(
+ parent_def_id,
+ parent_trait_ref.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 { .. }),
+ ..
+ })) => {
+ candidates.push(impl_def_id);
+ }
+ _ => {}
+ },
+ );
+ if let [def_id] = &candidates[..] {
+ match self.tcx.hir().get_if_local(*def_id) {
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+ ..
+ })) => {
+ if let Some(pred) = parent_p {
+ // Done to add the "doesn't satisfy" `span_label`.
+ let _ = format_pred(*pred);
+ }
+ skip_list.insert(p);
+ let mut spans = Vec::with_capacity(2);
+ if let Some(trait_ref) = of_trait {
+ spans.push(trait_ref.path.span);
+ }
+ spans.push(self_ty.span);
+ let entry = spanned_predicates.entry(spans.into());
+ entry
+ .or_insert_with(|| (path, tr_self_ty, Vec::new()))
+ .2
+ .push(p);
+ }
+ _ => {}
+ }
+ }
+ }
+ for (span, (path, self_ty, preds)) in spanned_predicates {
+ err.span_note(
+ span,
+ &format!(
+ "the following trait bounds were not satisfied because of the \
+ requirements of the implementation of `{}` for `{}`:\n{}",
+ path,
+ self_ty,
+ preds
+ .into_iter()
+ // .map(|pred| format!("{:?}", pred))
+ .filter_map(|pred| format_pred(*pred))
+ .map(|(p, _)| format!("`{}`", p))
+ .collect::<Vec<_>>()
+ .join("\n"),
+ ),
+ );
+ }
+
+ // The requirements that didn't have an `impl` span to show.
let mut bound_list = unsatisfied_predicates
.iter()
- .filter_map(|(pred, parent_pred)| {
- format_pred(*pred).map(|(p, self_ty)| match parent_pred {
- None => format!("`{}`", &p),
- Some(parent_pred) => match format_pred(*parent_pred) {
+ .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);
+ match parent_pred {
None => format!("`{}`", &p),
- Some((parent_p, _)) => {
- collect_type_param_suggestions(self_ty, parent_pred, &p);
- format!("`{}`\nwhich is required by `{}`", p, parent_p)
- }
- },
+ Some(parent_pred) => match format_pred(*parent_pred) {
+ None => format!("`{}`", &p),
+ Some((parent_p, _)) => {
+ collect_type_param_suggestions(
+ self_ty,
+ parent_pred,
+ &p,
+ );
+ format!("`{}`\nwhich is required by `{}`", p, parent_p)
+ }
+ },
+ }
})
})
.enumerate()
.collect::<Vec<(usize, String)>>();
+
for ((span, empty_where), obligations) in type_params.into_iter() {
restrict_type_params = true;
// #74886: Sort here so that the output is always the same.
@@ -812,7 +937,7 @@
for (span, msg) in bound_spans.into_iter() {
err.span_label(span, &msg);
}
- if !bound_list.is_empty() {
+ if !bound_list.is_empty() || !skip_list.is_empty() {
let bound_list = bound_list
.into_iter()
.map(|(_, path)| path)
@@ -822,9 +947,11 @@
err.set_primary_message(&format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));
- err.note(&format!(
- "the following trait bounds were not satisfied:\n{bound_list}"
- ));
+ if !bound_list.is_empty() {
+ err.note(&format!(
+ "the following trait bounds were not satisfied:\n{bound_list}"
+ ));
+ }
self.suggest_derive(&mut err, &unsatisfied_predicates);
unsatisfied_bounds = true;
@@ -1038,18 +1165,25 @@
err.span_note(spans, &msg);
}
- let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect();
+ let preds: Vec<_> = errors
+ .iter()
+ .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
+ .collect();
self.suggest_derive(err, &preds);
}
fn suggest_derive(
&self,
err: &mut DiagnosticBuilder<'_>,
- unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+ unsatisfied_predicates: &Vec<(
+ ty::Predicate<'tcx>,
+ Option<ty::Predicate<'tcx>>,
+ Option<ObligationCause<'tcx>>,
+ )>,
) {
let mut derives = Vec::<(String, Span, String)>::new();
let mut traits = Vec::<Span>::new();
- for (pred, _) in unsatisfied_predicates {
+ for (pred, _, _) in unsatisfied_predicates {
let trait_pred = match pred.kind().skip_binder() {
ty::PredicateKind::Trait(trait_pred) => trait_pred,
_ => continue,
@@ -1203,6 +1337,13 @@
let mut candidates = valid_out_of_scope_traits;
candidates.sort();
candidates.dedup();
+
+ // `TryFrom` and `FromIterator` have no methods
+ let edition_fix = candidates
+ .iter()
+ .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
+ .copied();
+
err.help("items from traits can only be used if the trait is in scope");
let msg = format!(
"the following {traits_are} implemented but not in scope; \
@@ -1212,6 +1353,13 @@
);
self.suggest_use_candidates(err, msg, candidates);
+ if let Some(did) = edition_fix {
+ err.note(&format!(
+ "'{}' is included in the prelude starting in Edition 2021",
+ with_crate_prefix(|| self.tcx.def_path_str(did))
+ ));
+ }
+
true
} else {
false
@@ -1226,7 +1374,11 @@
item_name: Ident,
source: SelfSource<'tcx>,
valid_out_of_scope_traits: Vec<DefId>,
- unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
+ unsatisfied_predicates: &[(
+ ty::Predicate<'tcx>,
+ Option<ty::Predicate<'tcx>>,
+ Option<ObligationCause<'tcx>>,
+ )],
unsatisfied_bounds: bool,
) {
let mut alt_rcvr_sugg = false;
@@ -1237,6 +1389,7 @@
self.tcx.lang_items().deref_trait(),
self.tcx.lang_items().deref_mut_trait(),
self.tcx.lang_items().drop_trait(),
+ self.tcx.get_diagnostic_item(sym::AsRef),
];
// Try alternative arbitrary self types that could fulfill this call.
// FIXME: probe for all types that *could* be arbitrary self-types, not
@@ -1286,7 +1439,11 @@
// We don't want to suggest a container type when the missing
// method is `.clone()` or `.deref()` otherwise we'd suggest
// `Arc::new(foo).clone()`, which is far from what the user wants.
- let skip = skippable.contains(&did);
+ // 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));
// 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`
@@ -1337,7 +1494,7 @@
// this isn't perfect (that is, there are cases when
// implementing a trait would be legal but is rejected
// here).
- unsatisfied_predicates.iter().all(|(p, _)| {
+ unsatisfied_predicates.iter().all(|(p, _, _)| {
match p.kind().skip_binder() {
// Hide traits if they are present in predicates as they can be fixed without
// having to implement them.
@@ -1391,7 +1548,7 @@
}
}
// We only want to suggest public or local traits (#45781).
- item.vis == ty::Visibility::Public || info.def_id.is_local()
+ item.vis.is_public() || info.def_id.is_local()
})
.is_some()
})
@@ -1451,7 +1608,7 @@
Node::GenericParam(param) => {
let mut impl_trait = false;
let has_bounds =
- if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
+ if let hir::GenericParamKind::Type { synthetic: true, .. } =
¶m.kind
{
// We've found `fn foo(x: impl Trait)` instead of
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index a037bb6..7bfd3f0 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -297,9 +297,9 @@
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id);
- if outer_def_id != def_id {
- return tcx.has_typeck_results(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
@@ -348,9 +348,9 @@
) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
@@ -535,8 +535,8 @@
}
fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
- // Only restricted on wasm32 target for now
- if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+ // Only restricted on wasm target for now
+ if !tcx.sess.target.is_like_wasm {
return;
}
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 79e004a..f83209f 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -42,7 +42,7 @@
return_ty
};
- self.check_lhs_assignable(lhs, "E0067", &op.span);
+ self.check_lhs_assignable(lhs, "E0067", op.span);
ty
}
@@ -399,12 +399,9 @@
}
};
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!(
"`{}{}` can be used on `{}`, you can dereference `{}`",
@@ -492,7 +489,7 @@
other_ty: Ty<'tcx>,
op: hir::BinOp,
is_assign: IsAssign,
- ) -> bool /* did we suggest to call a function because of missing parenthesis? */ {
+ ) -> bool /* did we suggest to call a function because of missing parentheses? */ {
err.span_label(span, ty.to_string());
if let FnDef(def_id, _) = *ty.kind() {
let source_map = self.tcx.sess.source_map();
@@ -502,9 +499,7 @@
// FIXME: Instead of exiting early when encountering bound vars in
// the function signature, consider keeping the binder here and
// propagating it downwards.
- let fn_sig = if let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() {
- fn_sig
- } else {
+ let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else {
return false;
};
@@ -831,10 +826,7 @@
self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
fulfill.register_predicate_obligation(self, obligation);
- Err(match fulfill.select_where_possible(&self.infcx) {
- Err(errors) => errors,
- _ => vec![],
- })
+ Err(fulfill.select_where_possible(&self.infcx))
}
}
}
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 6352191..cbf33cf 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -292,7 +292,9 @@
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
- PatKind::Lit(lt) => match self.check_expr(lt).kind() {
+ //
+ // Call `resolve_vars_if_possible` here for inline const blocks.
+ PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel,
},
@@ -718,10 +720,7 @@
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
// Resolve the path and check the definition for errors.
- let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id)
- {
- variant_ty
- } else {
+ let Some((variant, pat_ty)) = self.check_struct_path(qpath, pat.hir_id) else {
let err = self.tcx.ty_error();
for field in fields {
let ti = TopInfo { parent_pat: Some(pat), ..ti };
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 849bf1e..5d9e6eb 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -411,9 +411,7 @@
debug!("convert_place_op_to_mutable: method={:?}", method);
self.write_method_call(expr.hir_id, method);
- let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() {
- r
- } else {
+ let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else {
span_bug!(expr.span, "input to mutable place op is not a mut ref?");
};
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 7c8b752..d2d8b14 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -88,7 +88,6 @@
use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use std::ops::Deref;
// a variation on try that just returns unit
@@ -104,7 +103,7 @@
};
}
-trait OutlivesEnvironmentExt<'tcx> {
+pub(crate) trait OutlivesEnvironmentExt<'tcx> {
fn add_implied_bounds(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
@@ -340,8 +339,29 @@
self.link_fn_params(body.params);
self.visit_body(body);
self.visit_region_obligations(body_id.hir_id);
+ }
- self.constrain_opaque_types(self.outlives_environment.free_region_map());
+ fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+ debug!("visit_inline_const(id={:?})", id);
+
+ // Save state of current function. We will restore afterwards.
+ let old_body_id = self.body_id;
+ let old_body_owner = self.body_owner;
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
+
+ let body_id = body.id();
+ self.body_id = body_id.hir_id;
+ self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
+
+ self.outlives_environment.save_implied_bounds(body_id.hir_id);
+
+ self.visit_body(body);
+ self.visit_region_obligations(body_id.hir_id);
+
+ // Restore state from previous function.
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
+ self.body_id = old_body_id;
+ self.body_owner = old_body_owner;
}
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
@@ -409,13 +429,13 @@
// `visit_fn_body`. We will restore afterwards.
let old_body_id = self.body_id;
let old_body_owner = self.body_owner;
- let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
let body = self.tcx.hir().body(body_id);
self.visit_fn_body(hir_id, body, span);
// Restore state from previous function.
- self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
self.body_id = old_body_id;
self.body_owner = old_body_owner;
}
@@ -463,6 +483,11 @@
intravisit::walk_expr(self, expr);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.tcx.hir().body(anon_const.body);
+ self.visit_inline_const(anon_const.hir_id, body);
+ }
+
_ => intravisit::walk_expr(self, expr),
}
}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 67c9670..5f5d308 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -148,10 +148,17 @@
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
- let body = self.fcx.tcx.hir().body(body_id);
- self.visit_body(body);
- self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ match expr.kind {
+ hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+ let body = self.fcx.tcx.hir().body(body_id);
+ self.visit_body(body);
+ self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ }
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.fcx.tcx.hir().body(anon_const.body);
+ self.visit_body(body);
+ }
+ _ => {}
}
intravisit::walk_expr(self, expr);
@@ -930,8 +937,8 @@
self.tcx.get_diagnostic_item(sym::unwind_safe_trait),
self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait),
];
- let auto_traits =
- vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
+ const AUTO_TRAITS: [&str; 6] =
+ ["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?;
@@ -1004,7 +1011,7 @@
// by the root variable but not by the capture
for (idx, _) in obligations_should_hold.iter().enumerate() {
if !obligations_holds_for_capture[idx] && obligations_should_hold[idx] {
- capture_problems.insert(auto_traits[idx]);
+ capture_problems.insert(AUTO_TRAITS[idx]);
}
}
@@ -1052,11 +1059,7 @@
return None;
}
- let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
- min_captures.and_then(|m| m.get(&var_hir_id))
- {
- root_var_min_capture_list
- } else {
+ let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else {
// The upvar is mentioned within the closure but no path starting from it is
// used. This occurs when you have (e.g.)
//
@@ -1150,9 +1153,7 @@
closure_clause: hir::CaptureBy,
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
) -> (Vec<NeededMigration>, MigrationWarningReason) {
- let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
- upvars
- } else {
+ let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else {
return (Vec::new(), MigrationWarningReason::default());
};
@@ -1756,9 +1757,7 @@
diag_expr_id: hir::HirId,
) {
let tcx = self.fcx.tcx;
- let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
- upvar_id
- } else {
+ let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else {
return;
};
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index d737fe9..e58faf9 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -1,3 +1,4 @@
+use crate::check::regionck::OutlivesEnvironmentExt;
use crate::check::{FnCtxt, Inherited};
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
@@ -11,16 +12,21 @@
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
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_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
- self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
+ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+ WithConstness,
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::Span;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
use std::convert::TryInto;
@@ -253,6 +259,362 @@
.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>>;
+/// }
+/// ```
+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();
+
+ 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);
+ }
+ }
+ }
+
+ // 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 {
+ 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);
+ }
+ }
+ }
+
+ // 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);
+ }
+ }
+ }
+
+ // If there are any missing clauses, emit an error
+ let mut clauses = clauses.unwrap_or_default();
+ debug!(?clauses);
+ if !clauses.is_empty() {
+ let written_predicates: ty::GenericPredicates<'_> =
+ tcx.explicit_predicates_of(trait_item.def_id);
+ let mut clauses: Vec<_> = clauses
+ .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause))
+ .map(|clause| format!("{}", clause))
+ .collect();
+ // We sort so that order is predictable
+ clauses.sort();
+ if !clauses.is_empty() {
+ let mut err = tcx.sess.struct_span_err(
+ trait_item.span,
+ &format!("Missing required bounds on {}", trait_item.ident),
+ );
+
+ let suggestion = format!(
+ "{} {}",
+ if !trait_item.generics.where_clause.predicates.is_empty() {
+ ","
+ } else {
+ " where"
+ },
+ clauses.join(", "),
+ );
+ err.span_suggestion(
+ trait_item.generics.where_clause.tail_span_for_suggestion(),
+ "add the required where clauses",
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+
+ err.emit()
+ }
+ }
+}
+
+// FIXME(jackh726): refactor some of the shared logic between the two functions below
+
+/// Given a known `param_env` and a set of well formed types, can we prove that
+/// `ty` outlives `region`.
+fn ty_known_to_outlive<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ wf_tys: &FxHashSet<Ty<'tcx>>,
+ ty: Ty<'tcx>,
+ region: 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 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;
+ (&infcx).push_sub_region_constraint(origin, region_a, region_b);
+
+ 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()
+ })
+}
+
+/// TypeVisitor that looks for uses of GATs like
+/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
+/// the two vectors, `regions` and `types` (depending on their kind). For each
+/// parameter `Pi` also track the index `i`.
+struct GATSubstCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ gat: DefId,
+ // Which region appears and which parameter index its subsituted for
+ regions: FxHashSet<(ty::Region<'tcx>, usize)>,
+ // Which params appears and which parameter index its subsituted for
+ types: FxHashSet<(Ty<'tcx>, usize)>,
+}
+
+impl<'tcx> GATSubstCollector<'tcx> {
+ fn visit<T: TypeFoldable<'tcx>>(
+ tcx: TyCtxt<'tcx>,
+ gat: DefId,
+ t: T,
+ ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
+ let mut visitor = GATSubstCollector {
+ tcx,
+ gat,
+ regions: FxHashSet::default(),
+ types: FxHashSet::default(),
+ };
+ t.visit_with(&mut visitor);
+ (visitor.regions, visitor.types)
+ }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
+ type BreakTy = !;
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ ty::Projection(p) if p.item_def_id == self.gat => {
+ for (idx, subst) in p.substs.iter().enumerate() {
+ match subst.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ self.regions.insert((lt, idx));
+ }
+ GenericArgKind::Type(t) => {
+ self.types.insert((t, idx));
+ }
+ _ => {}
+ }
+ }
+ }
+ _ => {}
+ }
+ 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 {
@@ -1274,19 +1636,38 @@
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
/// aren't true.
-fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
+fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirId) {
let empty_env = ty::ParamEnv::empty();
let def_id = fcx.tcx.hir().local_def_id(id);
- let predicates = fcx.tcx.predicates_of(def_id).predicates.iter().map(|(p, _)| *p);
+ let predicates_with_span =
+ fcx.tcx.predicates_of(def_id).predicates.iter().map(|(p, span)| (*p, *span));
// Check elaborated bounds.
- let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
+ let implied_obligations = traits::elaborate_predicates_with_span(fcx.tcx, predicates_with_span);
for obligation in implied_obligations {
let pred = obligation.predicate;
// Match the existing behavior.
if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() {
let pred = fcx.normalize_associated_types_in(span, pred);
+ let hir_node = fcx.tcx.hir().find(id);
+
+ // only use the span of the predicate clause (#90869)
+
+ if let Some(hir::Generics { where_clause, .. }) =
+ hir_node.and_then(|node| node.generics())
+ {
+ let obligation_span = obligation.cause.span(fcx.tcx);
+
+ span = where_clause
+ .predicates
+ .iter()
+ // There seems to be no better way to find out which predicate we are in
+ .find(|pred| pred.span().contains(obligation_span))
+ .map(|pred| pred.span())
+ .unwrap_or(obligation_span);
+ }
+
let obligation = traits::Obligation::new(
traits::ObligationCause::new(span, id, traits::TrivialBound),
empty_env,
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index d951df9..fdc8b6b 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -282,6 +282,12 @@
hir::ExprKind::Field(..) => {
self.visit_field_id(e.hir_id);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ self.visit_node_id(e.span, anon_const.hir_id);
+
+ let body = self.tcx().hir().body(anon_const.body);
+ self.visit_body(body);
+ }
_ => {}
}
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 8cae61e..372e835 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -180,14 +180,14 @@
let coerced_fields = fields
.iter()
- .filter_map(|field| {
+ .filter(|field| {
let ty_a = field.ty(tcx, substs_a);
let ty_b = field.ty(tcx, substs_b);
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
if layout.is_zst() && layout.align.abi.bytes() == 1 {
// ignore ZST fields with alignment of 1 byte
- return None;
+ return false;
}
}
@@ -204,11 +204,11 @@
))
.emit();
- return None;
+ return false;
}
}
- Some(field)
+ return true;
})
.collect::<Vec<_>>();
@@ -263,7 +263,8 @@
}
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
@@ -522,7 +523,8 @@
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 079604f..377ebf1 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -168,6 +168,7 @@
use self::builtin::coerce_unsized_info;
use self::inherent_impls::{crate_inherent_impls, inherent_impls};
use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
+ use self::orphan::orphan_check_crate;
*providers = Providers {
coherent_trait,
@@ -175,6 +176,7 @@
inherent_impls,
crate_inherent_impls_overlap_check,
coerce_unsized_info,
+ orphan_check_crate,
..*providers
};
}
@@ -195,13 +197,13 @@
}
pub fn check_coherence(tcx: TyCtxt<'_>) {
+ tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
+ tcx.ensure().orphan_check_crate(());
+
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
tcx.ensure().coherent_trait(trait_def_id);
}
- tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
- tcx.sess.time("orphan_checking", || orphan::check(tcx));
-
// these queries are executed for side-effects (error reporting):
tcx.ensure().crate_inherent_impls(());
tcx.ensure().crate_inherent_impls_overlap_check(());
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 0326d1f..b450d3f 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -2,250 +2,266 @@
//! crate or pertains to a type defined in this crate.
use rustc_errors::struct_span_err;
+use rustc_errors::ErrorReported;
use rustc_hir as hir;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
use rustc_trait_selection::traits;
-pub fn check(tcx: TyCtxt<'_>) {
- let mut orphan = OrphanChecker { tcx };
- tcx.hir().visit_all_item_likes(&mut orphan);
-}
-
-struct OrphanChecker<'tcx> {
- tcx: TyCtxt<'tcx>,
-}
-
-impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
- /// Checks exactly one impl for orphan rules and other such
- /// restrictions. In this fn, it can happen that multiple errors
- /// apply to a specific impl, so just return after reporting one
- /// to prevent inundating the user with a bunch of similar error
- /// reports.
- fn visit_item(&mut self, item: &hir::Item<'_>) {
- // "Trait" impl
- if let hir::ItemKind::Impl(hir::Impl {
- generics, of_trait: Some(ref tr), self_ty, ..
- }) = &item.kind
- {
- debug!(
- "coherence2::orphan check: trait impl {}",
- self.tcx.hir().node_to_string(item.hir_id())
- );
- let trait_ref = self.tcx.impl_trait_ref(item.def_id).unwrap();
- let trait_def_id = trait_ref.def_id;
- let sm = self.tcx.sess.source_map();
- let sp = sm.guess_head_span(item.span);
- match traits::orphan_check(self.tcx, item.def_id.to_def_id()) {
+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 &impl_of_trait in impls_of_trait {
+ match orphan_check_impl(tcx, impl_of_trait) {
Ok(()) => {}
- Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- sp,
- E0117,
- "only traits defined in the current crate can be implemented for \
- arbitrary types"
- );
- err.span_label(sp, "impl doesn't use only types from inside the current crate");
- for (ty, is_target_ty) in &tys {
- let mut ty = *ty;
- self.tcx.infer_ctxt().enter(|infcx| {
- // Remove the lifetimes unnecessary for this error.
- ty = infcx.freshen(ty);
- });
- ty = match ty.kind() {
- // Remove the type arguments from the output, as they are not relevant.
- // You can think of this as the reverse of `resolve_vars_if_possible`.
- // That way if we had `Vec<MyType>`, we will properly attribute the
- // problem to `Vec<T>` and avoid confusing the user if they were to see
- // `MyType` in the error.
- ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
- _ => ty,
- };
- let this = "this".to_string();
- let (ty, postfix) = match &ty.kind() {
- ty::Slice(_) => (this, " because slices are always foreign"),
- ty::Array(..) => (this, " because arrays are always foreign"),
- ty::Tuple(..) => (this, " because tuples are always foreign"),
- _ => (format!("`{}`", ty), ""),
- };
- let msg = format!("{} is not defined in the current crate{}", ty, postfix);
- if *is_target_ty {
- // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(self_ty.span, &msg);
- } else {
- // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(tr.path.span, &msg);
- }
- }
- err.note("define and implement a trait or new type instead");
- err.emit();
- return;
- }
- Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
- let mut sp = sp;
- for param in generics.params {
- if param.name.ident().to_string() == param_ty.to_string() {
- sp = param.span;
- }
- }
-
- match local_type {
- Some(local_type) => {
- struct_span_err!(
- self.tcx.sess,
- sp,
- E0210,
- "type parameter `{}` must be covered by another type \
- when it appears before the first local type (`{}`)",
- param_ty,
- local_type
- )
- .span_label(
- sp,
- format!(
- "type parameter `{}` must be covered by another type \
- when it appears before the first local type (`{}`)",
- param_ty, local_type
- ),
- )
- .note(
- "implementing a foreign trait is only possible if at \
- least one of the types for which it is implemented is local, \
- and no uncovered type parameters appear before that first \
- local type",
- )
- .note(
- "in this case, 'before' refers to the following order: \
- `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
- where `T0` is the first and `Tn` is the last",
- )
- .emit();
- }
- None => {
- struct_span_err!(
- self.tcx.sess,
- sp,
- E0210,
- "type parameter `{}` must be used as the type parameter for some \
- local type (e.g., `MyStruct<{}>`)",
- param_ty,
- param_ty
- ).span_label(sp, format!(
- "type parameter `{}` must be used as the type parameter for some \
- local type",
- param_ty,
- )).note("implementing a foreign trait is only possible if at \
- least one of the types for which it is implemented is local"
- ).note("only traits defined in the current crate can be \
- implemented for a type parameter"
- ).emit();
- }
- };
- return;
- }
+ Err(ErrorReported) => errors.push(impl_of_trait),
}
+ }
+ }
+ tcx.arena.alloc_slice(&errors)
+}
- // In addition to the above rules, we restrict impls of auto traits
- // so that they can only be implemented on nominal types, such as structs,
- // enums or foreign types. To see why this restriction exists, consider the
- // following example (#22978). Imagine that crate A defines an auto trait
- // `Foo` and a fn that operates on pairs of types:
- //
- // ```
- // // Crate A
- // auto trait Foo { }
- // fn two_foos<A:Foo,B:Foo>(..) {
- // one_foo::<(A,B)>(..)
- // }
- // fn one_foo<T:Foo>(..) { .. }
- // ```
- //
- // This type-checks fine; in particular the fn
- // `two_foos` is able to conclude that `(A,B):Foo`
- // because `A:Foo` and `B:Foo`.
- //
- // Now imagine that crate B comes along and does the following:
- //
- // ```
- // struct A { }
- // struct B { }
- // impl Foo for A { }
- // impl Foo for B { }
- // impl !Send for (A, B) { }
- // ```
- //
- // This final impl is legal according to the orphan
- // rules, but it invalidates the reasoning from
- // `two_foos` above.
- debug!(
- "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
- trait_ref,
- trait_def_id,
- self.tcx.trait_is_auto(trait_def_id)
- );
- if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
- let self_ty = trait_ref.self_ty();
- let opt_self_def_id = match *self_ty.kind() {
- ty::Adt(self_def, _) => Some(self_def.did),
- ty::Foreign(did) => Some(did),
- _ => None,
- };
+#[instrument(skip(tcx), level = "debug")]
+fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorReported> {
+ let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
+ let trait_def_id = trait_ref.def_id;
- let msg = match opt_self_def_id {
- // We only want to permit nominal types, but not *all* nominal types.
- // They must be local to the current crate, so that people
- // can't do `unsafe impl Send for Rc<SomethingLocal>` or
- // `impl !Send for Box<SomethingLocalAndSend>`.
- Some(self_def_id) => {
- if self_def_id.is_local() {
- None
- } else {
- Some((
- format!(
- "cross-crate traits with a default impl, like `{}`, \
- can only be implemented for a struct/enum type \
- defined in the current crate",
- self.tcx.def_path_str(trait_def_id)
- ),
- "can't implement cross-crate trait for type in another crate",
- ))
- }
- }
- _ => Some((
+ let item = tcx.hir().item(hir::ItemId { def_id });
+ let impl_ = match item.kind {
+ hir::ItemKind::Impl(ref impl_) => impl_,
+ _ => bug!("{:?} is not an impl: {:?}", def_id, item),
+ };
+ let sp = tcx.sess.source_map().guess_head_span(item.span);
+ let tr = impl_.of_trait.as_ref().unwrap();
+ match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+ Ok(()) => {}
+ Err(err) => emit_orphan_check_error(
+ tcx,
+ sp,
+ tr.path.span,
+ impl_.self_ty.span,
+ &impl_.generics,
+ err,
+ )?,
+ }
+
+ // In addition to the above rules, we restrict impls of auto traits
+ // so that they can only be implemented on nominal types, such as structs,
+ // enums or foreign types. To see why this restriction exists, consider the
+ // following example (#22978). Imagine that crate A defines an auto trait
+ // `Foo` and a fn that operates on pairs of types:
+ //
+ // ```
+ // // Crate A
+ // auto trait Foo { }
+ // fn two_foos<A:Foo,B:Foo>(..) {
+ // one_foo::<(A,B)>(..)
+ // }
+ // fn one_foo<T:Foo>(..) { .. }
+ // ```
+ //
+ // This type-checks fine; in particular the fn
+ // `two_foos` is able to conclude that `(A,B):Foo`
+ // because `A:Foo` and `B:Foo`.
+ //
+ // Now imagine that crate B comes along and does the following:
+ //
+ // ```
+ // struct A { }
+ // struct B { }
+ // impl Foo for A { }
+ // impl Foo for B { }
+ // impl !Send for (A, B) { }
+ // ```
+ //
+ // This final impl is legal according to the orphan
+ // rules, but it invalidates the reasoning from
+ // `two_foos` above.
+ debug!(
+ "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
+ trait_ref,
+ trait_def_id,
+ tcx.trait_is_auto(trait_def_id)
+ );
+
+ if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
+ let self_ty = trait_ref.self_ty();
+ let opt_self_def_id = match *self_ty.kind() {
+ ty::Adt(self_def, _) => Some(self_def.did),
+ ty::Foreign(did) => Some(did),
+ _ => None,
+ };
+
+ let msg = match opt_self_def_id {
+ // We only want to permit nominal types, but not *all* nominal types.
+ // They must be local to the current crate, so that people
+ // can't do `unsafe impl Send for Rc<SomethingLocal>` or
+ // `impl !Send for Box<SomethingLocalAndSend>`.
+ Some(self_def_id) => {
+ if self_def_id.is_local() {
+ None
+ } else {
+ Some((
format!(
- "cross-crate traits with a default impl, like `{}`, can \
- only be implemented for a struct/enum type, not `{}`",
- self.tcx.def_path_str(trait_def_id),
- self_ty
+ "cross-crate traits with a default impl, like `{}`, \
+ can only be implemented for a struct/enum type \
+ defined in the current crate",
+ tcx.def_path_str(trait_def_id)
),
- "can't implement cross-crate trait with a default impl for \
- non-struct/enum type",
- )),
- };
+ "can't implement cross-crate trait for type in another crate",
+ ))
+ }
+ }
+ _ => Some((
+ format!(
+ "cross-crate traits with a default impl, like `{}`, can \
+ only be implemented for a struct/enum type, not `{}`",
+ tcx.def_path_str(trait_def_id),
+ self_ty
+ ),
+ "can't implement cross-crate trait with a default impl for \
+ non-struct/enum type",
+ )),
+ };
- if let Some((msg, label)) = msg {
- struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
- .span_label(sp, label)
- .emit();
- return;
+ if let Some((msg, label)) = msg {
+ struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
+ return Err(ErrorReported);
+ }
+ }
+
+ if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
+ tcx.sess
+ .struct_span_err(sp, "cannot implement trait on type alias impl trait")
+ .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
+ .emit();
+ return Err(ErrorReported);
+ }
+
+ Ok(())
+}
+
+fn emit_orphan_check_error(
+ tcx: TyCtxt<'tcx>,
+ sp: Span,
+ trait_span: Span,
+ self_ty_span: Span,
+ generics: &hir::Generics<'tcx>,
+ err: traits::OrphanCheckErr<'tcx>,
+) -> Result<!, ErrorReported> {
+ match err {
+ traits::OrphanCheckErr::NonLocalInputType(tys) => {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ sp,
+ E0117,
+ "only traits defined in the current crate can be implemented for \
+ arbitrary types"
+ );
+ err.span_label(sp, "impl doesn't use only types from inside the current crate");
+ for (ty, is_target_ty) in &tys {
+ let mut ty = *ty;
+ tcx.infer_ctxt().enter(|infcx| {
+ // Remove the lifetimes unnecessary for this error.
+ ty = infcx.freshen(ty);
+ });
+ ty = match ty.kind() {
+ // Remove the type arguments from the output, as they are not relevant.
+ // You can think of this as the reverse of `resolve_vars_if_possible`.
+ // That way if we had `Vec<MyType>`, we will properly attribute the
+ // problem to `Vec<T>` and avoid confusing the user if they were to see
+ // `MyType` in the error.
+ ty::Adt(def, _) => tcx.mk_adt(def, ty::List::empty()),
+ _ => ty,
+ };
+ let this = "this".to_string();
+ let (ty, postfix) = match &ty.kind() {
+ ty::Slice(_) => (this, " because slices are always foreign"),
+ ty::Array(..) => (this, " because arrays are always foreign"),
+ ty::Tuple(..) => (this, " because tuples are always foreign"),
+ _ => (format!("`{}`", ty), ""),
+ };
+ let msg = format!("{} is not defined in the current crate{}", ty, postfix);
+ if *is_target_ty {
+ // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
+ err.span_label(self_ty_span, &msg);
+ } else {
+ // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
+ err.span_label(trait_span, &msg);
+ }
+ }
+ err.note("define and implement a trait or new type instead");
+ err.emit()
+ }
+ traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
+ let mut sp = sp;
+ for param in generics.params {
+ if param.name.ident().to_string() == param_ty.to_string() {
+ sp = param.span;
}
}
- if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
- self.tcx
- .sess
- .struct_span_err(sp, "cannot implement trait on type alias impl trait")
- .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here")
- .emit();
+ match local_type {
+ Some(local_type) => struct_span_err!(
+ tcx.sess,
+ sp,
+ E0210,
+ "type parameter `{}` must be covered by another type \
+ when it appears before the first local type (`{}`)",
+ param_ty,
+ local_type
+ )
+ .span_label(
+ sp,
+ format!(
+ "type parameter `{}` must be covered by another type \
+ when it appears before the first local type (`{}`)",
+ param_ty, local_type
+ ),
+ )
+ .note(
+ "implementing a foreign trait is only possible if at \
+ least one of the types for which it is implemented is local, \
+ and no uncovered type parameters appear before that first \
+ local type",
+ )
+ .note(
+ "in this case, 'before' refers to the following order: \
+ `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
+ where `T0` is the first and `Tn` is the last",
+ )
+ .emit(),
+ None => struct_span_err!(
+ tcx.sess,
+ sp,
+ E0210,
+ "type parameter `{}` must be used as the type parameter for some \
+ local type (e.g., `MyStruct<{}>`)",
+ param_ty,
+ param_ty
+ )
+ .span_label(
+ sp,
+ format!(
+ "type parameter `{}` must be used as the type parameter for some \
+ local type",
+ param_ty,
+ ),
+ )
+ .note(
+ "implementing a foreign trait is only possible if at \
+ least one of the types for which it is implemented is local",
+ )
+ .note(
+ "only traits defined in the current crate can be \
+ implemented for a type parameter",
+ )
+ .emit(),
}
}
}
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-
- fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
+ Err(ErrorReported)
}
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index df7f2ae..b9db8a6 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -28,7 +28,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind, Res};
+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::weak_lang_items;
@@ -668,6 +668,7 @@
})
.flat_map(|b| predicates_from_bound(self, ty, b));
+ let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
let from_where_clauses = ast_generics
.where_clause
.predicates
@@ -677,7 +678,7 @@
_ => None,
})
.flat_map(|bp| {
- let bt = if is_param(self.tcx, bp.bounded_ty, param_id) {
+ let bt = if bp.is_param_bound(param_def_id) {
Some(ty)
} else if !only_self_bounds.0 {
Some(self.to_ty(bp.bounded_ty))
@@ -714,23 +715,6 @@
}
}
-/// Tests whether this is the AST for a reference to the type
-/// parameter with ID `param_id`. We use this so as to avoid running
-/// `ast_ty_to_ty`, because we want to avoid triggering an all-out
-/// conversion of the type to avoid inducing unnecessary cycles.
-fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool {
- if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind {
- match path.res {
- Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => {
- def_id == tcx.hir().local_def_id(param_id).to_def_id()
- }
- _ => false,
- }
- } else {
- false
- }
-}
-
fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir().item(item_id);
debug!("convert: item {} with id {}", it.ident, it.hir_id());
@@ -1494,13 +1478,15 @@
{
Some(parent_def_id.to_def_id())
}
-
+ Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
_ => None,
}
}
}
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
- Some(tcx.closure_base_def_id(def_id))
+ Some(tcx.typeck_root_def_id(def_id))
}
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
@@ -1557,7 +1543,7 @@
kind: ty::GenericParamDefKind::Type {
has_default: false,
object_lifetime_default: rl::Set1::Empty,
- synthetic: None,
+ synthetic: false,
},
});
@@ -1687,11 +1673,29 @@
kind: ty::GenericParamDefKind::Type {
has_default: false,
object_lifetime_default: rl::Set1::Empty,
- synthetic: None,
+ synthetic: false,
},
}));
}
+ // provide junk type parameter defs for const blocks.
+ if let Node::AnonConst(_) = node {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+ params.push(ty::GenericParamDef {
+ index: type_start,
+ name: Symbol::intern("<const_ty>"),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: false,
+ },
+ });
+ }
+ }
+
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics {
@@ -1986,16 +1990,12 @@
// prove that the trait applies to the types that were
// used, and adding the predicate into this list ensures
// that this is done.
- let mut span = tcx.def_span(def_id);
- if tcx.sess.source_map().is_local_span(span) {
- // `guess_head_span` reads the actual source file from
- // disk to try to determine the 'head' snippet of the span.
- // Don't do this for a span that comes from a file outside
- // of our crate, since this would make our query output
- // (and overall crate metadata) dependent on the
- // *current* state of an external file.
- span = tcx.sess.source_map().guess_head_span(span);
- }
+ //
+ // We use a DUMMY_SP here as a way to signal trait bounds that come
+ // from the trait itself that *shouldn't* be shown as the source of
+ // an obligation and instead be skipped. Otherwise we'd use
+ // `tcx.def_span(def_id);`
+ let span = rustc_span::DUMMY_SP;
result.predicates =
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx),
@@ -2861,14 +2861,6 @@
} else if attr.has_name(sym::link_name) {
codegen_fn_attrs.link_name = attr.value_str();
} else if attr.has_name(sym::link_ordinal) {
- if link_ordinal_span.is_some() {
- tcx.sess
- .struct_span_err(
- attr.span,
- "multiple `link_ordinal` attributes on a single definition",
- )
- .emit();
- }
link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal;
@@ -2879,6 +2871,8 @@
for item in list.iter() {
if item.has_name(sym::address) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
+ } else if item.has_name(sym::cfi) {
+ 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::thread) {
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index cee3679..04a6825 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -292,7 +292,8 @@
// 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::STILL_FURTHER_SPECIALIZABLE
+ | ty::TypeFlags::HAS_ERROR;
assert!(!arg.has_type_flags(!allowed_flags));
}
substs
@@ -493,7 +494,8 @@
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id =>
{
- tcx.typeck(def_id).node_type(anon_const.hir_id)
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ substs.as_inline_const().ty()
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@@ -771,7 +773,7 @@
} else {
err.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ &format!("however, the inferred type `{}` cannot be named", ty),
);
}
}
@@ -795,7 +797,7 @@
} else {
diag.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ &format!("however, the inferred type `{}` cannot be named", ty),
);
}
}
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index 39bcf89..a49eda6 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -88,7 +88,8 @@
),
);
- if let Err(errors) = fulfill.select_all_or_error(&infcx) {
+ let errors = fulfill.select_all_or_error(&infcx);
+ if !errors.is_empty() {
tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
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 f4bb576..4fb422c 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -382,6 +382,7 @@
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: _,
}) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
@@ -413,6 +414,7 @@
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: _,
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
ty::PredicateKind::Trait(_)
| ty::PredicateKind::RegionOutlives(_)
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 971776c..0881cf0 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -58,17 +58,19 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(if_let_guard)]
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(nll)]
#![feature(try_blocks)]
#![feature(never_type)]
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
+#![feature(hash_drain_filter)]
#![recursion_limit = "256"]
#[macro_use]
@@ -155,10 +157,10 @@
}
}
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => true,
- Err(errors) => {
- infcx.report_fulfillment_errors(&errors, None, false);
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => true,
+ errors => {
+ infcx.report_fulfillment_errors(errors, None, false);
false
}
}
@@ -350,8 +352,9 @@
term_id,
cause,
);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
error = true;
}
});
diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
index 4ab5fe2..91727d5 100644
--- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
+++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
@@ -83,7 +83,8 @@
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations);
- if fulfill_cx.select_all_or_error(self).is_err() {
+ let errors = fulfill_cx.select_all_or_error(self);
+ if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index 8d3862f..a1c2945 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -300,7 +300,7 @@
hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Def(_, id), .. },
- )) if *id == def_id => true,
+ )) => *id == def_id,
_ => false,
})
})
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 1c8ac10..33c27ce 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -223,8 +223,8 @@
self.add_constraints_from_region(current, lt, variance_i)
}
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
- GenericArgKind::Const(_) => {
- // Consts impose no constraints.
+ GenericArgKind::Const(val) => {
+ self.add_constraints_from_const(current, val, variance_i)
}
}
}
@@ -263,7 +263,8 @@
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
}
- ty::Array(typ, _) => {
+ ty::Array(typ, len) => {
+ self.add_constraints_from_const(current, len, variance);
self.add_constraints_from_ty(current, typ, variance);
}
@@ -385,13 +386,32 @@
self.add_constraints_from_region(current, lt, variance_i)
}
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
- GenericArgKind::Const(_) => {
- // Consts impose no constraints.
+ GenericArgKind::Const(val) => {
+ self.add_constraints_from_const(current, val, variance)
}
}
}
}
+ /// Adds constraints appropriate for a const expression `val`
+ /// in a context with ambient variance `variance`
+ fn add_constraints_from_const(
+ &mut self,
+ current: &CurrentItem,
+ val: &ty::Const<'tcx>,
+ variance: VarianceTermPtr<'a>,
+ ) {
+ debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
+
+ match &val.val {
+ ty::ConstKind::Unevaluated(uv) => {
+ let substs = uv.substs(self.tcx());
+ self.add_constraints_from_invariant_substs(current, substs, variance);
+ }
+ _ => {}
+ }
+ }
+
/// Adds constraints appropriate for a function with signature
/// `sig` appearing in a context with ambient variance `variance`
fn add_constraints_from_sig(