Skip to content

Commit

Permalink
Auto merge of #119722 - matthiaskrgr:rollup-y6w3c9h, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #116129 (Rewrite `pin` module documentation to clarify usage and invariants)
 - #119703 (Impl trait diagnostic tweaks)
 - #119705 (Support `~const` in associated functions in trait impls)
 - #119708 (Unions are not `PointerLike`)
 - #119711 (Delete unused makefile in tests/ui)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 8, 2024
2 parents 75c68cf + bf20ade commit 76101ee
Show file tree
Hide file tree
Showing 53 changed files with 1,499 additions and 597 deletions.
3 changes: 2 additions & 1 deletion compiler/rustc_ast_lowering/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ ast_lowering_misplaced_double_dot =
.note = only allowed in tuple, tuple struct, and slice patterns
ast_lowering_misplaced_impl_trait =
`impl Trait` only allowed in function and inherent method argument and return types, not in {$position}
`impl Trait` is not allowed in {$position}
.note = `impl Trait` is only allowed in arguments and return types of functions and methods
ast_lowering_misplaced_relax_trait_bound =
`?Trait` bounds are only permitted at the point where a type parameter is declared
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub enum AssocTyParenthesesSub {

#[derive(Diagnostic)]
#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")]
#[note]
pub struct MisplacedImplTrait<'a> {
#[primary_span]
pub span: Span,
Expand Down
39 changes: 23 additions & 16 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::PredicateOrigin;
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, sym, Ident};
Expand Down Expand Up @@ -182,7 +183,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
}
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
let (ty, body_id) =
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
hir::ItemKind::Static(ty, *m, body_id)
}
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
Expand All @@ -191,7 +193,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_const_item(ty, span, expr.as_deref()),
|this| {
this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy)
},
);
hir::ItemKind::Const(ty, generics, body_id)
}
Expand Down Expand Up @@ -448,8 +452,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty: &Ty,
span: Span,
body: Option<&Expr>,
impl_trait_position: ImplTraitPosition,
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(impl_trait_position));
(ty, self.lower_const_body(span, body))
}

Expand Down Expand Up @@ -572,23 +577,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.

match parent_hir.node().expect_item().kind {
let generics = match parent_hir.node().expect_item().kind {
hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some();
&impl_.generics
}
hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => {
self.host_param_id = generics
.params
.iter()
.find(|param| {
matches!(
param.kind,
hir::GenericParamKind::Const { is_host_effect: true, .. }
)
})
.map(|param| param.def_id);
hir::ItemKind::Trait(_, _, generics, _, _) => generics,
kind => {
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
}
_ => {}
};

if self.tcx.features().effects {
self.host_param_id = generics
.params
.iter()
.find(|param| {
matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })
})
.map(|param| param.def_id);
}

match ctxt {
Expand Down
92 changes: 37 additions & 55 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,6 @@ enum ImplTraitPosition {
ClosureParam,
PointerParam,
FnTraitParam,
TraitParam,
ImplParam,
ExternFnReturn,
ClosureReturn,
PointerReturn,
Expand All @@ -324,29 +322,27 @@ impl std::fmt::Display for ImplTraitPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
ImplTraitPosition::Path => "paths",
ImplTraitPosition::Variable => "variable bindings",
ImplTraitPosition::Variable => "the type of variable bindings",
ImplTraitPosition::Trait => "traits",
ImplTraitPosition::AsyncBlock => "async blocks",
ImplTraitPosition::Bound => "bounds",
ImplTraitPosition::Generic => "generics",
ImplTraitPosition::ExternFnParam => "`extern fn` params",
ImplTraitPosition::ClosureParam => "closure params",
ImplTraitPosition::PointerParam => "`fn` pointer params",
ImplTraitPosition::FnTraitParam => "`Fn` trait params",
ImplTraitPosition::TraitParam => "trait method params",
ImplTraitPosition::ImplParam => "`impl` method params",
ImplTraitPosition::ExternFnParam => "`extern fn` parameters",
ImplTraitPosition::ClosureParam => "closure parameters",
ImplTraitPosition::PointerParam => "`fn` pointer parameters",
ImplTraitPosition::FnTraitParam => "the parameters of `Fn` trait bounds",
ImplTraitPosition::ExternFnReturn => "`extern fn` return types",
ImplTraitPosition::ClosureReturn => "closure return types",
ImplTraitPosition::PointerReturn => "`fn` pointer return types",
ImplTraitPosition::FnTraitReturn => "`Fn` trait return types",
ImplTraitPosition::FnTraitReturn => "the return type of `Fn` trait bounds",
ImplTraitPosition::GenericDefault => "generic parameter defaults",
ImplTraitPosition::ConstTy => "const types",
ImplTraitPosition::StaticTy => "static types",
ImplTraitPosition::AssocTy => "associated types",
ImplTraitPosition::FieldTy => "field types",
ImplTraitPosition::Cast => "cast types",
ImplTraitPosition::Cast => "cast expression types",
ImplTraitPosition::ImplSelf => "impl headers",
ImplTraitPosition::OffsetOf => "`offset_of!` params",
ImplTraitPosition::OffsetOf => "`offset_of!` parameters",
};

write!(f, "{name}")
Expand All @@ -364,19 +360,6 @@ enum FnDeclKind {
Impl,
}

impl FnDeclKind {
fn param_impl_trait_allowed(&self) -> bool {
matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait)
}

fn return_impl_trait_allowed(&self) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true,
_ => false,
}
}
}

