Skip to content

Commit ed460d2

Browse files
Rollup merge of #125575 - dingxiangfei2009:derive-smart-ptr, r=davidtwco
SmartPointer derive-macro <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r​? <reviewer name> --> Possibly replacing #123472 for continued upkeep of the proposal rust-lang/rfcs#3621 and implementation of the tracking issue #123430. cc `@Darksonn` `@wedsonaf`
2 parents c77dc28 + f1be59f commit ed460d2

10 files changed

Lines changed: 264 additions & 0 deletions

File tree

‎compiler/rustc_builtin_macros/src/deriving/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub(crate) mod decodable;
2727
pub(crate)mod default;
2828
pub(crate)mod encodable;
2929
pub(crate)mod hash;
30+
pub(crate)mod smart_ptr;
3031

3132
#[path = "cmp/eq.rs"]
3233
pub(crate)mod eq;
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
use std::mem::swap;
2+
3+
use ast::HasAttrs;
4+
use rustc_ast::{
5+
selfas ast,GenericArg,GenericBound,GenericParamKind,ItemKind,MetaItem,
6+
TraitBoundModifiers,
7+
};
8+
use rustc_expand::base::{Annotatable,ExtCtxt};
9+
use rustc_span::symbol::{sym,Ident};
10+
use rustc_span::Span;
11+
use smallvec::{smallvec,SmallVec};
12+
use thin_vec::{thin_vec,ThinVec};
13+
14+
macro_rules! path {
15+
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*]}
16+
}
17+
18+
pubfnexpand_deriving_smart_ptr(
19+
cx:&ExtCtxt<'_>,
20+
span:Span,
21+
_mitem:&MetaItem,
22+
item:&Annotatable,
23+
push:&mutdynFnMut(Annotatable),
24+
_is_const:bool,
25+
){
26+
let(name_ident, generics) = ifletAnnotatable::Item(aitem) = item
27+
&& letItemKind::Struct(_, g) = &aitem.kind
28+
{
29+
(aitem.ident, g)
30+
}else{
31+
cx.dcx().struct_span_err(span,"`SmartPointer` can only be derived on `struct`s").emit();
32+
return;
33+
};
34+
35+
// Convert generic parameters (from the struct) into generic args.
36+
letmut pointee_param = None;
37+
letmut multiple_pointee_diag:SmallVec<[_;2]> = smallvec![];
38+
let self_params = generics
39+
.params
40+
.iter()
41+
.enumerate()
42+
.map(|(idx, p)| match p.kind{
43+
GenericParamKind::Lifetime => GenericArg::Lifetime(cx.lifetime(p.span(), p.ident)),
44+
GenericParamKind::Type{ .. } => {
45+
if p.attrs().iter().any(|attr| attr.has_name(sym::pointee)){
46+
if pointee_param.is_some(){
47+
multiple_pointee_diag.push(cx.dcx().struct_span_err(
48+
p.span(),
49+
"`SmartPointer` can only admit one type as pointee",
50+
));
51+
}else{
52+
pointee_param = Some(idx);
53+
}
54+
}
55+
GenericArg::Type(cx.ty_ident(p.span(), p.ident))
56+
}
57+
GenericParamKind::Const{ .. } => GenericArg::Const(cx.const_ident(p.span(), p.ident)),
58+
})
59+
.collect::<Vec<_>>();
60+
letSome(pointee_param_idx) = pointee_param else{
61+
cx.dcx().struct_span_err(
62+
span,
63+
"At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
64+
).emit();
65+
return;
66+
};
67+
if !multiple_pointee_diag.is_empty(){
68+
for diag in multiple_pointee_diag {
69+
diag.emit();
70+
}
71+
return;
72+
}
73+
74+
// Create the type of `self`.
75+
let path = cx.path_all(span,false,vec![name_ident], self_params.clone());
76+
let self_type = cx.ty_path(path);
77+
78+
// Declare helper function that adds implementation blocks.
79+
// FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls
80+
let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),];
81+
letmut add_impl_block = |generics, trait_symbol, trait_args| {
82+
letmut parts = path!(span, core::ops);
83+
parts.push(Ident::new(trait_symbol, span));
84+
let trait_path = cx.path_all(span,true, parts, trait_args);
85+
let trait_ref = cx.trait_ref(trait_path);
86+
let item = cx.item(
87+
span,
88+
Ident::empty(),
89+
attrs.clone(),
90+
ast::ItemKind::Impl(Box::new(ast::Impl{
91+
safety: ast::Safety::Default,
92+
polarity: ast::ImplPolarity::Positive,
93+
defaultness: ast::Defaultness::Final,
94+
constness: ast::Const::No,
95+
generics,
96+
of_trait:Some(trait_ref),
97+
self_ty: self_type.clone(),
98+
items:ThinVec::new(),
99+
})),
100+
);
101+
push(Annotatable::Item(item));
102+
};
103+
104+
// Create unsized `self`, that is, one where the `#[pointee]` type arg is replaced with `__S`. For
105+
// example, instead of `MyType<'a, T>`, it will be `MyType<'a, __S>`.
106+
let s_ty = cx.ty_ident(span,Ident::new(sym::__S, span));
107+
letmut alt_self_params = self_params;
108+
alt_self_params[pointee_param_idx] = GenericArg::Type(s_ty.clone());
109+
let alt_self_type = cx.ty_path(cx.path_all(span,false,vec![name_ident], alt_self_params));
110+
111+
// Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
112+
letmut impl_generics = generics.clone();
113+
{
114+
let p = &mut impl_generics.params[pointee_param_idx];
115+
let arg = GenericArg::Type(s_ty.clone());
116+
let unsize = cx.path_all(span,true,path!(span, core::marker::Unsize),vec![arg]);
117+
p.bounds.push(cx.trait_bound(unsize,false));
118+
letmut attrs = thin_vec![];
119+
swap(&mut p.attrs,&mut attrs);
120+
p.attrs = attrs.into_iter().filter(|attr| !attr.has_name(sym::pointee)).collect();
121+
}
122+
123+
// Add the `__S: ?Sized` extra parameter to the impl block.
124+
let sized = cx.path_global(span,path!(span, core::marker::Sized));
125+
let bound = GenericBound::Trait(
126+
cx.poly_trait_ref(span, sized),
127+
TraitBoundModifiers{
128+
polarity: ast::BoundPolarity::Maybe(span),
129+
constness: ast::BoundConstness::Never,
130+
asyncness: ast::BoundAsyncness::Normal,
131+
},
132+
);
133+
let extra_param = cx.typaram(span,Ident::new(sym::__S, span),vec![bound],None);
134+
impl_generics.params.push(extra_param);
135+
136+
// Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`.
137+
let gen_args = vec![GenericArg::Type(alt_self_type.clone())];
138+
add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone());
139+
add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone());
140+
}

