Auto merge of #98359 - JohnTitor:rollup-v30vyzr, r=JohnTitor

Rollup of 6 pull requests

Successful merges:

 - #97867 (lub: don't bail out due to empty binders)
 - #98099 (interpret: convert_tag_add_extra: allow tagger to raise errors)
 - #98199 (Move some tests to more reasonable directories)
 - #98334 (Add a full regression test for #73727)
 - #98336 (Remove the unused-`#[doc(hidden)]` logic from the `unused_attributes` lint)
 - #98344 (This comment is out dated and misleading, the arm is about TAITs)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-06-22 00:28:20 +00:00
commit a09c668c96
58 changed files with 248 additions and 291 deletions

View file

@ -334,12 +334,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// allocation (because a copy had to be done to add tags or metadata), machine memory will
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
/// owned allocation to the map even when the map is shared.)
///
/// This must only fail if `alloc` contains relocations.
fn init_allocation_extra<'b>(
ecx: &InterpCx<'mir, 'tcx, Self>,
id: AllocId,
alloc: Cow<'b, Allocation>,
kind: Option<MemoryKind<Self::MemoryKind>>,
) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>>;
/// Hook for performing extra checks on a memory read access.
///
@ -485,9 +487,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
_id: AllocId,
alloc: Cow<'b, Allocation>,
_kind: Option<MemoryKind<Self::MemoryKind>>,
) -> Cow<'b, Allocation<Self::PointerTag>> {
) -> InterpResult<$tcx, Cow<'b, Allocation<Self::PointerTag>>> {
// We do not use a tag so we can just cheaply forward the allocation
alloc
Ok(alloc)
}
fn extern_static_base_pointer(

View file

@ -199,7 +199,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
Ok(self.allocate_raw_ptr(alloc, kind))
// We can `unwrap` since `alloc` contains no pointers.
Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
}
pub fn allocate_bytes_ptr(
@ -210,23 +211,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
mutability: Mutability,
) -> Pointer<M::PointerTag> {
let alloc = Allocation::from_bytes(bytes, align, mutability);
self.allocate_raw_ptr(alloc, kind)
// We can `unwrap` since `alloc` contains no pointers.
self.allocate_raw_ptr(alloc, kind).unwrap()
}
/// This can fail only of `alloc` contains relocations.
pub fn allocate_raw_ptr(
&mut self,
alloc: Allocation,
kind: MemoryKind<M::MemoryKind>,
) -> Pointer<M::PointerTag> {
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
let id = self.tcx.reserve_alloc_id();
debug_assert_ne!(
Some(kind),
M::GLOBAL_KIND.map(MemoryKind::Machine),
"dynamically allocating global memory"
);
let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind));
let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind))?;
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
M::tag_alloc_base_pointer(self, Pointer::from(id))
Ok(M::tag_alloc_base_pointer(self, Pointer::from(id)))
}
pub fn reallocate_ptr(
@ -510,13 +513,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?;
// We got tcx memory. Let the machine initialize its "extra" stuff.
let alloc = M::init_allocation_extra(
M::init_allocation_extra(
self,
id, // always use the ID we got as input, not the "hidden" one.
Cow::Borrowed(alloc.inner()),
M::GLOBAL_KIND.map(MemoryKind::Machine),
);
Ok(alloc)
)
}
/// Gives raw access to the `Allocation`, without bounds or alignment checks.

View file

@ -95,12 +95,20 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
T: Relate<'tcx>,
{
debug!("binders(a={:?}, b={:?})", a, b);
// When higher-ranked types are involved, computing the LUB is
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
// When higher-ranked types are involved, computing the GLB is
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
a,
b,
)?;
Ok(a)
} else {
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
}
}
}

View file

@ -95,12 +95,20 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
T: Relate<'tcx>,
{
debug!("binders(a={:?}, b={:?})", a, b);
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
a,
b,
)?;
Ok(a)
} else {
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
}
}
}

View file