#[derive(Copy, Clone)]
enum AstOwner<'a> {
NonOwner,
Expand Down Expand Up @@ -1842,19 +1825,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
inputs = &inputs[..inputs.len() - 1];
}
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
let itctx = if kind.param_impl_trait_allowed() {
ImplTraitContext::Universal
} else {
ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow APIT")
}
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
FnDeclKind::Trait => ImplTraitPosition::TraitParam,
FnDeclKind::Impl => ImplTraitPosition::ImplParam,
})
let itctx = match kind {
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => {
ImplTraitContext::Universal
}
FnDeclKind::ExternFn => {
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam)
}
FnDeclKind::Closure => {
ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam)
}
FnDeclKind::Pointer => {
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
}
};
self.lower_ty_direct(&param.ty, &itctx)
}));
Expand All @@ -1866,26 +1849,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
None => match &decl.output {
FnRetTy::Ty(ty) => {
let context = if kind.return_impl_trait_allowed() {
let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
let itctx = match kind {
FnDeclKind::Fn
| FnDeclKind::Inherent
| FnDeclKind::Trait
| FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
fn_kind: kind,
},
FnDeclKind::ExternFn => {
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
}
FnDeclKind::Closure => {
ImplTraitContext::Disallowed(ImplTraitPosition::ClosureReturn)
}
FnDeclKind::Pointer => {
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
}
} else {
ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn
| FnDeclKind::Inherent
| FnDeclKind::Trait
| FnDeclKind::Impl => {
unreachable!("fn should allow return-position impl trait in traits")
}
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn,
FnDeclKind::Closure => ImplTraitPosition::ClosureReturn,
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
})
};
hir::FnRetTy::Return(self.lower_ty(ty, &context))
hir::FnRetTy::Return(self.lower_ty(ty, &itctx))
}
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
},
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_target/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ impl<'a> Layout<'a> {
/// Whether the layout is from a type that implements [`std::marker::PointerLike`].
///
/// Currently, that means that the type is pointer-sized, pointer-aligned,
/// and has a scalar ABI.
/// and has a initialized (non-union), scalar ABI.
pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
self.size() == data_layout.pointer_size
&& self.align().abi == data_layout.pointer_align.abi
&& matches!(self.abi(), Abi::Scalar(..))
&& matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. }))
}
}

Expand Down
71 changes: 47 additions & 24 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,25 +899,37 @@ marker_impls! {
{T: ?Sized} &mut T,
}

