Auto merge of #74710 - JohnTitor:rollup-bdz4oee, r=JohnTitor
Rollup of 12 pull requests Successful merges: - #74361 (Improve doc theme logo display) - #74504 (Add right border bar to Dark and Light theme) - #74572 (Internally unify rustc_deprecated and deprecated) - #74601 (Clean up E0724 explanation) - #74623 (polymorphize GlobalAlloc::Function) - #74665 (Don't ICE on unconstrained anonymous lifetimes inside associated types.) - #74666 (More BTreeMap test cases, some exposing undefined behaviour) - #74669 (Fix typo) - #74677 (Remove needless unsafety from BTreeMap::drain_filter) - #74680 (Add missing backticks in diagnostics note) - #74694 (Clean up E0727 explanation) - #74703 (Fix ICE while building MIR with type errors) Failed merges: r? @ghost
This commit is contained in:
commit
900869371e
@ -1672,19 +1672,12 @@ pub(super) fn peek(&self) -> Option<(&K, &V)> {
|
||||
edge.reborrow().next_kv().ok().map(|kv| kv.into_kv())
|
||||
}
|
||||
|
||||
unsafe fn next_kv(
|
||||
&mut self,
|
||||
) -> Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>> {
|
||||
let edge = self.cur_leaf_edge.as_ref()?;
|
||||
unsafe { ptr::read(edge).next_kv().ok() }
|
||||
}
|
||||
|
||||
/// Implementation of a typical `DrainFilter::next` method, given the predicate.
|
||||
pub(super) fn next<F>(&mut self, pred: &mut F) -> Option<(K, V)>
|
||||
where
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
{
|
||||
while let Some(mut kv) = unsafe { self.next_kv() } {
|
||||
while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() {
|
||||
let (k, v) = kv.kv_mut();
|
||||
if pred(k, v) {
|
||||
*self.length -= 1;
|
||||
|
@ -3,6 +3,7 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Debug;
|
||||
use std::iter::FromIterator;
|
||||
use std::mem;
|
||||
use std::ops::Bound::{self, Excluded, Included, Unbounded};
|
||||
use std::ops::RangeBounds;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
@ -25,6 +26,20 @@
|
||||
// It's not the minimum size: removing an element from such a tree does not always reduce height.
|
||||
const MIN_INSERTS_HEIGHT_2: usize = NODE_CAPACITY + (NODE_CAPACITY + 1) * NODE_CAPACITY + 1;
|
||||
|
||||
// Gather all references from a mutable iterator and make sure Miri notices if
|
||||
// using them is dangerous.
|
||||
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
|
||||
// Gather all those references.
|
||||
let mut refs: Vec<&mut T> = iter.collect();
|
||||
// Use them all. Twice, to be sure we got all interleavings.
|
||||
for r in refs.iter_mut() {
|
||||
mem::swap(dummy, r);
|
||||
}
|
||||
for r in refs {
|
||||
mem::swap(dummy, r);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_large() {
|
||||
let mut map = BTreeMap::new();
|
||||
@ -268,7 +283,14 @@ fn test_iter_mut_mutation() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
|
||||
fn test_values_mut() {
|
||||
let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect();
|
||||
test_all_refs(&mut 13, a.values_mut());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_values_mut_mutation() {
|
||||
let mut a = BTreeMap::new();
|
||||
a.insert(1, String::from("hello"));
|
||||
a.insert(2, String::from("goodbye"));
|
||||
@ -281,6 +303,36 @@ fn test_values_mut() {
|
||||
assert_eq!(values, [String::from("hello!"), String::from("goodbye!")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
|
||||
fn test_iter_entering_root_twice() {
|
||||
let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect();
|
||||
let mut it = map.iter_mut();
|
||||
let front = it.next().unwrap();
|
||||
let back = it.next_back().unwrap();
|
||||
assert_eq!(front, (&0, &mut 0));
|
||||
assert_eq!(back, (&1, &mut 1));
|
||||
*front.1 = 24;
|
||||
*back.1 = 42;
|
||||
assert_eq!(front, (&0, &mut 24));
|
||||
assert_eq!(back, (&1, &mut 42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
|
||||
fn test_iter_descending_to_same_node_twice() {
|
||||
let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect();
|
||||
let mut it = map.iter_mut();
|
||||
// Descend into first child.
|
||||
let front = it.next().unwrap();
|
||||
// Descend into first child again, after running through second child.
|
||||
while it.next_back().is_some() {}
|
||||
// Check immutable access.
|
||||
assert_eq!(front, (&0, &mut 0));
|
||||
// Perform mutable access.
|
||||
*front.1 = 42;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iter_mixed() {
|
||||
// Miri is too slow
|
||||
@ -835,10 +887,8 @@ fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(0, D);
|
||||
map.insert(4, D);
|
||||
map.insert(8, D);
|
||||
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
|
||||
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
|
||||
|
||||
catch_unwind(move || {
|
||||
drop(map.drain_filter(|i, _| {
|
||||
@ -846,7 +896,7 @@ fn drop(&mut self) {
|
||||
true
|
||||
}))
|
||||
})
|
||||
.ok();
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
|
||||
@ -864,10 +914,8 @@ fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(0, D);
|
||||
map.insert(4, D);
|
||||
map.insert(8, D);
|
||||
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
|
||||
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
|
||||
|
||||
catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(map.drain_filter(|i, _| {
|
||||
@ -878,7 +926,45 @@ fn drop(&mut self) {
|
||||
}
|
||||
}))
|
||||
}))
|
||||
.ok();
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
|
||||
assert_eq!(map.len(), 2);
|
||||
assert_eq!(map.first_entry().unwrap().key(), &4);
|
||||
assert_eq!(map.last_entry().unwrap().key(), &8);
|
||||
}
|
||||
|
||||
// Same as above, but attempt to use the iterator again after the panic in the predicate
|
||||
#[test]
|
||||
fn pred_panic_reuse() {
|
||||
static PREDS: AtomicUsize = AtomicUsize::new(0);
|
||||
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
struct D;
|
||||
impl Drop for D {
|
||||
fn drop(&mut self) {
|
||||
DROPS.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
|
||||
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
|
||||
|
||||
{
|
||||
let mut it = map.drain_filter(|i, _| {
|
||||
PREDS.fetch_add(1usize << i, Ordering::SeqCst);
|
||||
match i {
|
||||
0 => true,
|
||||
_ => panic!(),
|
||||
}
|
||||
});
|
||||
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
||||
// Iterator behaviour after a panic is explicitly unspecified,
|
||||
// so this is just the current implementation:
|
||||
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
||||
assert!(matches!(result, Ok(None)));
|
||||
}
|
||||
|
||||
assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
|
||||
@ -1283,6 +1369,34 @@ fn test_split_off_empty_left() {
|
||||
assert!(right.into_iter().eq(data));
|
||||
}
|
||||
|
||||
// In a tree with 3 levels, if all but a part of the first leaf node is split off,
|
||||
// make sure fix_top eliminates both top levels.
|
||||
#[test]
|
||||
fn test_split_off_tiny_left_height_2() {
|
||||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||
let mut left: BTreeMap<_, _> = pairs.clone().collect();
|
||||
let right = left.split_off(&1);
|
||||
assert_eq!(left.len(), 1);
|
||||
assert_eq!(right.len(), MIN_INSERTS_HEIGHT_2 - 1);
|
||||
assert_eq!(*left.first_key_value().unwrap().0, 0);
|
||||
assert_eq!(*right.first_key_value().unwrap().0, 1);
|
||||
}
|
||||
|
||||
// In a tree with 3 levels, if only part of the last leaf node is split off,
|
||||
// make sure fix_top eliminates both top levels.
|
||||
#[test]
|
||||
fn test_split_off_tiny_right_height_2() {
|
||||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||
let last = MIN_INSERTS_HEIGHT_2 - 1;
|
||||
let mut left: BTreeMap<_, _> = pairs.clone().collect();
|
||||
assert_eq!(*left.last_key_value().unwrap().0, last);
|
||||
let right = left.split_off(&last);
|
||||
assert_eq!(left.len(), MIN_INSERTS_HEIGHT_2 - 1);
|
||||
assert_eq!(right.len(), 1);
|
||||
assert_eq!(*left.last_key_value().unwrap().0, last - 1);
|
||||
assert_eq!(*right.last_key_value().unwrap().0, last);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_off_large_random_sorted() {
|
||||
// Miri is too slow
|
||||
@ -1319,7 +1433,7 @@ fn drop(&mut self) {
|
||||
map.insert("d", D);
|
||||
map.insert("e", D);
|
||||
|
||||
catch_unwind(move || drop(map.into_iter())).ok();
|
||||
catch_unwind(move || drop(map.into_iter())).unwrap_err();
|
||||
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
|
||||
}
|
||||
@ -1343,7 +1457,7 @@ fn drop(&mut self) {
|
||||
DROPS.store(0, Ordering::SeqCst);
|
||||
PANIC_POINT.store(panic_point, Ordering::SeqCst);
|
||||
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
|
||||
catch_unwind(move || drop(map.into_iter())).ok();
|
||||
catch_unwind(move || drop(map.into_iter())).unwrap_err();
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), size);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
/// * `steps_between(&a, &b) == Some(n)` only if `a <= b`
|
||||
/// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b`
|
||||
/// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
|
||||
/// this is the case wheen it would require more than `usize::MAX` steps to get to `b`
|
||||
/// this is the case when it would require more than `usize::MAX` steps to get to `b`
|
||||
/// * `steps_between(&a, &b) == None` if `a > b`
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize>;
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
Args = "()",
|
||||
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"
|
||||
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
|
||||
),
|
||||
message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
|
||||
label = "expected an `Fn<{Args}>` closure, found `{Self}`"
|
||||
@ -141,7 +141,7 @@ pub trait Fn<Args>: FnMut<Args> {
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
Args = "()",
|
||||
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"
|
||||
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
|
||||
),
|
||||
message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
|
||||
label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
|
||||
@ -215,7 +215,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
Args = "()",
|
||||
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"
|
||||
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
|
||||
),
|
||||
message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
|
||||
label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
|
||||
|
@ -124,13 +124,11 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
|
||||
///
|
||||
/// - `#[stable]`
|
||||
/// - `#[unstable]`
|
||||
/// - `#[rustc_deprecated]`
|
||||
#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct Stability {
|
||||
pub level: StabilityLevel,
|
||||
pub feature: Symbol,
|
||||
pub rustc_depr: Option<RustcDeprecation>,
|
||||
}
|
||||
|
||||
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
|
||||
@ -163,15 +161,6 @@ pub fn is_stable(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct RustcDeprecation {
|
||||
pub since: Symbol,
|
||||
pub reason: Symbol,
|
||||
/// A text snippet used to completely replace any use of the deprecated item in an expression.
|
||||
pub suggestion: Option<Symbol>,
|
||||
}
|
||||
|
||||
/// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
|
||||
/// This will not perform any "sanity checks" on the form of the attributes.
|
||||
pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
|
||||
@ -205,7 +194,6 @@ fn find_stability_generic<'a, I>(
|
||||
use StabilityLevel::*;
|
||||
|
||||
let mut stab: Option<Stability> = None;
|
||||
let mut rustc_depr: Option<RustcDeprecation> = None;
|
||||
let mut const_stab: Option<ConstStability> = None;
|
||||
let mut promotable = false;
|
||||
let mut allow_const_fn_ptr = false;
|
||||
@ -213,7 +201,6 @@ fn find_stability_generic<'a, I>(
|
||||
|
||||
'outer: for attr in attrs_iter {
|
||||
if ![
|
||||
sym::rustc_deprecated,
|
||||
sym::rustc_const_unstable,
|
||||
sym::rustc_const_stable,
|
||||
sym::unstable,
|
||||
@ -258,76 +245,8 @@ fn find_stability_generic<'a, I>(
|
||||
}
|
||||
};
|
||||
|
||||
macro_rules! get_meta {
|
||||
($($name:ident),+) => {
|
||||
$(
|
||||
let mut $name = None;
|
||||
)+
|
||||
for meta in metas {
|
||||
if let Some(mi) = meta.meta_item() {
|
||||
match mi.name_or_empty() {
|
||||
$(
|
||||
sym::$name => if !get(mi, &mut $name) { continue 'outer },
|
||||
)+
|
||||
_ => {
|
||||
let expected = &[ $( stringify!($name) ),+ ];
|
||||
handle_errors(
|
||||
sess,
|
||||
mi.span,
|
||||
AttrError::UnknownMetaItem(
|
||||
pprust::path_to_string(&mi.path),
|
||||
expected,
|
||||
),
|
||||
);
|
||||
continue 'outer
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span(),
|
||||
AttrError::UnsupportedLiteral(
|
||||
"unsupported literal",
|
||||
false,
|
||||
),
|
||||
);
|
||||
continue 'outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let meta_name = meta.name_or_empty();
|
||||
match meta_name {
|
||||
sym::rustc_deprecated => {
|
||||
if rustc_depr.is_some() {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item_sp,
|
||||
E0540,
|
||||
"multiple rustc_deprecated attributes"
|
||||
)
|
||||
.emit();
|
||||
continue 'outer;
|
||||
}
|
||||
|
||||
get_meta!(since, reason, suggestion);
|
||||
|
||||
match (since, reason) {
|
||||
(Some(since), Some(reason)) => {
|
||||
rustc_depr = Some(RustcDeprecation { since, reason, suggestion })
|
||||
}
|
||||
(None, _) => {
|
||||
handle_errors(sess, attr.span, AttrError::MissingSince);
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'")
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
sym::rustc_const_unstable | sym::unstable => {
|
||||
if meta_name == sym::unstable && stab.is_some() {
|
||||
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||
@ -429,7 +348,7 @@ macro_rules! get_meta {
|
||||
(Some(feature), reason, Some(_)) => {
|
||||
let level = Unstable { reason, issue: issue_num, is_soft };
|
||||
if sym::unstable == meta_name {
|
||||
stab = Some(Stability { level, feature, rustc_depr: None });
|
||||
stab = Some(Stability { level, feature });
|
||||
} else {
|
||||
const_stab = Some(ConstStability {
|
||||
level,
|
||||
@ -501,7 +420,7 @@ macro_rules! get_meta {
|
||||
(Some(feature), Some(since)) => {
|
||||
let level = Stable { since };
|
||||
if sym::stable == meta_name {
|
||||
stab = Some(Stability { level, feature, rustc_depr: None });
|
||||
stab = Some(Stability { level, feature });
|
||||
} else {
|
||||
const_stab = Some(ConstStability {
|
||||
level,
|
||||
@ -526,22 +445,6 @@ macro_rules! get_meta {
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the deprecation info into the stability info
|
||||
if let Some(rustc_depr) = rustc_depr {
|
||||
if let Some(ref mut stab) = stab {
|
||||
stab.rustc_depr = Some(rustc_depr);
|
||||
} else {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item_sp,
|
||||
E0549,
|
||||
"rustc_deprecated attribute must be paired with \
|
||||
either stable or unstable attribute"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the const-unstable info into the stability info
|
||||
if promotable || allow_const_fn_ptr {
|
||||
if let Some(ref mut stab) = const_stab {
|
||||
@ -714,7 +617,16 @@ pub fn eval_condition(
|
||||
#[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)]
|
||||
pub struct Deprecation {
|
||||
pub since: Option<Symbol>,
|
||||
/// The note to issue a reason.
|
||||
pub note: Option<Symbol>,
|
||||
/// A text snippet used to completely replace any use of the deprecated item in an expression.
|
||||
///
|
||||
/// This is currently unstable.
|
||||
pub suggestion: Option<Symbol>,
|
||||
|
||||
/// Whether to treat the since attribute as being a Rust version identifier
|
||||
/// (rather than an opaque string).
|
||||
pub is_since_rustc_version: bool,
|
||||
}
|
||||
|
||||
/// Finds the deprecation attribute. `None` if none exists.
|
||||
@ -738,7 +650,7 @@ fn find_deprecation_generic<'a, I>(
|
||||
let diagnostic = &sess.span_diagnostic;
|
||||
|
||||
'outer: for attr in attrs_iter {
|
||||
if !attr.check_name(sym::deprecated) {
|
||||
if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -751,11 +663,12 @@ fn find_deprecation_generic<'a, I>(
|
||||
Some(meta) => meta,
|
||||
None => continue,
|
||||
};
|
||||
depr = match &meta.kind {
|
||||
MetaItemKind::Word => Some(Deprecation { since: None, note: None }),
|
||||
MetaItemKind::NameValue(..) => {
|
||||
meta.value_str().map(|note| Deprecation { since: None, note: Some(note) })
|
||||
}
|
||||
let mut since = None;
|
||||
let mut note = None;
|
||||
let mut suggestion = None;
|
||||
match &meta.kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::NameValue(..) => note = meta.value_str(),
|
||||
MetaItemKind::List(list) => {
|
||||
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||
if item.is_some() {
|
||||
@ -789,8 +702,6 @@ fn find_deprecation_generic<'a, I>(
|
||||
}
|
||||
};
|
||||
|
||||
let mut since = None;
|
||||
let mut note = None;
|
||||
for meta in list {
|
||||
match meta {
|
||||
NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
|
||||
@ -799,18 +710,32 @@ fn find_deprecation_generic<'a, I>(
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
sym::note => {
|
||||
sym::note if attr.check_name(sym::deprecated) => {
|
||||
if !get(mi, &mut note) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
sym::reason if attr.check_name(sym::rustc_deprecated) => {
|
||||
if !get(mi, &mut note) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
sym::suggestion if attr.check_name(sym::rustc_deprecated) => {
|
||||
if !get(mi, &mut suggestion) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span(),
|
||||
AttrError::UnknownMetaItem(
|
||||
pprust::path_to_string(&mi.path),
|
||||
&["since", "note"],
|
||||
if attr.check_name(sym::deprecated) {
|
||||
&["since", "note"]
|
||||
} else {
|
||||
&["since", "reason", "suggestion"]
|
||||
},
|
||||
),
|
||||
);
|
||||
continue 'outer;
|
||||
@ -829,10 +754,29 @@ fn find_deprecation_generic<'a, I>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Deprecation { since, note })
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if suggestion.is_some() && attr.check_name(sym::deprecated) {
|
||||
unreachable!("only allowed on rustc_deprecated")
|
||||
}
|
||||
|
||||
if attr.check_name(sym::rustc_deprecated) {
|
||||
if since.is_none() {
|
||||
handle_errors(sess, attr.span, AttrError::MissingSince);
|
||||
continue;
|
||||
}
|
||||
|
||||
if note.is_none() {
|
||||
struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mark_used(&attr);
|
||||
|
||||
let is_since_rustc_version = attr.check_name(sym::rustc_deprecated);
|
||||
depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version });
|
||||
}
|
||||
|
||||
depr
|
||||
|
@ -257,7 +257,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -
|
||||
(value, AddressSpace::DATA)
|
||||
}
|
||||
GlobalAlloc::Function(fn_instance) => (
|
||||
self.get_fn_addr(fn_instance),
|
||||
self.get_fn_addr(fn_instance.polymorphize(self.tcx)),
|
||||
self.data_layout().instruction_address_space,
|
||||
),
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
|
@ -589,7 +589,7 @@
|
||||
E0521, // borrowed data escapes outside of closure
|
||||
E0523,
|
||||
// E0526, // shuffle indices are not constant
|
||||
E0540, // multiple rustc_deprecated attributes
|
||||
// E0540, // multiple rustc_deprecated attributes
|
||||
E0542, // missing 'since'
|
||||
E0543, // missing 'reason'
|
||||
E0544, // multiple stability levels
|
||||
|
@ -1,4 +1,5 @@
|
||||
`#[ffi_returns_twice]` was used on non-foreign function.
|
||||
`#[ffi_returns_twice]` was used on something other than a foreign function
|
||||
declaration.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
A `yield` clause was used in an `async` context.
|
||||
|
||||
Example of erroneous code:
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0727,edition2018
|
||||
#![feature(generators)]
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use rustc_ast::ast::CRATE_NODE_ID;
|
||||
use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability};
|
||||
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_feature::GateIssue;
|
||||
@ -130,14 +130,26 @@ pub fn report_unstable(
|
||||
|
||||
/// Checks whether an item marked with `deprecated(since="X")` is currently
|
||||
/// deprecated (i.e., whether X is not greater than the current rustc version).
|
||||
pub fn deprecation_in_effect(since: &str) -> bool {
|
||||
pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool {
|
||||
let since = if let Some(since) = since {
|
||||
if is_since_rustc_version {
|
||||
since
|
||||
} else {
|
||||
// We assume that the deprecation is in effect if it's not a
|
||||
// rustc version.
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// If since attribute is not set, then we're definitely in effect.
|
||||
return true;
|
||||
};
|
||||
fn parse_version(ver: &str) -> Vec<u32> {
|
||||
// We ignore non-integer components of the version (e.g., "nightly").
|
||||
ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
|
||||
}
|
||||
|
||||
if let Some(rustc) = option_env!("CFG_RELEASE") {
|
||||
let since: Vec<u32> = parse_version(since);
|
||||
let since: Vec<u32> = parse_version(&since);
|
||||
let rustc: Vec<u32> = parse_version(rustc);
|
||||
// We simply treat invalid `since` attributes as relating to a previous
|
||||
// Rust version, thus always displaying the warning.
|
||||
@ -167,31 +179,27 @@ pub fn deprecation_suggestion(
|
||||
}
|
||||
}
|
||||
|
||||
fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
|
||||
match reason {
|
||||
Some(reason) => format!("{}: {}", message, reason),
|
||||
None => message,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
|
||||
let message = format!("use of deprecated item '{}'", path);
|
||||
(deprecation_message_common(message, depr.note), DEPRECATED)
|
||||
}
|
||||
|
||||
pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
|
||||
let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
|
||||
let (message, lint) = if deprecation_in_effect(
|
||||
depr.is_since_rustc_version,
|
||||
depr.since.map(Symbol::as_str).as_deref(),
|
||||
) {
|
||||
(format!("use of deprecated item '{}'", path), DEPRECATED)
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
"use of item '{}' that will be deprecated in future version {}",
|
||||
path, depr.since
|
||||
path,
|
||||
depr.since.unwrap()
|
||||
),
|
||||
DEPRECATED_IN_FUTURE,
|
||||
)
|
||||
};
|
||||
(deprecation_message_common(message, Some(depr.reason)), lint)
|
||||
let message = match depr.note {
|
||||
Some(reason) => format!("{}: {}", message, reason),
|
||||
None => message,
|
||||
};
|
||||
(message, lint)
|
||||
}
|
||||
|
||||
pub fn early_report_deprecation(
|
||||
@ -289,10 +297,23 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
|
||||
.lookup_deprecation_entry(parent_def_id.to_def_id())
|
||||
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
|
||||
|
||||
if !skip {
|
||||
// #[deprecated] doesn't emit a notice if we're not on the
|
||||
// topmost deprecation. For example, if a struct is deprecated,
|
||||
// the use of a field won't be linted.
|
||||
//
|
||||
// #[rustc_deprecated] however wants to emit down the whole
|
||||
// hierarchy.
|
||||
if !skip || depr_entry.attr.is_since_rustc_version {
|
||||
let (message, lint) =
|
||||
deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
|
||||
late_report_deprecation(self, &message, None, lint, span, id);
|
||||
late_report_deprecation(
|
||||
self,
|
||||
&message,
|
||||
depr_entry.attr.suggestion,
|
||||
lint,
|
||||
span,
|
||||
id,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -310,16 +331,6 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
|
||||
def_id, span, stability
|
||||
);
|
||||
|
||||
if let Some(id) = id {
|
||||
if let Some(stability) = stability {
|
||||
if let Some(depr) = &stability.rustc_depr {
|
||||
let (message, lint) =
|
||||
rustc_deprecation_message(depr, &self.def_path_str(def_id));
|
||||
late_report_deprecation(self, &message, depr.suggestion, lint, span, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only the cross-crate scenario matters when checking unstable APIs
|
||||
let cross_crate = !def_id.is_local();
|
||||
if !cross_crate {
|
||||
|
@ -509,11 +509,6 @@ fn normalize_range_pattern_ends(
|
||||
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
|
||||
let mut ty = self.typeck_results.node_type(pat.hir_id);
|
||||
|
||||
if let ty::Error(_) = ty.kind {
|
||||
// Avoid ICEs (e.g., #50577 and #50585).
|
||||
return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
|
||||
}
|
||||
|
||||
let kind = match pat.kind {
|
||||
hir::PatKind::Wild => PatKind::Wild,
|
||||
|
||||
|
@ -59,20 +59,50 @@ fn annotate<F>(
|
||||
) where
|
||||
F: FnOnce(&mut Self),
|
||||
{
|
||||
debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
|
||||
let mut did_error = false;
|
||||
if !self.tcx.features().staged_api {
|
||||
self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children);
|
||||
return;
|
||||
did_error = self.forbid_staged_api_attrs(hir_id, attrs);
|
||||
}
|
||||
|
||||
// This crate explicitly wants staged API.
|
||||
let depr = if did_error {
|
||||
None
|
||||
} else {
|
||||
attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
|
||||
};
|
||||
let mut is_deprecated = false;
|
||||
if let Some(depr) = &depr {
|
||||
is_deprecated = true;
|
||||
|
||||
debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
|
||||
if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
|
||||
self.tcx.sess.span_err(
|
||||
item_sp,
|
||||
"`#[deprecated]` cannot be used in staged API; \
|
||||
use `#[rustc_deprecated]` instead",
|
||||
if kind == AnnotationKind::Prohibited {
|
||||
self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
|
||||
}
|
||||
|
||||
// `Deprecation` is just two pointers, no need to intern it
|
||||
let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
|
||||
self.index.depr_map.insert(hir_id, depr_entry);
|
||||
} else if let Some(parent_depr) = self.parent_depr.clone() {
|
||||
is_deprecated = true;
|
||||
info!("tagging child {:?} as deprecated from parent", hir_id);
|
||||
self.index.depr_map.insert(hir_id, parent_depr);
|
||||
}
|
||||
|
||||
if self.tcx.features().staged_api {
|
||||
if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
|
||||
self.tcx.sess.span_err(
|
||||
item_sp,
|
||||
"`#[deprecated]` cannot be used in staged API; \
|
||||
use `#[rustc_deprecated]` instead",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.recurse_with_stability_attrs(
|
||||
depr.map(|d| DeprecationEntry::local(d, hir_id)),
|
||||
None,
|
||||
None,
|
||||
visit_children,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
|
||||
@ -92,33 +122,34 @@ fn annotate<F>(
|
||||
}
|
||||
}
|
||||
|
||||
let stab = stab.map(|mut stab| {
|
||||
if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) {
|
||||
if stab.is_none() {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
item_sp,
|
||||
E0549,
|
||||
"rustc_deprecated attribute must be paired with \
|
||||
either stable or unstable attribute"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let stab = stab.map(|stab| {
|
||||
// Error if prohibited, or can't inherit anything from a container.
|
||||
if kind == AnnotationKind::Prohibited
|
||||
|| (kind == AnnotationKind::Container
|
||||
&& stab.level.is_stable()
|
||||
&& stab.rustc_depr.is_none())
|
||||
|| (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
|
||||
{
|
||||
self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
|
||||
}
|
||||
|
||||
debug!("annotate: found {:?}", stab);
|
||||
// If parent is deprecated and we're not, inherit this by merging
|
||||
// deprecated_since and its reason.
|
||||
if let Some(parent_stab) = self.parent_stab {
|
||||
if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
|
||||
stab.rustc_depr = parent_stab.rustc_depr
|
||||
}
|
||||
}
|
||||
|
||||
let stab = self.tcx.intern_stability(stab);
|
||||
|
||||
// Check if deprecated_since < stable_since. If it is,
|
||||
// this is *almost surely* an accident.
|
||||
if let (
|
||||
&Some(attr::RustcDeprecation { since: dep_since, .. }),
|
||||
&attr::Stable { since: stab_since },
|
||||
) = (&stab.rustc_depr, &stab.level)
|
||||
if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
|
||||
(&depr.as_ref().and_then(|d| d.since), &stab.level)
|
||||
{
|
||||
// Explicit version of iter::order::lt to handle parse errors properly
|
||||
for (dep_v, stab_v) in
|
||||
@ -163,19 +194,29 @@ fn annotate<F>(
|
||||
}
|
||||
}
|
||||
|
||||
self.recurse_with_stability_attrs(stab, const_stab, visit_children);
|
||||
self.recurse_with_stability_attrs(
|
||||
depr.map(|d| DeprecationEntry::local(d, hir_id)),
|
||||
stab,
|
||||
const_stab,
|
||||
visit_children,
|
||||
);
|
||||
}
|
||||
|
||||
fn recurse_with_stability_attrs(
|
||||
&mut self,
|
||||
depr: Option<DeprecationEntry>,
|
||||
stab: Option<&'tcx Stability>,
|
||||
const_stab: Option<&'tcx ConstStability>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
// These will be `Some` if this item changes the corresponding stability attribute.
|
||||
let mut replaced_parent_depr = None;
|
||||
let mut replaced_parent_stab = None;
|
||||
let mut replaced_parent_const_stab = None;
|
||||
|
||||
if let Some(depr) = depr {
|
||||
replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
|
||||
}
|
||||
if let Some(stab) = stab {
|
||||
replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
|
||||
}
|
||||
@ -186,6 +227,9 @@ fn recurse_with_stability_attrs(
|
||||
|
||||
f(self);
|
||||
|
||||
if let Some(orig_parent_depr) = replaced_parent_depr {
|
||||
self.parent_depr = orig_parent_depr;
|
||||
}
|
||||
if let Some(orig_parent_stab) = replaced_parent_stab {
|
||||
self.parent_stab = orig_parent_stab;
|
||||
}
|
||||
@ -194,14 +238,8 @@ fn recurse_with_stability_attrs(
|
||||
}
|
||||
}
|
||||
|
||||
fn forbid_staged_api_attrs(
|
||||
&mut self,
|
||||
hir_id: HirId,
|
||||
attrs: &[Attribute],
|
||||
item_sp: Span,
|
||||
kind: AnnotationKind,
|
||||
visit_children: impl FnOnce(&mut Self),
|
||||
) {
|
||||
// returns true if an error occurred, used to suppress some spurious errors
|
||||
fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
|
||||
// Emit errors for non-staged-api crates.
|
||||
let unstable_attrs = [
|
||||
sym::unstable,
|
||||
@ -210,6 +248,7 @@ fn forbid_staged_api_attrs(
|
||||
sym::rustc_const_unstable,
|
||||
sym::rustc_const_stable,
|
||||
];
|
||||
let mut has_error = false;
|
||||
for attr in attrs {
|
||||
let name = attr.name_or_empty();
|
||||
if unstable_attrs.contains(&name) {
|
||||
@ -221,6 +260,7 @@ fn forbid_staged_api_attrs(
|
||||
"stability attributes may not be used outside of the standard library",
|
||||
)
|
||||
.emit();
|
||||
has_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,24 +272,7 @@ fn forbid_staged_api_attrs(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(depr) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
|
||||
if kind == AnnotationKind::Prohibited {
|
||||
self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
|
||||
}
|
||||
|
||||
// `Deprecation` is just two pointers, no need to intern it
|
||||
let depr_entry = DeprecationEntry::local(depr, hir_id);
|
||||
self.index.depr_map.insert(hir_id, depr_entry.clone());
|
||||
|
||||
let orig_parent_depr = replace(&mut self.parent_depr, Some(depr_entry));
|
||||
visit_children(self);
|
||||
self.parent_depr = orig_parent_depr;
|
||||
} else if let Some(parent_depr) = self.parent_depr.clone() {
|
||||
self.index.depr_map.insert(hir_id, parent_depr);
|
||||
visit_children(self);
|
||||
} else {
|
||||
visit_children(self);
|
||||
}
|
||||
has_error
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,7 +477,6 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
|
||||
is_soft: false,
|
||||
},
|
||||
feature: sym::rustc_private,
|
||||
rustc_depr: None,
|
||||
});
|
||||
annotator.parent_stab = Some(stability);
|
||||
}
|
||||
|
@ -1017,22 +1017,17 @@ fn check_stability_and_deprecation(
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(depr) = &stability.rustc_depr {
|
||||
let path = pprust::path_to_string(path);
|
||||
let (message, lint) = stability::rustc_deprecation_message(depr, &path);
|
||||
stability::early_report_deprecation(
|
||||
&mut self.lint_buffer,
|
||||
&message,
|
||||
depr.suggestion,
|
||||
lint,
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(depr) = &ext.deprecation {
|
||||
let path = pprust::path_to_string(&path);
|
||||
let (message, lint) = stability::deprecation_message(depr, &path);
|
||||
stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span);
|
||||
stability::early_report_deprecation(
|
||||
&mut self.lint_buffer,
|
||||
&message,
|
||||
depr.suggestion,
|
||||
lint,
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1485,28 +1485,33 @@ fn add_predicates_for_ast_type_binding(
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
binding.span,
|
||||
"anonymous bound region {:?} in binding but not trait ref",
|
||||
br
|
||||
);
|
||||
}
|
||||
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
|
||||
_ => "an anonymous lifetime".to_string(),
|
||||
};
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
struct_span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references lifetime `{}`, \
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name,
|
||||
br_name
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
|
||||
if let ty::BrAnon(_) = *br {
|
||||
// The only way for an anonymous lifetime to wind up
|
||||
// in the return type but **also** be unconstrained is
|
||||
// if it only appears in "associated types" in the
|
||||
// input. See #62200 for an example. In this case,
|
||||
// though we can easily give a hint that ought to be
|
||||
// relevant.
|
||||
err.note("lifetimes appearing in an associated type are not considered constrained");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2353,10 +2353,6 @@ fn clean(&self, _: &DocContext<'_>) -> Stability {
|
||||
attr::Stable { ref since } => since.to_string(),
|
||||
_ => String::new(),
|
||||
},
|
||||
deprecation: self.rustc_depr.as_ref().map(|d| Deprecation {
|
||||
note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
|
||||
since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
|
||||
}),
|
||||
unstable_reason: match self.level {
|
||||
attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
|
||||
_ => None,
|
||||
@ -2374,6 +2370,7 @@ fn clean(&self, _: &DocContext<'_>) -> Deprecation {
|
||||
Deprecation {
|
||||
since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
|
||||
note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
|
||||
is_since_rustc_version: self.is_since_rustc_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,8 @@ pub fn stability_class(&self) -> Option<String> {
|
||||
classes.push("unstable");
|
||||
}
|
||||
|
||||
if s.deprecation.is_some() {
|
||||
// FIXME: what about non-staged API items that are deprecated?
|
||||
if self.deprecation.is_some() {
|
||||
classes.push("deprecated");
|
||||
}
|
||||
|
||||
@ -216,14 +217,6 @@ pub fn type_(&self) -> ItemType {
|
||||
ItemType::from(self)
|
||||
}
|
||||
|
||||
/// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
|
||||
///
|
||||
/// If the item is not deprecated, returns `None`.
|
||||
pub fn deprecation(&self) -> Option<&Deprecation> {
|
||||
self.deprecation
|
||||
.as_ref()
|
||||
.or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
|
||||
}
|
||||
pub fn is_default(&self) -> bool {
|
||||
match self.inner {
|
||||
ItemEnum::MethodItem(ref meth) => {
|
||||
@ -1528,7 +1521,6 @@ pub struct Stability {
|
||||
pub level: stability::StabilityLevel,
|
||||
pub feature: Option<String>,
|
||||
pub since: String,
|
||||
pub deprecation: Option<Deprecation>,
|
||||
pub unstable_reason: Option<String>,
|
||||
pub issue: Option<NonZeroU32>,
|
||||
}
|
||||
@ -1537,6 +1529,7 @@ pub struct Stability {
|
||||
pub struct Deprecation {
|
||||
pub since: Option<String>,
|
||||
pub note: Option<String>,
|
||||
pub is_since_rustc_version: bool,
|
||||
}
|
||||
|
||||
/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
|
||||
|
@ -2216,16 +2216,10 @@ fn tag_html(class: &str, contents: &str) -> String {
|
||||
}
|
||||
|
||||
// The trailing space after each tag is to space it properly against the rest of the docs.
|
||||
if item.deprecation().is_some() {
|
||||
if let Some(depr) = &item.deprecation {
|
||||
let mut message = "Deprecated";
|
||||
if let Some(ref stab) = item.stability {
|
||||
if let Some(ref depr) = stab.deprecation {
|
||||
if let Some(ref since) = depr.since {
|
||||
if !stability::deprecation_in_effect(&since) {
|
||||
message = "Deprecation planned";
|
||||
}
|
||||
}
|
||||
}
|
||||
if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) {
|
||||
message = "Deprecation planned";
|
||||
}
|
||||
tags += &tag_html("deprecated", message);
|
||||
}
|
||||
@ -2254,23 +2248,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
|
||||
let mut stability = vec![];
|
||||
let error_codes = cx.shared.codes;
|
||||
|
||||
if let Some(Deprecation { note, since }) = &item.deprecation() {
|
||||
if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation {
|
||||
// We display deprecation messages for #[deprecated] and #[rustc_deprecated]
|
||||
// but only display the future-deprecation messages for #[rustc_deprecated].
|
||||
let mut message = if let Some(since) = since {
|
||||
format!("Deprecated since {}", Escape(since))
|
||||
if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
|
||||
format!("Deprecating in {}", Escape(&since))
|
||||
} else {
|
||||
format!("Deprecated since {}", Escape(&since))
|
||||
}
|
||||
} else {
|
||||
String::from("Deprecated")
|
||||
};
|
||||
if let Some(ref stab) = item.stability {
|
||||
if let Some(ref depr) = stab.deprecation {
|
||||
if let Some(ref since) = depr.since {
|
||||
if !stability::deprecation_in_effect(&since) {
|
||||
message = format!("Deprecating in {}", Escape(&since));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(note) = note {
|
||||
let mut ids = cx.id_map.borrow_mut();
|
||||
|
@ -62,6 +62,10 @@ pre {
|
||||
background-color: #14191f;
|
||||
}
|
||||
|
||||
.logo-container > img {
|
||||
filter: drop-shadow(0 0 5px #fff);
|
||||
}
|
||||
|
||||
/* Improve the scrollbar display on firefox */
|
||||
* {
|
||||
scrollbar-color: #5c6773 transparent;
|
||||
@ -322,7 +326,7 @@ a.test-arrow:hover {
|
||||
|
||||
:target > code, :target > .in-band {
|
||||
background: rgba(255, 236, 164, 0.06);
|
||||
border-right: 3px solid #ffb44c;
|
||||
border-right: 3px solid rgba(255, 180, 76, 0.85);
|
||||
}
|
||||
|
||||
pre.compile_fail {
|
||||
|
@ -34,6 +34,10 @@ pre {
|
||||
background-color: #505050;
|
||||
}
|
||||
|
||||
.logo-container > img {
|
||||
filter: drop-shadow(0 0 5px #fff);
|
||||
}
|
||||
|
||||
/* Improve the scrollbar display on firefox */
|
||||
* {
|
||||
scrollbar-color: rgb(64, 65, 67) #717171;
|
||||
@ -270,6 +274,7 @@ a.test-arrow:hover{
|
||||
|
||||
:target > code, :target > .in-band {
|
||||
background-color: #494a3d;
|
||||
border-right: 3px solid #bb7410;
|
||||
}
|
||||
|
||||
pre.compile_fail {
|
||||
|
@ -45,6 +45,10 @@ pre {
|
||||
scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
|
||||
}
|
||||
|
||||
.logo-container > img {
|
||||
filter: drop-shadow(0 0 5px #aaa);
|
||||
}
|
||||
|
||||
/* Improve the scrollbar display on webkit-based browsers */
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #ecebeb;
|
||||
@ -265,6 +269,7 @@ a.test-arrow:hover{
|
||||
|
||||
:target > code, :target > .in-band {
|
||||
background: #FDFFD3;
|
||||
border-right: 3px solid #ffb44c;
|
||||
}
|
||||
|
||||
pre.compile_fail {
|
||||
|
15
src/test/ui/associated-types/issue-62200.rs
Normal file
15
src/test/ui/associated-types/issue-62200.rs
Normal file
@ -0,0 +1,15 @@
|
||||
struct S {}
|
||||
|
||||
trait T<'a> {
|
||||
type A;
|
||||
}
|
||||
|
||||
impl T<'_> for S {
|
||||
type A = u32;
|
||||
}
|
||||
|
||||
fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
|
||||
//~^ ERROR binding for associated type `Output` references an anonymous lifetime
|
||||
//~^^ NOTE lifetimes appearing in an associated type are not considered constrained
|
||||
|
||||
fn main() {}
|
11
src/test/ui/associated-types/issue-62200.stderr
Normal file
11
src/test/ui/associated-types/issue-62200.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
|
||||
--> $DIR/issue-62200.rs:11:39
|
||||
|
|
||||
LL | fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: lifetimes appearing in an associated type are not considered constrained
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0582`.
|
@ -5,7 +5,7 @@ LL | let y = x.or_else(4);
|
||||
| ^ expected an `FnOnce<()>` closure, found `{integer}`
|
||||
|
|
||||
= help: the trait `std::ops::FnOnce<()>` is not implemented for `{integer}`
|
||||
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -8,7 +8,7 @@ LL | is_fn(f);
|
||||
| ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}`
|
||||
|
|
||||
= help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}`
|
||||
= note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32;
|
||||
LL | type F<'a> = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
||||
|
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | impl<T: std::ops::Fn<()>> Fun for T {
|
||||
|
@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32;
|
||||
LL | type F<'a> = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
||||
|
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | impl<T: std::ops::Fn<()>> Fun for T {
|
||||
|
@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32;
|
||||
LL | type F<'a> = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
||||
|
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | impl<T: std::ops::Fn<()>> Fun for T {
|
||||
|
@ -16,7 +16,7 @@ LL | type F<'a>: Fn() -> u32;
|
||||
LL | type F<'a> = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
||||
|
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | impl<T: std::ops::Fn<()>> Fun for T {
|
||||
|
17
src/test/ui/issue-74047.rs
Normal file
17
src/test/ui/issue-74047.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// edition:2018
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io;
|
||||
|
||||
pub struct MyStream;
|
||||
pub struct OtherStream;
|
||||
|
||||
pub async fn connect() -> io::Result<MyStream> {
|
||||
let stream: MyStream = OtherStream.try_into()?;
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
impl TryFrom<OtherStream> for MyStream {}
|
||||
//~^ ERROR: missing
|
||||
|
||||
fn main() {}
|
12
src/test/ui/issue-74047.stderr
Normal file
12
src/test/ui/issue-74047.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0046]: not all trait items implemented, missing: `Error`, `try_from`
|
||||
--> $DIR/issue-74047.rs:14:1
|
||||
|
|
||||
LL | impl TryFrom<OtherStream> for MyStream {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation
|
||||
|
|
||||
= help: implement the missing item: `type Error = Type;`
|
||||
= help: implement the missing item: `fn try_from(_: T) -> std::result::Result<Self, <Self as std::convert::TryFrom<T>>::Error> { todo!() }`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0046`.
|
@ -5,7 +5,7 @@ LL | &mut *(ptr as *mut dyn Fn())
|
||||
| ^^^ expected an `Fn<()>` closure, found `()`
|
||||
|
|
||||
= help: the trait `std::ops::Fn<()>` is not implemented for `()`
|
||||
= note: wrap the `()` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: required for the cast to the object type `dyn std::ops::Fn()`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
13
src/test/ui/polymorphization/promoted-function.rs
Normal file
13
src/test/ui/polymorphization/promoted-function.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// run-pass
|
||||
fn fop<T>() {}
|
||||
|
||||
fn bar<T>() -> &'static fn() {
|
||||
&(fop::<T> as fn())
|
||||
}
|
||||
pub const FN: &'static fn() = &(fop::<i32> as fn());
|
||||
|
||||
fn main() {
|
||||
bar::<u32>();
|
||||
bar::<i32>();
|
||||
(FN)();
|
||||
}
|
@ -8,7 +8,7 @@ LL | call(foo);
|
||||
| ^^^ expected an `Fn<()>` closure, found `fn() {foo}`
|
||||
|
|
||||
= help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}`
|
||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||
|
||||
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
|
||||
@ -21,7 +21,7 @@ LL | call_mut(foo);
|
||||
| ^^^ expected an `FnMut<()>` closure, found `fn() {foo}`
|
||||
|
|
||||
= help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}`
|
||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||
|
||||
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
|
||||
@ -34,7 +34,7 @@ LL | call_once(foo);
|
||||
| ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}`
|
||||
|
|
||||
= help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}`
|
||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||
|
||||
error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
|
||||
@ -47,7 +47,7 @@ LL | call(foo_unsafe);
|
||||
| ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
|
||||
|
|
||||
= help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}`
|
||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||
|
||||
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
|
||||
@ -60,7 +60,7 @@ LL | call_mut(foo_unsafe);
|
||||
| ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
|
||||
|
|
||||
= help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}`
|
||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||
|
||||
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
|
||||
@ -73,7 +73,7 @@ LL | call_once(foo_unsafe);
|
||||
| ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
|
||||
|
|
||||
= help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}`
|
||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
|
||||
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
|
||||
= note: `#[target_feature]` functions do not implement the `Fn` traits
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
@ -62,7 +62,7 @@ fn multiple3() { }
|
||||
#[rustc_deprecated(since = "b", reason = "text")]
|
||||
#[rustc_const_unstable(feature = "c", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
|
||||
pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
|
||||
pub const fn multiple4() { } //~ ERROR multiple deprecated attributes
|
||||
//~^ ERROR Invalid stability or deprecation version found
|
||||
|
||||
#[rustc_deprecated(since = "a", reason = "text")]
|
||||
|
@ -82,7 +82,7 @@ error[E0544]: multiple stability levels
|
||||
LL | #[stable(feature = "a", since = "b")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0540]: multiple rustc_deprecated attributes
|
||||
error[E0550]: multiple deprecated attributes
|
||||
--> $DIR/stability-attribute-sanity.rs:65:1
|
||||
|
|
||||
LL | pub const fn multiple4() { }
|
||||
@ -108,5 +108,5 @@ LL | fn deprecated_without_unstable_or_stable() { }
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0539, E0541.
|
||||
Some errors have detailed explanations: E0539, E0541, E0550.
|
||||
For more information about an error, try `rustc --explain E0539`.
|
||||
|
Loading…
Reference in New Issue
Block a user