@ -244,12 +244,12 @@ impl<Tag> Allocation<Tag> {
impl Allocation {
/// Convert Tag and add Extra fields
pub fn convert_tag_add_extra<Tag, Extra>(
pub fn convert_tag_add_extra<Tag, Extra, Err>(
self,
cx: &impl HasDataLayout,
extra: Extra,
mut tagger: impl FnMut(Pointer<AllocId>) -> Pointer<Tag>,
) -> Allocation<Tag, Extra> {
mut tagger: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Tag>, Err>,
) -> Result<Allocation<Tag, Extra>, Err> {
// Compute new pointer tags, which also adjusts the bytes.
let mut bytes = self.bytes;
let mut new_relocations = Vec::with_capacity(self.relocations.0.len());
@ -260,19 +260,19 @@ impl Allocation {
let ptr_bytes = &mut bytes[idx..idx + ptr_size];
let bits = read_target_uint(endian, ptr_bytes).unwrap();
let (ptr_tag, ptr_offset) =
tagger(Pointer::new(alloc_id, Size::from_bytes(bits))).into_parts();
tagger(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
new_relocations.push((offset, ptr_tag));
}
// Create allocation.
Allocation {
Ok(Allocation {
bytes,
relocations: Relocations::from_presorted(new_relocations),
init_mask: self.init_mask,
align: self.align,
mutability: self.mutability,
extra,
}
})
}
}

View file

@ -4,8 +4,7 @@
//! conflicts between multiple such attributes attached to the same
//! item.
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem};
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_expand::base::resolve_path;
@ -899,68 +898,6 @@ impl CheckAttrVisitor<'_> {
}
}
/// Checks `#[doc(hidden)]` attributes. Returns `true` if valid.
fn check_doc_hidden(
&self,
attr: &Attribute,
meta_index: usize,
meta: &NestedMetaItem,
hir_id: HirId,
target: Target,
) -> bool {
if let Target::AssocConst
| Target::AssocTy
| Target::Method(MethodKind::Trait { body: true }) = target
{
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = containing_item.kind {
let meta_items = attr.meta_item_list().unwrap();
let (span, replacement_span) = if meta_items.len() == 1 {
(attr.span, attr.span)
} else {
let meta_span = meta.span();
(
meta_span,
meta_span.until(match meta_items.get(meta_index + 1) {
Some(next_item) => next_item.span(),
None => match attr.get_normal_item().args {
MacArgs::Delimited(DelimSpan { close, .. }, ..) => close,
_ => unreachable!(),
},
}),
)
};
// FIXME: #[doc(hidden)] was previously erroneously allowed on trait impl items,
// so for backward compatibility only emit a warning and do not mark it as invalid.
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
lint.build("`#[doc(hidden)]` is ignored on trait impl items")
.warn(
"this was previously accepted by the compiler but is \
being phased out; it will become a hard error in \
a future release!",
)
.note(
"whether the impl item is `doc(hidden)` or not \
entirely depends on the corresponding trait item",
)
.span_suggestion(
replacement_span,
"remove this attribute",
"",
Applicability::MachineApplicable,
)
.emit();
});
}
}
true
}
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
fn check_attr_not_crate_level(
&self,
@ -1079,7 +1016,7 @@ impl CheckAttrVisitor<'_> {
let mut is_valid = true;
if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
for (meta_index, meta) in list.into_iter().enumerate() {
for meta in list {
if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() {
sym::alias
@ -1127,15 +1064,6 @@ impl CheckAttrVisitor<'_> {
is_valid = false;
}
sym::hidden if !self.check_doc_hidden(attr,
meta_index,
meta,
hir_id,
target,
) => {
is_valid = false;
}
// no_default_passes: deprecated
// passes: deprecated
// plugins: removed, but rustdoc warns about it itself

View file

@ -846,8 +846,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// the opaque_ty generics
let opaque_ty = self.tcx.hir().item(item_id);
let (generics, bounds) = match opaque_ty.kind {
// Named opaque `impl Trait` types are reached via `TyKind::Path`.
// This arm is for `impl Trait` in the types of statics, constants and locals.
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias,
..
@ -866,7 +864,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
return;
}
// RPIT (return position impl trait)
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
ref generics,

View file

@ -1,5 +1,5 @@
error: `&'static [u32]` is forbidden as the type of a const generic parameter
--> $DIR/static-reference-array-const-param.rs:1:15
--> $DIR/issue-73727-static-reference-array-const-param.rs:9:15
|
LL | fn a<const X: &'static [u32]>() {}
| ^^^^^^^^^^^^^^

View file

@ -0,0 +1,14 @@
// Regression test for #73727
// revisions: full min
//[full]check-pass
#![cfg_attr(full, feature(adt_const_params))]
#![cfg_attr(full, allow(incomplete_features))]
fn a<const X: &'static [u32]>() {}
//[min]~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter
fn main() {
a::<{&[]}>();
}

View file

@ -1,6 +0,0 @@
fn a<const X: &'static [u32]>() {}
//~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter
fn main() {
a::<{&[]}>();
}

View file

@ -1,55 +0,0 @@
#![feature(inherent_associated_types)]
#![allow(dead_code, incomplete_features)]
#![crate_type = "lib"]
#![deny(unused_attributes)]
// run-rustfix
pub trait Trait {
type It;
const IT: ();
fn it0();
fn it1();
fn it2();
}
pub struct Implementor;
impl Implementor {
#[doc(hidden)] // no error
type Inh = ();
#[doc(hidden)] // no error
const INH: () = ();
#[doc(hidden)] // no error
fn inh() {}
}
impl Trait for Implementor {
type It = ();
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
const IT: () = ();
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc(alias = "aka")]
fn it0() {}
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc(alias = "this", )]
fn it1() {}
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc()]
fn it2() {}
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
//~| ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
}