/// Types that can be safely moved after being pinned.
///
/// Rust itself has no notion of immovable types, and considers moves (e.g.,
/// through assignment or [`mem::replace`]) to always be safe.
///
/// The [`Pin`][Pin] type is used instead to prevent moves through the type
/// system. Pointers `P<T>` wrapped in the [`Pin<P<T>>`][Pin] wrapper can't be
/// moved out of. See the [`pin` module] documentation for more information on
/// pinning.
///
/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off
/// the type, which then allows moving `T` out of [`Pin<P<T>>`][Pin] with
/// functions such as [`mem::replace`].
///
/// `Unpin` has no consequence at all for non-pinned data. In particular,
/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not
/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data
/// wrapped inside a [`Pin<P<T>>`][Pin] because you cannot get the `&mut T` you
/// need for that, and *that* is what makes this system work.
/// Types that do not require any pinning guarantees.
///
/// For information on what "pinning" is, see the [`pin` module] documentation.
///
/// Implementing the `Unpin` trait for `T` expresses the fact that `T` is pinning-agnostic:
/// it shall not expose nor rely on any pinning guarantees. This, in turn, means that a
/// `Pin`-wrapped pointer to such a type can feature a *fully unrestricted* API.
/// In other words, if `T: Unpin`, a value of type `T` will *not* be bound by the invariants
/// which pinning otherwise offers, even when "pinned" by a [`Pin<Ptr>`] pointing at it.
/// When a value of type `T` is pointed at by a [`Pin<Ptr>`], [`Pin`] will not restrict access
/// to the pointee value like it normally would, thus allowing the user to do anything that they
/// normally could with a non-[`Pin`]-wrapped `Ptr` to that value.
///
/// The idea of this trait is to alleviate the reduced ergonomics of APIs that require the use
/// of [`Pin`] for soundness for some types, but which also want to be used by other types that
/// don't care about pinning. The prime example of such an API is [`Future::poll`]. There are many
/// [`Future`] types that don't care about pinning. These futures can implement `Unpin` and
/// therefore get around the pinning related restrictions in the API, while still allowing the
/// subset of [`Future`]s which *do* require pinning to be implemented soundly.
///
/// For more discussion on the consequences of [`Unpin`] within the wider scope of the pinning
/// system, see the [section about `Unpin`] in the [`pin` module].
///
/// `Unpin` has no consequence at all for non-pinned data. In particular, [`mem::replace`] happily
/// moves `!Unpin` data, which would be immovable when pinned ([`mem::replace`] works for any
/// `&mut T`, not just when `T: Unpin`).
///
/// *However*, you cannot use [`mem::replace`] on `!Unpin` data which is *pinned* by being wrapped
/// inside a [`Pin<Ptr>`] pointing at it. This is because you cannot (safely) use a
/// [`Pin<Ptr>`] to get an `&mut T` to its pointee value, which you would need to call
/// [`mem::replace`], and *that* is what makes this system work.
///
/// So this, for example, can only be done on types implementing `Unpin`:
///
Expand All @@ -935,11 +947,22 @@ marker_impls! {
/// mem::replace(&mut *pinned_string, "other".to_string());
/// ```
///
/// This trait is automatically implemented for almost every type.
///
/// [`mem::replace`]: crate::mem::replace
/// [Pin]: crate::pin::Pin
/// [`pin` module]: crate::pin
/// This trait is automatically implemented for almost every type. The compiler is free
/// to take the conservative stance of marking types as [`Unpin`] so long as all of the types that
/// compose its fields are also [`Unpin`]. This is because if a type implements [`Unpin`], then it
/// is unsound for that type's implementation to rely on pinning-related guarantees for soundness,
/// *even* when viewed through a "pinning" pointer! It is the responsibility of the implementor of
/// a type that relies upon pinning for soundness to ensure that type is *not* marked as [`Unpin`]
/// by adding [`PhantomPinned`] field. For more details, see the [`pin` module] docs.
///
/// [`mem::replace`]: crate::mem::replace "mem replace"
/// [`Future`]: crate::future::Future "Future"
/// [`Future::poll`]: crate::future::Future::poll "Future poll"
/// [`Pin`]: crate::pin::Pin "Pin"
/// [`Pin<Ptr>`]: crate::pin::Pin "Pin"
/// [`pin` module]: crate::pin "pin module"
/// [section about `Unpin`]: crate::pin#unpin "pin module docs about unpin"
/// [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
#[stable(feature = "pin", since = "1.33.0")]
#[diagnostic::on_unimplemented(
note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope",
Expand Down

0 comments on commit 76101ee

Please sign in to comment.