From de405dcb8fbcd0add1e60c75800dac9b8fbe4884 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 27 Jan 2025 06:06:06 +0800 Subject: [PATCH 1/6] introduce CoercePointeeWellformed for coherence checks at typeck stage --- .../src/deriving/coerce_pointee.rs | 64 ++++++++++++--- .../src/error_codes/E0802.md | 80 +++++++++++++++++++ compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_expand/src/build.rs | 39 ++++++++- compiler/rustc_hir/src/lang_items.rs | 6 ++ compiler/rustc_hir_analysis/messages.ftl | 6 ++ .../src/coherence/builtin.rs | 28 +++++++ compiler/rustc_hir_analysis/src/errors.rs | 22 +++++ compiler/rustc_span/src/symbol.rs | 2 + library/core/src/marker.rs | 6 ++ .../ui/deriving/auxiliary/malicious-macro.rs | 31 +++++++ .../deriving/built-in-proc-macro-scope.stdout | 2 + .../deriving-coerce-pointee-expanded.stdout | 13 +++ .../deriving/deriving-coerce-pointee-neg.rs | 11 +++ .../deriving-coerce-pointee-neg.stderr | 62 ++++++++------ 15 files changed, 337 insertions(+), 36 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0802.md create mode 100644 tests/ui/deriving/auxiliary/malicious-macro.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 82417a86dd9ee..7e30cf327fc81 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -3,11 +3,12 @@ use ast::ptr::P; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::visit::BoundKind; use rustc_ast::{ - self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, + self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem, TraitBoundModifiers, VariantData, WherePredicate, }; use rustc_attr_parsing as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_errors::E0802; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; @@ -88,8 +89,7 @@ pub(crate) fn expand_deriving_coerce_pointee( } else { let mut pointees = type_params .iter() - .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span))) - .fuse(); + .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span))); match (pointees.next(), pointees.next()) { (Some((idx, _span)), None) => idx, (None, _) => { @@ -110,6 +110,52 @@ pub(crate) fn expand_deriving_coerce_pointee( // Declare helper function that adds implementation blocks. // FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),]; + // # Wellformed-ness assertion + { + let trait_path = + cx.path_all(span, true, path!(span, core::marker::CoercePointeeWellformed), vec![]); + let trait_ref = cx.trait_ref(trait_path); + push(Annotatable::Item( + cx.item( + span, + Ident::empty(), + attrs.clone(), + ast::ItemKind::Impl(Box::new(ast::Impl { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Final, + constness: ast::Const::No, + generics: Generics { + params: generics + .params + .iter() + .map(|p| match &p.kind { + GenericParamKind::Lifetime => { + cx.lifetime_param(p.span(), p.ident, p.bounds.clone()) + } + GenericParamKind::Type { default: _ } => { + cx.typaram(p.span(), p.ident, p.bounds.clone(), None) + } + GenericParamKind::Const { ty, kw_span: _, default: _ } => cx + .const_param( + p.span(), + p.ident, + p.bounds.clone(), + ty.clone(), + None, + ), + }) + .collect(), + where_clause: generics.where_clause.clone(), + span: generics.span, + }, + of_trait: Some(trait_ref), + self_ty: self_type.clone(), + items: ThinVec::new(), + })), + ), + )); + } let mut add_impl_block = |generics, trait_symbol, trait_args| { let mut parts = path!(span, core::ops); parts.push(Ident::new(trait_symbol, span)); @@ -430,35 +476,35 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_transparent)] +#[diag(builtin_macros_coerce_pointee_requires_transparent, code = E0802)] struct RequireTransparent { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_field)] +#[diag(builtin_macros_coerce_pointee_requires_one_field, code = E0802)] struct RequireOneField { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_generic)] +#[diag(builtin_macros_coerce_pointee_requires_one_generic, code = E0802)] struct RequireOneGeneric { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_one_pointee)] +#[diag(builtin_macros_coerce_pointee_requires_one_pointee, code = E0802)] struct RequireOnePointee { #[primary_span] span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_too_many_pointees)] +#[diag(builtin_macros_coerce_pointee_too_many_pointees, code = E0802)] struct TooManyPointees { #[primary_span] one: Span, @@ -467,7 +513,7 @@ struct TooManyPointees { } #[derive(Diagnostic)] -#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)] +#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)] struct RequiresMaybeSized { #[primary_span] span: Span, diff --git a/compiler/rustc_error_codes/src/error_codes/E0802.md b/compiler/rustc_error_codes/src/error_codes/E0802.md new file mode 100644 index 0000000000000..9088b100886d3 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0802.md @@ -0,0 +1,80 @@ +The target of `derive(CoercePointee)` macro has inadmissible specification for +a meaningful use. + +Erroneous code examples: + +The target data is not a `struct`. + +```compile_fail,E0802 +#[derive(CoercePointee)] +enum NotStruct<'a, T: ?Sized> { + Variant(&'a T), +} +``` + +The target data has a layout that is not transparent, or `repr(transparent)` +in other words. + +```compile_fail,E0802 +#[derive(CoercePointee)] +struct NotTransparent<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} +``` + +The target data has no data field. + +```compile_fail,E0802 +#[derive(CoercePointee)] +#[repr(transparent)] +struct NoField<'a, #[pointee] T: ?Sized> {} +``` + +The target data is not generic over any data, or has no generic type parameter. + +```compile_fail,E0802 +#[derive(CoercePointee)] +#[repr(transparent)] +struct NoGeneric<'a>(&'a u8); +``` + +The target data has multiple generic type parameters, but none is designated as +a pointee for coercion. + +```compile_fail,E0802 +#[derive(CoercePointee)] +#[repr(transparent)] +struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> { + a: (&'a T1, &'a T2), +} +``` + +The target data has multiple generic type parameters that are designated as +pointees for coercion. + +```compile_fail,E0802 +#[derive(CoercePointee)] +#[repr(transparent)] +struct TooManyPointees< + 'a, + #[pointee] A: ?Sized, + #[pointee] B: ?Sized> +((&'a A, &'a B)); +``` + +The type parameter that is designated as a pointee is not marked `?Sized`. + +```compile_fail,E0802 +#[derive(CoercePointee)] +#[repr(transparent)] +struct NoMaybeSized<'a, #[pointee] T> { + ptr: &'a T, +} +``` + +In summary, the `CoercePointee` macro demands the type to be a `struct` that is +generic over at least one type or over more types, one of which is marked with +`#[pointee]`, and has at least one data field and adopts a `repr(transparent)` +layout. +The only generic type or the type marked with `#[pointee]` has to be also +marked as `?Sized`. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 0a30bdb48a09c..e970b16f61064 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -545,6 +545,7 @@ E0798: 0798, E0799: 0799, E0800: 0800, E0801: 0801, +E0802: 0802, ); ) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 8bf09cf96b3f7..df4a0031e3107 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -1,7 +1,8 @@ use rustc_ast::ptr::P; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, attr, token, + self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, + attr, token, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -138,6 +139,42 @@ impl<'a> ExtCtxt<'a> { } } + pub fn lifetime_param( + &self, + span: Span, + ident: Ident, + bounds: ast::GenericBounds, + ) -> ast::GenericParam { + ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: ident.with_span_pos(span), + attrs: AttrVec::new(), + bounds, + is_placeholder: false, + kind: ast::GenericParamKind::Lifetime, + colon_span: None, + } + } + + pub fn const_param( + &self, + span: Span, + ident: Ident, + bounds: ast::GenericBounds, + ty: P, + default: Option, + ) -> ast::GenericParam { + ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: ident.with_span_pos(span), + attrs: AttrVec::new(), + bounds, + is_placeholder: false, + kind: ast::GenericParamKind::Const { ty, kw_span: DUMMY_SP, default }, + colon_span: None, + } + } + pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef { ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID } } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b6689c95c4bb2..b18e96646b18f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -370,6 +370,8 @@ language_item_table! { PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0); + CoercePointeeWellformed, sym::coerce_pointee_wellformed, coerce_pointee_wellformed_trait, Target::Trait, GenericRequirement::Exact(0); + ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); @@ -429,9 +431,13 @@ language_item_table! { ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None; } +/// The requirement imposed on the generics of a lang item pub enum GenericRequirement { + /// No restriction on the generics None, + /// A minimum number of generics that is demanded on a lang item Minimum(usize), + /// The number of generics must match precisely as stipulated Exact(usize), } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c28c1afcfe66c..2417ff3bb1a1f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -85,6 +85,12 @@ hir_analysis_cmse_output_stack_spill = .note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size +hir_analysis_coerce_pointee_not_concrete_ty = `derive(CoercePointee)` is only applicable to `struct` + +hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applicable to `struct`, instead of `{$kind}` + +hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout + hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 3511dbc625295..a872bb72bef1c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -48,6 +48,10 @@ pub(super) fn check_trait<'tcx>( checker .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; + checker.check( + lang_items.coerce_pointee_wellformed_trait(), + visit_implementation_of_coerce_pointee_wellformed, + )?; Ok(()) } @@ -782,3 +786,27 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err .with_note(why_disqualified) .emit()) } + +fn visit_implementation_of_coerce_pointee_wellformed( + checker: &Checker<'_>, +) -> Result<(), ErrorGuaranteed> { + let tcx = checker.tcx; + let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + let ty::Adt(def, _args) = self_ty.kind() else { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { + span: tcx.def_span(checker.impl_def_id), + })); + }; + let did = def.did(); + let span = + if let Some(local) = did.as_local() { tcx.source_span(local) } else { tcx.def_span(did) }; + if !def.is_struct() { + return Err(tcx + .dcx() + .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() })); + } + if !def.repr().transparent() { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span })); + } + Ok(()) +} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9769be302264d..a921022a1124e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1180,6 +1180,28 @@ pub(crate) struct DispatchFromDynRepr { pub span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_not_struct, code = E0802)] +pub(crate) struct CoercePointeeNotStruct { + #[primary_span] + pub span: Span, + pub kind: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_not_concrete_ty, code = E0802)] +pub(crate) struct CoercePointeeNotConcreteType { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_not_transparent, code = E0802)] +pub(crate) struct CoercePointeeNotTransparent { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)] #[help] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c819d43323583..096a438906ce2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -193,6 +193,7 @@ symbols! { Cleanup, Clone, CoercePointee, + CoercePointeeWellformed, CoerceUnsized, Command, ConstParamTy, @@ -619,6 +620,7 @@ symbols! { cmp_partialord_lt, cmpxchg16b_target_feature, cmse_nonsecure_entry, + coerce_pointee_wellformed, coerce_unsized, cold, cold_path, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1a8ef20dd7b9d..62f569d37df02 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1289,3 +1289,9 @@ pub trait FnPtr: Copy + Clone { pub macro CoercePointee($item:item) { /* compiler built-in */ } + +#[cfg(not(bootstrap))] +#[lang = "coerce_pointee_wellformed"] +#[unstable(feature = "derive_coerce_pointee", issue = "123430")] +#[doc(hidden)] +pub trait CoercePointeeWellformed {} diff --git a/tests/ui/deriving/auxiliary/malicious-macro.rs b/tests/ui/deriving/auxiliary/malicious-macro.rs new file mode 100644 index 0000000000000..6665b40a14f2b --- /dev/null +++ b/tests/ui/deriving/auxiliary/malicious-macro.rs @@ -0,0 +1,31 @@ +#![feature(let_chains)] + +extern crate proc_macro; + +use proc_macro::{Delimiter, TokenStream, TokenTree}; + +#[proc_macro_attribute] +pub fn norepr(_: TokenStream, input: TokenStream) -> TokenStream { + let mut tokens = vec![]; + let mut tts = input.into_iter().fuse().peekable(); + loop { + let Some(token) = tts.next() else { break }; + if let TokenTree::Punct(punct) = &token + && punct.as_char() == '#' + { + if let Some(TokenTree::Group(group)) = tts.peek() + && let Delimiter::Bracket = group.delimiter() + && let Some(TokenTree::Ident(ident)) = group.stream().into_iter().next() + && ident.to_string() == "repr" + { + let _ = tts.next(); + // skip '#' and '[repr(..)] + } else { + tokens.push(token); + } + } else { + tokens.push(token); + } + } + tokens.into_iter().collect() +} diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index db97c7145ea09..aa989ed231757 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -20,6 +20,8 @@ pub struct Ptr<'a, #[pointee] T: ?Sized> { data: &'a mut T, } #[automatically_derived] +impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for Ptr<'a, T> { } +#[automatically_derived] impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized> ::core::ops::DispatchFromDyn> for Ptr<'a, T> { } diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index d6eaca5cba188..ea5ee60a0bb4e 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -16,6 +16,10 @@ struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, } #[automatically_derived] +impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for + MyPointer<'a, T> { +} +#[automatically_derived] impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized> ::core::ops::DispatchFromDyn> for MyPointer<'a, T> { } @@ -31,6 +35,11 @@ pub struct MyPointer2<'a, Y, Z: MyTrait, #[pointee] T: ?Sized + MyTrait, x: core::marker::PhantomData, } #[automatically_derived] +impl<'a, Y, Z: MyTrait, T: ?Sized + MyTrait, X: MyTrait> + ::core::marker::CoercePointeeWellformed for MyPointer2<'a, Y, Z, T, X> + where Y: MyTrait { +} +#[automatically_derived] impl<'a, Y, Z: MyTrait + MyTrait<__S>, T: ?Sized + MyTrait + ::core::marker::Unsize<__S>, __S: ?Sized + MyTrait<__S>, X: MyTrait + MyTrait<__S>> ::core::ops::DispatchFromDyn> @@ -48,6 +57,10 @@ struct MyPointerWithoutPointee<'a, T: ?Sized> { ptr: &'a T, } #[automatically_derived] +impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for + MyPointerWithoutPointee<'a, T> { +} +#[automatically_derived] impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized> ::core::ops::DispatchFromDyn> for MyPointerWithoutPointee<'a, T> { diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs index da25c854c546a..0a23538cd4a66 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs @@ -1,6 +1,9 @@ +//@ proc-macro: malicious-macro.rs #![feature(derive_coerce_pointee, arbitrary_self_types)] extern crate core; +extern crate malicious_macro; + use std::marker::CoercePointee; #[derive(CoercePointee)] @@ -131,4 +134,12 @@ struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> { ptr: &'a T, } +#[derive(CoercePointee)] +#[malicious_macro::norepr] +#[repr(transparent)] +struct TryToWipeRepr<'a, #[pointee] T: ?Sized> { + //~^ ERROR: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout [E0802] + ptr: &'a T, +} + fn main() {} diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr index c1e8be49d37d3..2400a48456f5e 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr @@ -1,89 +1,89 @@ -error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-coerce-pointee-neg.rs:6:10 +error[E0802]: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-coerce-pointee-neg.rs:9:10 | LL | #[derive(CoercePointee)] | ^^^^^^^^^^^^^ | = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `CoercePointee` can only be derived on `struct`s with at least one field - --> $DIR/deriving-coerce-pointee-neg.rs:12:10 +error[E0802]: `CoercePointee` can only be derived on `struct`s with at least one field + --> $DIR/deriving-coerce-pointee-neg.rs:15:10 | LL | #[derive(CoercePointee)] | ^^^^^^^^^^^^^ | = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `CoercePointee` can only be derived on `struct`s with at least one field - --> $DIR/deriving-coerce-pointee-neg.rs:19:10 +error[E0802]: `CoercePointee` can only be derived on `struct`s with at least one field + --> $DIR/deriving-coerce-pointee-neg.rs:22:10 | LL | #[derive(CoercePointee)] | ^^^^^^^^^^^^^ | = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type - --> $DIR/deriving-coerce-pointee-neg.rs:26:10 +error[E0802]: `CoercePointee` can only be derived on `struct`s that are generic over at least one type + --> $DIR/deriving-coerce-pointee-neg.rs:29:10 | LL | #[derive(CoercePointee)] | ^^^^^^^^^^^^^ | = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) -error: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits - --> $DIR/deriving-coerce-pointee-neg.rs:31:10 +error[E0802]: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits + --> $DIR/deriving-coerce-pointee-neg.rs:34:10 | LL | #[derive(CoercePointee)] | ^^^^^^^^^^^^^ | = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) -error: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits - --> $DIR/deriving-coerce-pointee-neg.rs:40:39 +error[E0802]: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits + --> $DIR/deriving-coerce-pointee-neg.rs:43:39 | LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); | ^ - here another type parameter is marked as `#[pointee]` -error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-coerce-pointee-neg.rs:43:10 +error[E0802]: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-coerce-pointee-neg.rs:46:10 | LL | #[derive(CoercePointee)] | ^^^^^^^^^^^^^ | = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `derive(CoercePointee)` requires `T` to be marked `?Sized` - --> $DIR/deriving-coerce-pointee-neg.rs:51:36 +error[E0802]: `derive(CoercePointee)` requires `T` to be marked `?Sized` + --> $DIR/deriving-coerce-pointee-neg.rs:54:36 | LL | struct NoMaybeSized<'a, #[pointee] T> { | ^ error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-coerce-pointee-neg.rs:59:5 + --> $DIR/deriving-coerce-pointee-neg.rs:62:5 | LL | #[pointee] | ^^^^^^^^^^ error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-coerce-pointee-neg.rs:69:33 + --> $DIR/deriving-coerce-pointee-neg.rs:72:33 | LL | struct UhOh<#[pointee] T>(T); | ^^^^^^^^^^ error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-coerce-pointee-neg.rs:83:21 + --> $DIR/deriving-coerce-pointee-neg.rs:86:21 | LL | struct UhOh<#[pointee] T>(T); | ^^^^^^^^^^ error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-coerce-pointee-neg.rs:98:25 + --> $DIR/deriving-coerce-pointee-neg.rs:101:25 | LL | struct UhOh<#[pointee] T>(T); | ^^^^^^^^^^ error[E0392]: lifetime parameter `'a` is never used - --> $DIR/deriving-coerce-pointee-neg.rs:15:16 + --> $DIR/deriving-coerce-pointee-neg.rs:18:16 | LL | struct NoField<'a, #[pointee] T: ?Sized> {} | ^^ unused lifetime parameter @@ -91,7 +91,7 @@ LL | struct NoField<'a, #[pointee] T: ?Sized> {} = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: type parameter `T` is never used - --> $DIR/deriving-coerce-pointee-neg.rs:15:31 + --> $DIR/deriving-coerce-pointee-neg.rs:18:31 | LL | struct NoField<'a, #[pointee] T: ?Sized> {} | ^ unused type parameter @@ -99,7 +99,7 @@ LL | struct NoField<'a, #[pointee] T: ?Sized> {} = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: lifetime parameter `'a` is never used - --> $DIR/deriving-coerce-pointee-neg.rs:22:20 + --> $DIR/deriving-coerce-pointee-neg.rs:25:20 | LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); | ^^ unused lifetime parameter @@ -107,13 +107,23 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: type parameter `T` is never used - --> $DIR/deriving-coerce-pointee-neg.rs:22:35 + --> $DIR/deriving-coerce-pointee-neg.rs:25:35 | LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error: aborting due to 16 previous errors +error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout + --> $DIR/deriving-coerce-pointee-neg.rs:140:1 + | +LL | / struct TryToWipeRepr<'a, #[pointee] T: ?Sized> { +LL | | +LL | | ptr: &'a T, +LL | | } + | |_^ + +error: aborting due to 17 previous errors -For more information about this error, try `rustc --explain E0392`. +Some errors have detailed explanations: E0392, E0802. +For more information about an error, try `rustc --explain E0392`. From c0673246371b1a5ecac940f1ea6418857f932d7c Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Wed, 29 Jan 2025 06:15:56 +0800 Subject: [PATCH 2/6] rename the trait to validity and place a feature gate afront --- .../src/deriving/coerce_pointee.rs | 4 ++-- compiler/rustc_hir/src/lang_items.rs | 2 +- compiler/rustc_hir_analysis/messages.ftl | 2 ++ .../src/coherence/builtin.rs | 18 ++++++++++-------- compiler/rustc_hir_analysis/src/errors.rs | 7 +++++++ compiler/rustc_span/src/symbol.rs | 4 ++-- library/core/src/marker.rs | 17 +++++++++++++---- .../deriving/built-in-proc-macro-scope.stdout | 2 +- .../deriving-coerce-pointee-expanded.stdout | 6 +++--- .../deriving-coerce-pointee-neg.stderr | 7 ++----- 10 files changed, 43 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 7e30cf327fc81..e228095c97f7b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -110,10 +110,10 @@ pub(crate) fn expand_deriving_coerce_pointee( // Declare helper function that adds implementation blocks. // FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),]; - // # Wellformed-ness assertion + // # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`. { let trait_path = - cx.path_all(span, true, path!(span, core::marker::CoercePointeeWellformed), vec![]); + cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]); let trait_ref = cx.trait_ref(trait_path); push(Annotatable::Item( cx.item( diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b18e96646b18f..1852987b1677f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -370,7 +370,7 @@ language_item_table! { PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0); - CoercePointeeWellformed, sym::coerce_pointee_wellformed, coerce_pointee_wellformed_trait, Target::Trait, GenericRequirement::Exact(0); + CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0); ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 2417ff3bb1a1f..9c38193c84e38 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -85,6 +85,8 @@ hir_analysis_cmse_output_stack_spill = .note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size +hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden + hir_analysis_coerce_pointee_not_concrete_ty = `derive(CoercePointee)` is only applicable to `struct` hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applicable to `struct`, instead of `{$kind}` diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index a872bb72bef1c..c21576a5e7ca1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -49,8 +49,8 @@ pub(super) fn check_trait<'tcx>( .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; checker.check( - lang_items.coerce_pointee_wellformed_trait(), - visit_implementation_of_coerce_pointee_wellformed, + lang_items.coerce_pointee_validated_trait(), + visit_implementation_of_coerce_pointee_validity, )?; Ok(()) } @@ -787,19 +787,21 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err .emit()) } -fn visit_implementation_of_coerce_pointee_wellformed( +fn visit_implementation_of_coerce_pointee_validity( checker: &Checker<'_>, ) -> Result<(), ErrorGuaranteed> { let tcx = checker.tcx; let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + let span = tcx.def_span(checker.impl_def_id); + if !tcx.is_builtin_derived(checker.impl_def_id.into()) { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span })); + } let ty::Adt(def, _args) = self_ty.kind() else { - return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { - span: tcx.def_span(checker.impl_def_id), - })); + return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span })); }; let did = def.did(); - let span = - if let Some(local) = did.as_local() { tcx.source_span(local) } else { tcx.def_span(did) }; + // Now get a more precise span of the `struct`. + let span = tcx.def_span(did); if !def.is_struct() { return Err(tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a921022a1124e..c49e06d7448e2 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1195,6 +1195,13 @@ pub(crate) struct CoercePointeeNotConcreteType { pub span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_no_user_validity_assertion, code = E0802)] +pub(crate) struct CoercePointeeNoUserValidityAssertion { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_coerce_pointee_not_transparent, code = E0802)] pub(crate) struct CoercePointeeNotTransparent { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 096a438906ce2..1601577669714 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -193,7 +193,7 @@ symbols! { Cleanup, Clone, CoercePointee, - CoercePointeeWellformed, + CoercePointeeValidated, CoerceUnsized, Command, ConstParamTy, @@ -620,7 +620,7 @@ symbols! { cmp_partialord_lt, cmpxchg16b_target_feature, cmse_nonsecure_entry, - coerce_pointee_wellformed, + coerce_pointee_validated, coerce_unsized, cold, cold_path, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 62f569d37df02..163c80ffe1d1f 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1284,14 +1284,23 @@ pub trait FnPtr: Copy + Clone { /// } /// ``` #[rustc_builtin_macro(CoercePointee, attributes(pointee))] -#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] +#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] pub macro CoercePointee($item:item) { /* compiler built-in */ } +/// A validation trait that is implemented on data with `derive(CoercePointee)` +/// so that the compiler can enforce a set of rules that the target data must +/// conform to in order for the derived behaviours are safe and useful for +/// the purpose of the said macro. +/// +/// This trait will not ever be exposed for use as public part of the library +/// and shall not ever be stabilised. #[cfg(not(bootstrap))] -#[lang = "coerce_pointee_wellformed"] -#[unstable(feature = "derive_coerce_pointee", issue = "123430")] +#[lang = "coerce_pointee_validated"] +#[unstable(feature = "coerce_pointee_validated", issue = "123430")] #[doc(hidden)] -pub trait CoercePointeeWellformed {} +pub trait CoercePointeeValidated { + /* compiler built-in */ +} diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index aa989ed231757..fa4e50968f4de 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -20,7 +20,7 @@ pub struct Ptr<'a, #[pointee] T: ?Sized> { data: &'a mut T, } #[automatically_derived] -impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for Ptr<'a, T> { } +impl<'a, T: ?Sized> ::core::marker::CoercePointeeValidated for Ptr<'a, T> { } #[automatically_derived] impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized> ::core::ops::DispatchFromDyn> for Ptr<'a, T> { diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index ea5ee60a0bb4e..a774efbbe354b 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -16,7 +16,7 @@ struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, } #[automatically_derived] -impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for +impl<'a, T: ?Sized> ::core::marker::CoercePointeeValidated for MyPointer<'a, T> { } #[automatically_derived] @@ -36,7 +36,7 @@ pub struct MyPointer2<'a, Y, Z: MyTrait, #[pointee] T: ?Sized + MyTrait, } #[automatically_derived] impl<'a, Y, Z: MyTrait, T: ?Sized + MyTrait, X: MyTrait> - ::core::marker::CoercePointeeWellformed for MyPointer2<'a, Y, Z, T, X> + ::core::marker::CoercePointeeValidated for MyPointer2<'a, Y, Z, T, X> where Y: MyTrait { } #[automatically_derived] @@ -57,7 +57,7 @@ struct MyPointerWithoutPointee<'a, T: ?Sized> { ptr: &'a T, } #[automatically_derived] -impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for +impl<'a, T: ?Sized> ::core::marker::CoercePointeeValidated for MyPointerWithoutPointee<'a, T> { } #[automatically_derived] diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr index 2400a48456f5e..9e4d36572247b 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr @@ -117,11 +117,8 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout --> $DIR/deriving-coerce-pointee-neg.rs:140:1 | -LL | / struct TryToWipeRepr<'a, #[pointee] T: ?Sized> { -LL | | -LL | | ptr: &'a T, -LL | | } - | |_^ +LL | struct TryToWipeRepr<'a, #[pointee] T: ?Sized> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 17 previous errors From b9435056a7e152e1d455b404061240b964a39584 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Wed, 29 Jan 2025 06:48:28 +0800 Subject: [PATCH 3/6] move repr(transparent) checks to coherence --- .../src/deriving/coerce_pointee.rs | 10 ---------- compiler/rustc_hir_analysis/messages.ftl | 2 ++ .../rustc_hir_analysis/src/coherence/builtin.rs | 3 +++ compiler/rustc_hir_analysis/src/errors.rs | 7 +++++++ tests/ui/deriving/deriving-coerce-pointee-neg.rs | 2 +- .../ui/deriving/deriving-coerce-pointee-neg.stderr | 14 ++++++-------- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index e228095c97f7b..5aed9f76f144f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -6,7 +6,6 @@ use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem, TraitBoundModifiers, VariantData, WherePredicate, }; -use rustc_attr_parsing as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::E0802; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -33,15 +32,6 @@ pub(crate) fn expand_deriving_coerce_pointee( let (name_ident, generics) = if let Annotatable::Item(aitem) = item && let ItemKind::Struct(struct_data, g) = &aitem.kind { - let is_transparent = aitem.attrs.iter().any(|attr| { - attr::find_repr_attrs(cx.sess, attr) - .into_iter() - .any(|r| matches!(r, attr::ReprTransparent)) - }); - if !is_transparent { - cx.dcx().emit_err(RequireTransparent { span }); - return; - } if !matches!( struct_data, VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 9c38193c84e38..258267c5ca929 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -85,6 +85,8 @@ hir_analysis_cmse_output_stack_spill = .note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size +hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field + hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden hir_analysis_coerce_pointee_not_concrete_ty = `derive(CoercePointee)` is only applicable to `struct` diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index c21576a5e7ca1..c5aee60117b95 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -810,5 +810,8 @@ fn visit_implementation_of_coerce_pointee_validity( if !def.repr().transparent() { return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span })); } + if def.all_fields().next().is_none() { + return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span })); + } Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c49e06d7448e2..12750543f4bf7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1209,6 +1209,13 @@ pub(crate) struct CoercePointeeNotTransparent { pub span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_coerce_pointee_no_field, code = E0802)] +pub(crate) struct CoercePointeeNoField { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)] #[help] diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs index 0a23538cd4a66..6577500d8eb0f 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs @@ -44,8 +44,8 @@ struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, & //~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits #[derive(CoercePointee)] -//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` struct NotTransparent<'a, #[pointee] T: ?Sized> { + //~^ ERROR: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout ptr: &'a T, } diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr index 9e4d36572247b..999214bfa9fe3 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr @@ -44,14 +44,6 @@ error[E0802]: only one type parameter can be marked as `#[pointee]` when derivin LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); | ^ - here another type parameter is marked as `#[pointee]` -error[E0802]: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-coerce-pointee-neg.rs:46:10 - | -LL | #[derive(CoercePointee)] - | ^^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0802]: `derive(CoercePointee)` requires `T` to be marked `?Sized` --> $DIR/deriving-coerce-pointee-neg.rs:54:36 | @@ -114,6 +106,12 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` +error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout + --> $DIR/deriving-coerce-pointee-neg.rs:47:1 + | +LL | struct NotTransparent<'a, #[pointee] T: ?Sized> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout --> $DIR/deriving-coerce-pointee-neg.rs:140:1 | From 18483434ae377d215fa87c890cbf26884f3fae5c Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 10 Feb 2025 04:36:43 +0800 Subject: [PATCH 4/6] block coerce_pointee_validated for stabilization --- library/core/src/marker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 163c80ffe1d1f..3dbedac166be3 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1299,7 +1299,7 @@ pub macro CoercePointee($item:item) { /// and shall not ever be stabilised. #[cfg(not(bootstrap))] #[lang = "coerce_pointee_validated"] -#[unstable(feature = "coerce_pointee_validated", issue = "123430")] +#[unstable(feature = "coerce_pointee_validated", issue = "none")] #[doc(hidden)] pub trait CoercePointeeValidated { /* compiler built-in */ From aea5595c8613425c74791586b4c7fcff017fc14e Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 10 Feb 2025 03:02:13 +0800 Subject: [PATCH 5/6] fix the error code document --- .../rustc_error_codes/src/error_codes/E0802.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_error_codes/src/error_codes/E0802.md b/compiler/rustc_error_codes/src/error_codes/E0802.md index 9088b100886d3..59061ff04359d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0802.md +++ b/compiler/rustc_error_codes/src/error_codes/E0802.md @@ -6,6 +6,8 @@ Erroneous code examples: The target data is not a `struct`. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] enum NotStruct<'a, T: ?Sized> { Variant(&'a T), @@ -16,6 +18,8 @@ The target data has a layout that is not transparent, or `repr(transparent)` in other words. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] struct NotTransparent<'a, #[pointee] T: ?Sized> { ptr: &'a T, @@ -25,6 +29,8 @@ struct NotTransparent<'a, #[pointee] T: ?Sized> { The target data has no data field. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] #[repr(transparent)] struct NoField<'a, #[pointee] T: ?Sized> {} @@ -33,6 +39,8 @@ struct NoField<'a, #[pointee] T: ?Sized> {} The target data is not generic over any data, or has no generic type parameter. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] #[repr(transparent)] struct NoGeneric<'a>(&'a u8); @@ -42,6 +50,8 @@ The target data has multiple generic type parameters, but none is designated as a pointee for coercion. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] #[repr(transparent)] struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> { @@ -53,6 +63,8 @@ The target data has multiple generic type parameters that are designated as pointees for coercion. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] #[repr(transparent)] struct TooManyPointees< @@ -65,6 +77,8 @@ struct TooManyPointees< The type parameter that is designated as a pointee is not marked `?Sized`. ```compile_fail,E0802 +#![feature(coerce_pointee)] +use std::marker::CoercePointee; #[derive(CoercePointee)] #[repr(transparent)] struct NoMaybeSized<'a, #[pointee] T> { From 17026e24120a8c958b2d742b498fdb83d1314d59 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Feb 2025 11:50:02 -0500 Subject: [PATCH 6/6] Reword doc comment on `CoercePointeeValidated` --- library/core/src/marker.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 3dbedac166be3..029c8b356d074 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1290,13 +1290,12 @@ pub macro CoercePointee($item:item) { /* compiler built-in */ } -/// A validation trait that is implemented on data with `derive(CoercePointee)` -/// so that the compiler can enforce a set of rules that the target data must -/// conform to in order for the derived behaviours are safe and useful for -/// the purpose of the said macro. +/// A trait that is implemented for ADTs with `derive(CoercePointee)` so that +/// the compiler can enforce the derive impls are valid post-expansion, since +/// the derive has stricter requirements than if the impls were written by hand. /// -/// This trait will not ever be exposed for use as public part of the library -/// and shall not ever be stabilised. +/// This trait is not intended to be implemented by users or used other than +/// validation, so it should never be stabilized. #[cfg(not(bootstrap))] #[lang = "coerce_pointee_validated"] #[unstable(feature = "coerce_pointee_validated", issue = "none")]