View file

@ -1,55 +0,0 @@
#![feature(inherent_associated_types)]
#![allow(dead_code, incomplete_features)]
#![crate_type = "lib"]
#![deny(unused_attributes)]
// run-rustfix
pub trait Trait {
type It;
const IT: ();
fn it0();
fn it1();
fn it2();
}
pub struct Implementor;
impl Implementor {
#[doc(hidden)] // no error
type Inh = ();
#[doc(hidden)] // no error
const INH: () = ();
#[doc(hidden)] // no error
fn inh() {}
}
impl Trait for Implementor {
#[doc(hidden)]
type It = ();
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc(hidden)]
const IT: () = ();
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc(hidden, alias = "aka")]
fn it0() {}
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc(alias = "this", hidden,)]
fn it1() {}
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
#[doc(hidden, hidden)]
fn it2() {}
//~^^ ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
//~| ERROR `#[doc(hidden)]` is ignored
//~| WARNING this was previously accepted
}

View file

@ -1,67 +0,0 @@
error: `#[doc(hidden)]` is ignored on trait impl items
--> $DIR/unused-attr-doc-hidden.rs:29:5
|
LL | #[doc(hidden)]
| ^^^^^^^^^^^^^^ help: remove this attribute
|
note: the lint level is defined here
--> $DIR/unused-attr-doc-hidden.rs:4:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
error: `#[doc(hidden)]` is ignored on trait impl items
--> $DIR/unused-attr-doc-hidden.rs:34:5
|
LL | #[doc(hidden)]
| ^^^^^^^^^^^^^^ help: remove this attribute
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
error: `#[doc(hidden)]` is ignored on trait impl items
--> $DIR/unused-attr-doc-hidden.rs:39:11
|
LL | #[doc(hidden, alias = "aka")]
| ^^^^^^--
| |
| help: remove this attribute
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
error: `#[doc(hidden)]` is ignored on trait impl items
--> $DIR/unused-attr-doc-hidden.rs:44:27
|
LL | #[doc(alias = "this", hidden,)]
| ^^^^^^-
| |
| help: remove this attribute
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
error: `#[doc(hidden)]` is ignored on trait impl items
--> $DIR/unused-attr-doc-hidden.rs:49:11
|
LL | #[doc(hidden, hidden)]
| ^^^^^^--
| |
| help: remove this attribute
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
error: `#[doc(hidden)]` is ignored on trait impl items
--> $DIR/unused-attr-doc-hidden.rs:49:19
|
LL | #[doc(hidden, hidden)]
| ^^^^^^ help: remove this attribute
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
error: aborting due to 6 previous errors

View file

