Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2982,6 +2982,12 @@ impl Param {
None
}

/// Returns `true` if parameter is exactly `&pin mut self`.
pub fn is_pinned_mut_self_receiver(&self) -> bool {
self.to_self()
.is_some_and(|eself| matches!(eself.node, SelfKind::Pinned(None, Mutability::Mut)))
}

/// Returns `true` if parameter is `self`.
pub fn is_self(&self) -> bool {
if let PatKind::Ident(_, ident, _) = self.pat.kind {
Expand Down
31 changes: 21 additions & 10 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }),
);

let (ident, (generics, kind)) = match &i.kind {
let (mut ident, (generics, kind)) = match &i.kind {
AssocItemKind::Const(box ConstItem {
ident,
generics,
Expand Down Expand Up @@ -1323,22 +1323,33 @@ impl<'hir> LoweringContext<'_, 'hir> {
};

let span = self.lower_span(i.span);
let trait_item_def_id = if is_in_trait_impl {
Some(
self.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(
span,
"could not resolve trait item being implemented",
)
}),
)
} else {
None
};

if self.resolver.pin_drop_sugar_impl_items.contains(&i.id) {
ident = Ident::new(sym::pin_drop, ident.span);
}

let item = hir::ImplItem {
owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
generics,
impl_kind: if is_in_trait_impl {
ImplItemImplKind::Trait {
defaultness,
trait_item_def_id: self
.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(
span,
"could not resolve trait item being implemented",
)
}),
trait_item_def_id: trait_item_def_id.unwrap(),
}
} else {
ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/pin_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ impl NoArgsAttributeParser for PinV2Parser {
Allow(Target::Struct),
Allow(Target::Union),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PinV2;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PinV2;
}
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ pub enum AttributeKind {
},

/// Represents `#[pin_v2]`
PinV2,
PinV2(Span),

/// Represents `#[prelude_import]`
PreludeImport,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl AttributeKind {
PatchableFunctionEntry { .. } => Yes,
Path(..) => No,
PatternComplexityLimit { .. } => No,
PinV2 => Yes,
PinV2(..) => Yes,
PreludeImport => No,
ProcMacro => No,
ProcMacroAttribute => No,
Expand Down
72 changes: 71 additions & 1 deletion compiler/rustc_hir_analysis/src/check/always_applicable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::span_bug;
use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
use rustc_span::sym;
use rustc_trait_selection::regions::InferCtxtRegionExt;
use rustc_trait_selection::traits::{self, ObligationCtxt};

Expand Down Expand Up @@ -72,7 +73,11 @@ pub(crate) fn check_drop_impl(
drop_impl_did,
adt_def.did(),
adt_to_impl_args,
)
)?;

check_drop_xor_pin_drop(tcx, adt_def.did(), drop_impl_did)?;

Ok(())
}
_ => {
span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop");
Expand Down Expand Up @@ -363,3 +368,68 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(

Ok(())
}

/// This function checks at least and at most one of `Drop::drop` and `Drop::pin_drop` is implemented.
/// It also checks that `Drop::pin_drop` must be implemented if `#[pin_v2]` is present on the type.
fn check_drop_xor_pin_drop<'tcx>(
tcx: TyCtxt<'tcx>,
adt_def_id: DefId,
drop_impl_did: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let mut drop_span = None;
let mut pin_drop_span = None;
for item in tcx.associated_items(drop_impl_did).in_definition_order() {
match item.kind {
ty::AssocKind::Fn { name: sym::drop, .. } => {
drop_span = Some(tcx.def_span(item.def_id))
}
ty::AssocKind::Fn { name: sym::pin_drop, .. } => {
pin_drop_span = Some(tcx.def_span(item.def_id))
}
_ => {}
}
}

match (drop_span, pin_drop_span) {
(None, None) => {
if tcx.features().pin_ergonomics() {
return Err(tcx.dcx().emit_err(crate::errors::MissingOneOfTraitItem {
span: tcx.def_span(drop_impl_did),
note: None,
missing_items_msg: "drop`, `pin_drop".to_string(),
}));
} else {
return Err(tcx
.dcx()
.span_delayed_bug(tcx.def_span(drop_impl_did), "missing `Drop::drop`"));
}
}
(Some(span), None) => {
if tcx.adt_def(adt_def_id).is_pin_project() {
let pin_v2_span = rustc_hir::find_attr!(tcx, adt_def_id, PinV2(attr) => *attr);
let adt_name = tcx.item_name(adt_def_id);
return Err(tcx.dcx().emit_err(crate::errors::PinV2WithoutPinDrop {
span,
pin_v2_span,
adt_name,
}));
}
}
(None, Some(span)) => {
if !tcx.features().pin_ergonomics() {
return Err(tcx.dcx().span_delayed_bug(
span,
"`Drop::pin_drop` should be guarded by the library feature gate",
));
}
}
(Some(drop_span), Some(pin_drop_span)) => {
return Err(tcx.dcx().emit_err(crate::errors::ConflictImplDropAndPinDrop {
span: tcx.def_span(drop_impl_did),
drop_span,
pin_drop_span,
}));
}
}
Ok(())
}
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rustc_middle::ty::{
TypeVisitable, TypeVisitableExt, Unnormalized, fold_regions,
};
use rustc_session::lint::builtin::UNINHABITED_STATIC;
use rustc_span::sym;
use rustc_target::spec::{AbiMap, AbiMapping};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::traits;
Expand Down Expand Up @@ -1347,6 +1348,15 @@ fn check_impl_items_against_trait<'tcx>(
if !is_implemented_here {
let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
// When the feature `pin_ergonomics` is disabled, we report `Drop::drop` is missing,
// instead of `Drop::drop` is unstable that might be confusing.
EvalResult::Deny { .. }
if !tcx.features().pin_ergonomics()
&& tcx.is_lang_item(trait_ref.def_id, hir::LangItem::Drop)
&& tcx.item_name(trait_item_id) == sym::drop =>
{
missing_items.push(tcx.associated_item(trait_item_id));
}
EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
tcx,
full_impl_span,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ use rustc_middle::ty::{
use rustc_middle::{bug, span_bug};
use rustc_session::errors::feature_err;
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1968,3 +1968,35 @@ pub(crate) struct EiiDefkindMismatchStaticSafety {
pub span: Span,
pub eii_name: Symbol,
}

#[derive(Diagnostic)]
#[diag("conflicting implementations of `Drop::drop` and `Drop::pin_drop`")]
pub(crate) struct ConflictImplDropAndPinDrop {
#[primary_span]
pub span: Span,
#[label("`drop(&mut self)` implemented here")]
pub drop_span: Span,
#[label("`pin_drop(&pin mut self)` implemented here")]
pub pin_drop_span: Span,
}

#[derive(Diagnostic)]
#[diag("`{$adt_name}` must implement `pin_drop`")]
#[help("structurally pinned types must keep `Pin`'s safety contract")]
pub(crate) struct PinV2WithoutPinDrop {
#[primary_span]
#[suggestion(
"implement `pin_drop` instead",
code = "fn pin_drop(&pin mut self)",
applicability = "maybe-incorrect"
)]
pub span: Span,
#[note("`{$adt_name}` is marked `#[pin_v2]` here")]
#[suggestion(
"remove the `#[pin_v2]` attribute if it is not intended for structurally pinning",
code = "",
applicability = "maybe-incorrect"
)]
pub pin_v2_span: Option<Span>,
pub adt_name: Symbol,
}
7 changes: 5 additions & 2 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ pub(crate) fn check_legal_trait_for_method_call(
receiver: Option<Span>,
expr_span: Span,
trait_id: DefId,
_body_id: DefId,
body_id: DefId,
) -> Result<(), ErrorGuaranteed> {
if tcx.is_lang_item(trait_id, LangItem::Drop) {
if tcx.is_lang_item(trait_id, LangItem::Drop)
// Allow calling `Drop::pin_drop` in `Drop::drop`
&& !tcx.is_lang_item(tcx.parent(body_id), LangItem::Drop)
{
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
errors::ExplicitDestructorCallSugg::Snippet {
lo: expr_span.shrink_to_lo(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ impl AdtDefData {
debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
}
if find_attr!(tcx, did, PinV2) {
if find_attr!(tcx, did, PinV2(..)) {
debug!("found pin-project type {:?}", did);
flags |= AdtFlags::IS_PIN_PROJECT;
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use rustc_abi::{
};
use rustc_ast as ast;
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
use rustc_ast::node_id::NodeMap;
use rustc_ast::node_id::{NodeMap, NodeSet};
pub use rustc_ast_ir::{Movability, Mutability, try_visit};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
Expand Down Expand Up @@ -204,6 +204,8 @@ pub struct ResolverGlobalCtxt {
pub struct ResolverAstLowering<'tcx> {
/// Resolutions for nodes that have a single resolution.
pub partial_res_map: NodeMap<hir::def::PartialRes>,
/// Impl items accepted by resolver as `fn drop(&pin mut self)` sugar for `Drop::pin_drop`.
pub pin_drop_sugar_impl_items: NodeSet,
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
pub import_res_map: NodeMap<hir::def::PerNS<Option<Res<ast::NodeId>>>>,
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
CallToFunctionWith { function: func_did, missing, build_enabled },
);
}
if let Some(trait_did) = self.tcx.trait_of_assoc(func_did)
&& self.tcx.is_lang_item(trait_did, hir::LangItem::Drop)
{
self.requires_unsafe(expr.span, CallDropExplicitly(func_did));
}
}
}
ExprKind::RawBorrow { arg, .. } => {
Expand Down Expand Up @@ -661,6 +666,8 @@ enum UnsafeOpKind {
build_enabled: Vec<Symbol>,
},
UnsafeBinderCast,
/// Calling `Drop::drop` or `Drop::pin_drop` explicitly.
CallDropExplicitly(DefId),
}

use UnsafeOpKind::*;
Expand Down Expand Up @@ -829,6 +836,9 @@ impl UnsafeOpKind {
unsafe_not_inherited_note,
},
),
CallDropExplicitly(_) => {
span_bug!(span, "`Drop::drop` or `Drop::pin_drop` should not be called explicitly")
}
}
}

Expand Down Expand Up @@ -1034,6 +1044,13 @@ impl UnsafeOpKind {
UnsafeBinderCast => {
dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
}
CallDropExplicitly(did) => {
dcx.emit_err(CallDropExplicitlyRequiresUnsafe {
span,
unsafe_not_inherited_note,
function: tcx.def_path_str(*did),
});
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,16 @@ pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}

#[derive(Diagnostic)]
#[diag("call `{$function}` explicitly is unsafe and requires unsafe block", code = E0133)]
pub(crate) struct CallDropExplicitlyRequiresUnsafe {
#[primary_span]
pub(crate) span: Span,
pub(crate) function: String,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}

#[derive(Subdiagnostic)]
#[label("items do not inherit unsafety from separate enclosing items")]
pub(crate) struct UnsafeNotInheritedNote {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::PatchableFunctionEntry { .. }
| AttributeKind::Path(..)
| AttributeKind::PatternComplexityLimit { .. }
| AttributeKind::PinV2
| AttributeKind::PinV2(..)
| AttributeKind::PreludeImport
| AttributeKind::ProfilerRuntime
| AttributeKind::RecursionLimit { .. }
Expand Down
Loading
Loading