‎compiler/rustc_builtin_macros/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
127127
PartialOrd: partial_ord::expand_deriving_partial_ord,
128128
RustcDecodable: decodable::expand_deriving_rustc_decodable,
129129
RustcEncodable: encodable::expand_deriving_rustc_encodable,
130+
SmartPointer: smart_ptr::expand_deriving_smart_ptr,
130131
}
131132

132133
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);

‎compiler/rustc_feature/src/builtin_attrs.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
575575
EncodeCrossCrate::No, coroutines, experimental!(coroutines)
576576
),
577577

578+
// `#[pointee]` attribute to designate the pointee type in SmartPointer derive-macro
579+
gated!(
580+
pointee,Normal, template!(Word),ErrorFollowing,
581+
EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee)
582+
),
583+
578584
// ==========================================================================
579585
// Internal attributes: Stability, deprecation, and unsafe:
580586
// ==========================================================================

‎compiler/rustc_feature/src/unstable.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,8 @@ declare_features! (
436436
(unstable, deprecated_suggestion,"1.61.0",Some(94785)),
437437
/// Allows deref patterns.
438438
(incomplete, deref_patterns,"1.79.0",Some(87121)),
439+
/// Allows deriving `SmartPointer` traits
440+
(unstable, derive_smart_pointer,"1.79.0",Some(123430)),
439441
/// Controls errors in trait implementations.
440442
(unstable, do_not_recommend,"1.67.0",Some(51992)),
441443
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.

‎compiler/rustc_span/src/symbol.rs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ symbols! {
174174
Center,
175175
Cleanup,
176176
Clone,
177+
CoerceUnsized,
177178
Command,
178179
ConstParamTy,
179180
Context,
@@ -189,6 +190,7 @@ symbols! {
189190
DiagMessage,
190191
Diagnostic,
191192
DirBuilder,
193+
DispatchFromDyn,
192194
Display,
193195
DoubleEndedIterator,
194196
Duration,
@@ -299,8 +301,10 @@ symbols! {
299301
Saturating,
300302
Send,
301303
SeqCst,
304+
Sized,
302305
SliceIndex,
303306
SliceIter,
307+
SmartPointer,
304308
Some,
305309
SpanCtxt,
306310
String,
@@ -323,6 +327,7 @@ symbols! {
323327
TyCtxt,
324328
TyKind,
325329
Unknown,
330+
Unsize,
326331
Upvars,
327332
Vec,
328333
VecDeque,
@@ -707,6 +712,7 @@ symbols! {
707712
derive,
708713
derive_const,
709714
derive_default_enum,
715+
derive_smart_pointer,
710716
destruct,
711717
destructuring_assignment,
712718
diagnostic,
@@ -1315,6 +1321,7 @@ symbols! {
13151321
on,
13161322
on_unimplemented,
13171323
opaque,
1324+
ops,
13181325
opt_out_copy,
13191326
optimize,
13201327
optimize_attribute,
@@ -1389,6 +1396,7 @@ symbols! {
13891396
plugin,
13901397
plugin_registrar,
13911398
plugins,
1399+
pointee,
13921400
pointee_trait,
13931401
pointer,
13941402
pointer_like,

‎library/core/src/marker.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,3 +1018,12 @@ pub trait FnPtr: Copy + Clone {
10181018
#[lang = "fn_ptr_addr"]
10191019
fnaddr(self) -> *const();
10201020
}
1021+
1022+
/// Derive macro generating impls of traits related to smart pointers.
1023+
#[cfg(not(bootstrap))]
1024+
#[rustc_builtin_macro]
1025+
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
1026+
#[unstable(feature = "derive_smart_pointer", issue = "123430")]
1027+
pub macro SmartPointer($item:item){
1028+
/* compiler built-in */
1029+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@ run-pass
2+
#![feature(derive_smart_pointer, arbitrary_self_types)]
3+
4+
use std::marker::SmartPointer;
5+
6+
#[derive(SmartPointer)]
7+
structMyPointer<'a,#[pointee]T: ?Sized>{
8+
ptr:&'aT,
9+
}
10+
11+
impl<T: ?Sized>CopyforMyPointer<'_,T>{}
12+
impl<T: ?Sized>CloneforMyPointer<'_,T>{
13+
fnclone(&self) -> Self{
14+
Self{ptr:self.ptr}
15+
}
16+
}
17+
18+
impl<'a,T: ?Sized> core::ops::DerefforMyPointer<'a,T>{
19+
typeTarget = T;
20+
fnderef(&self) -> &'aT{
21+
self.ptr
22+
}
23+
}
24+
25+
structMyValue(u32);
26+
implMyValue{
27+
fnthrough_pointer(self:MyPointer<'_,Self>) -> u32{
28+
self.ptr.0
29+
}
30+
}
31+
32+
traitMyTrait{
33+
fnthrough_trait(&self) -> u32;
34+
fnthrough_trait_and_pointer(self:MyPointer<'_,Self>) -> u32;
35+
}
36+
37+
implMyTraitforMyValue{
38+
fnthrough_trait(&self) -> u32{
39+
self.0
40+
}
41+
42+
fnthrough_trait_and_pointer(self:MyPointer<'_,Self>) -> u32{
43+
self.ptr.0
44+
}
45+
}
46+
47+
pubfnmain(){
48+
let v = MyValue(10);
49+
let ptr = MyPointer{ptr:&v };
50+
assert_eq!(v.0, ptr.through_pointer());
51+
assert_eq!(v.0, ptr.through_pointer());
52+
let dptr = ptr asMyPointer<dynMyTrait>;
53+
assert_eq!(v.0, dptr.through_trait());
54+
assert_eq!(v.0, dptr.through_trait_and_pointer());
55+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use std::marker::SmartPointer;//~ ERROR use of unstable library feature 'derive_smart_pointer'
2+
3+
#[derive(SmartPointer)]//~ ERROR use of unstable library feature 'derive_smart_pointer'
4+
structMyPointer<'a,#[pointee]T: ?Sized>{
5+
//~^ ERROR the `#[pointee]` attribute is an experimental feature
6+
ptr:&'aT,
7+
}
8+
9+
fnmain(){}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0658]: use of unstable library feature 'derive_smart_pointer'
2+
--> $DIR/feature-gate-derive-smart-pointer.rs:3:10
3+
|
4+
LL | #[derive(SmartPointer)]
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
8+
= help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: the `#[pointee]` attribute is an experimental feature
12+
--> $DIR/feature-gate-derive-smart-pointer.rs:4:22
13+
|
14+
LL | struct MyPointer<'a, #[pointee] T: ?Sized> {
15+
| ^^^^^^^^^^
16+
|
17+
= note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
18+
= help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error[E0658]: use of unstable library feature 'derive_smart_pointer'
22+
--> $DIR/feature-gate-derive-smart-pointer.rs:1:5
23+
|
24+
LL | use std::marker::SmartPointer;
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
28+
= help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
29+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
30+
31+
error: aborting due to 3 previous errors
32+
33+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)