@ -0,0 +1,22 @@
// check-pass
fn lt_in_fn_fn<'a: 'a>() -> fn(fn(&'a ())) {
|_| ()
}
fn foo<'a, 'b, 'lower>(v: bool)
where
'a: 'lower,
'b: 'lower,
{
// if we infer `x` to be higher ranked in the future,
// this would cause a type error.
let x = match v {
true => lt_in_fn_fn::<'a>(),
false => lt_in_fn_fn::<'b>(),
};
let _: fn(fn(&'lower())) = x;
}
fn main() {}

View file

@ -0,0 +1,55 @@
fn lt<'a: 'a>() -> &'a () {
&()
}
fn lt_in_fn<'a: 'a>() -> fn(&'a ()) {
|_| ()
}
struct Contra<'a>(fn(&'a ()));
fn lt_in_contra<'a: 'a>() -> Contra<'a> {
Contra(|_| ())
}
fn covariance<'a, 'b, 'upper>(v: bool)
where
'upper: 'a,
'upper: 'b,
{
let _: &'upper () = match v {
//~^ ERROR lifetime may not live long enough
//~| ERROR lifetime may not live long enough
true => lt::<'a>(),
false => lt::<'b>(),
};
}
fn contra_fn<'a, 'b, 'lower>(v: bool)
where
'a: 'lower,
'b: 'lower,
{
let _: fn(&'lower ()) = match v {
//~^ ERROR lifetime may not live long enough
true => lt_in_fn::<'a>(),
false => lt_in_fn::<'b>(),
};
}
fn contra_struct<'a, 'b, 'lower>(v: bool)
where
'a: 'lower,
'b: 'lower,
{
let _: Contra<'lower> = match v {
//~^ ERROR lifetime may not live long enough
true => lt_in_contra::<'a>(),
false => lt_in_contra::<'b>(),
};
}
fn main() {}

View file

@ -0,0 +1,59 @@
error: lifetime may not live long enough
--> $DIR/empty-binders-err.rs:20:12
|
LL | fn covariance<'a, 'b, 'upper>(v: bool)
| -- ------ lifetime `'upper` defined here
| |
| lifetime `'a` defined here
...
LL | let _: &'upper () = match v {
| ^^^^^^^^^^ type annotation requires that `'a` must outlive `'upper`
|
= help: consider adding the following bound: `'a: 'upper`
error: lifetime may not live long enough
--> $DIR/empty-binders-err.rs:20:12
|
LL | fn covariance<'a, 'b, 'upper>(v: bool)
| -- ------ lifetime `'upper` defined here
| |
| lifetime `'b` defined here
...
LL | let _: &'upper () = match v {
| ^^^^^^^^^^ type annotation requires that `'b` must outlive `'upper`
|
= help: consider adding the following bound: `'b: 'upper`
help: the following changes may resolve your lifetime errors
|
= help: add bound `'a: 'upper`
= help: add bound `'b: 'upper`
error: lifetime may not live long enough
--> $DIR/empty-binders-err.rs:35:12
|
LL | fn contra_fn<'a, 'b, 'lower>(v: bool)
| -- ------ lifetime `'lower` defined here
| |
| lifetime `'a` defined here
...
LL | let _: fn(&'lower ()) = match v {
| ^^^^^^^^^^^^^^ type annotation requires that `'lower` must outlive `'a`
|
= help: consider adding the following bound: `'lower: 'a`
error: lifetime may not live long enough
--> $DIR/empty-binders-err.rs:48:12
|
LL | fn contra_struct<'a, 'b, 'lower>(v: bool)
| -- ------ lifetime `'lower` defined here
| |
| lifetime `'a` defined here
...
LL | let _: Contra<'lower> = match v {
| ^^^^^^^^^^^^^^ type annotation requires that `'lower` must outlive `'a`
|
= help: consider adding the following bound: `'lower: 'a`
error: aborting due to 4 previous errors

View file

@ -0,0 +1,45 @@
// check-pass
//
// Check that computing the lub works even for empty binders.
fn lt<'a: 'a>() -> &'a () {
&()
}
fn lt_in_fn<'a: 'a>() -> fn(&'a ()) {
|_| ()
}
struct Contra<'a>(fn(&'a ()));
fn lt_in_contra<'a: 'a>() -> Contra<'a> {
Contra(|_| ())
}
fn ok<'a, 'b, 'upper, 'lower>(v: bool)
where
'upper: 'a,
'upper: 'b,
'a: 'lower,
'b: 'lower,
{
let _: &'lower () = match v {
true => lt::<'a>(),
false => lt::<'b>(),
};
// This errored in the past because LUB and GLB always
// bailed out when encountering binders, even if they were
// empty.
let _: fn(&'upper ()) = match v {
true => lt_in_fn::<'a>(),
false => lt_in_fn::<'b>(),
};
// This was already accepted, as relate didn't encounter any binders.
let _: Contra<'upper> = match v {
true => lt_in_contra::<'a>(),
false => lt_in_contra::<'b>(),
};
}
fn main() {}

View file

@ -8,7 +8,7 @@ use std::path::Path;
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 968;
const ISSUES_ENTRY_LIMIT: usize = 2179;
const ISSUES_ENTRY_LIMIT: usize = 2147;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))