Rollup merge of #134140 - compiler-errors:unsafe-binders-ast, r=oli-obk
Add AST support for unsafe binders I'm splitting up #130514 into pieces. It's impossible for me to keep up with a huge PR like that. I'll land type system support for this next, probably w/o MIR lowering, which will come later. r? `@oli-obk` cc `@BoxyUwU` and `@lcnr` who also may want to look at this, though this PR doesn't do too much yet
This commit is contained in:
commit
5c9b227a3d
53 changed files with 616 additions and 18 deletions
|
@ -1382,6 +1382,7 @@ impl Expr {
|
||||||
| ExprKind::Tup(_)
|
| ExprKind::Tup(_)
|
||||||
| ExprKind::Type(..)
|
| ExprKind::Type(..)
|
||||||
| ExprKind::Underscore
|
| ExprKind::Underscore
|
||||||
|
| ExprKind::UnsafeBinderCast(..)
|
||||||
| ExprKind::While(..)
|
| ExprKind::While(..)
|
||||||
| ExprKind::Err(_)
|
| ExprKind::Err(_)
|
||||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||||
|
@ -1509,7 +1510,13 @@ pub enum ExprKind {
|
||||||
/// `'label: for await? pat in iter { block }`
|
/// `'label: for await? pat in iter { block }`
|
||||||
///
|
///
|
||||||
/// This is desugared to a combination of `loop` and `match` expressions.
|
/// This is desugared to a combination of `loop` and `match` expressions.
|
||||||
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
|
ForLoop {
|
||||||
|
pat: P<Pat>,
|
||||||
|
iter: P<Expr>,
|
||||||
|
body: P<Block>,
|
||||||
|
label: Option<Label>,
|
||||||
|
kind: ForLoopKind,
|
||||||
|
},
|
||||||
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
|
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||||
///
|
///
|
||||||
/// `'label: loop { block }`
|
/// `'label: loop { block }`
|
||||||
|
@ -1614,6 +1621,8 @@ pub enum ExprKind {
|
||||||
/// A `format_args!()` expression.
|
/// A `format_args!()` expression.
|
||||||
FormatArgs(P<FormatArgs>),
|
FormatArgs(P<FormatArgs>),
|
||||||
|
|
||||||
|
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
|
||||||
|
|
||||||
/// Placeholder for an expression that wasn't syntactically well formed in some way.
|
/// Placeholder for an expression that wasn't syntactically well formed in some way.
|
||||||
Err(ErrorGuaranteed),
|
Err(ErrorGuaranteed),
|
||||||
|
|
||||||
|
@ -1652,6 +1661,16 @@ impl GenBlockKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether we're unwrapping or wrapping an unsafe binder
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||||
|
pub enum UnsafeBinderCastKind {
|
||||||
|
// e.g. `&i32` -> `unsafe<'a> &'a i32`
|
||||||
|
Wrap,
|
||||||
|
// e.g. `unsafe<'a> &'a i32` -> `&i32`
|
||||||
|
Unwrap,
|
||||||
|
}
|
||||||
|
|
||||||
/// The explicit `Self` type in a "qualified path". The actual
|
/// The explicit `Self` type in a "qualified path". The actual
|
||||||
/// path, including the trait and the associated item, is stored
|
/// path, including the trait and the associated item, is stored
|
||||||
/// separately. `position` represents the index of the associated
|
/// separately. `position` represents the index of the associated
|
||||||
|
@ -2223,6 +2242,12 @@ pub struct BareFnTy {
|
||||||
pub decl_span: Span,
|
pub decl_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
|
pub struct UnsafeBinderTy {
|
||||||
|
pub generic_params: ThinVec<GenericParam>,
|
||||||
|
pub inner_ty: P<Ty>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The various kinds of type recognized by the compiler.
|
/// The various kinds of type recognized by the compiler.
|
||||||
//
|
//
|
||||||
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
|
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
|
||||||
|
@ -2242,6 +2267,8 @@ pub enum TyKind {
|
||||||
PinnedRef(Option<Lifetime>, MutTy),
|
PinnedRef(Option<Lifetime>, MutTy),
|
||||||
/// A bare function (e.g., `fn(usize) -> bool`).
|
/// A bare function (e.g., `fn(usize) -> bool`).
|
||||||
BareFn(P<BareFnTy>),
|
BareFn(P<BareFnTy>),
|
||||||
|
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
|
||||||
|
UnsafeBinder(P<UnsafeBinderTy>),
|
||||||
/// The never type (`!`).
|
/// The never type (`!`).
|
||||||
Never,
|
Never,
|
||||||
/// A tuple (`(A, B, C, D,...)`).
|
/// A tuple (`(A, B, C, D,...)`).
|
||||||
|
|
|
@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
||||||
vis.visit_fn_decl(decl);
|
vis.visit_fn_decl(decl);
|
||||||
vis.visit_span(decl_span);
|
vis.visit_span(decl_span);
|
||||||
}
|
}
|
||||||
|
TyKind::UnsafeBinder(binder) => {
|
||||||
|
let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut();
|
||||||
|
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||||
|
vis.visit_ty(inner_ty);
|
||||||
|
}
|
||||||
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
|
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
|
||||||
TyKind::Paren(ty) => vis.visit_ty(ty),
|
TyKind::Paren(ty) => vis.visit_ty(ty),
|
||||||
TyKind::Pat(ty, pat) => {
|
TyKind::Pat(ty, pat) => {
|
||||||
|
@ -1780,6 +1785,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
||||||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||||
ExprKind::Lit(_token) => {}
|
ExprKind::Lit(_token) => {}
|
||||||
ExprKind::IncludedBytes(_bytes) => {}
|
ExprKind::IncludedBytes(_bytes) => {}
|
||||||
|
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||||
|
vis.visit_expr(expr);
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
vis.visit_ty(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
ExprKind::Err(_guar) => {}
|
ExprKind::Err(_guar) => {}
|
||||||
ExprKind::Dummy => {}
|
ExprKind::Dummy => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
|
||||||
| Underscore
|
| Underscore
|
||||||
| Yeet(..)
|
| Yeet(..)
|
||||||
| Yield(..)
|
| Yield(..)
|
||||||
|
| UnsafeBinderCast(..)
|
||||||
| Err(..)
|
| Err(..)
|
||||||
| Dummy => return false,
|
| Dummy => return false,
|
||||||
}
|
}
|
||||||
|
@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||||
| Paren(_)
|
| Paren(_)
|
||||||
| Try(_)
|
| Try(_)
|
||||||
| Yeet(None)
|
| Yeet(None)
|
||||||
|
| UnsafeBinderCast(..)
|
||||||
| Err(_)
|
| Err(_)
|
||||||
| Dummy => break None,
|
| Dummy => break None,
|
||||||
}
|
}
|
||||||
|
@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
||||||
ty = &mut_ty.ty;
|
ty = &mut_ty.ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::TyKind::UnsafeBinder(binder) => {
|
||||||
|
ty = &binder.inner_ty;
|
||||||
|
}
|
||||||
|
|
||||||
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
||||||
ast::FnRetTy::Default(_) => break None,
|
ast::FnRetTy::Default(_) => break None,
|
||||||
ast::FnRetTy::Ty(ret) => ty = ret,
|
ast::FnRetTy::Ty(ret) => ty = ret,
|
||||||
|
|
|
@ -522,6 +522,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
||||||
walk_list!(visitor, visit_generic_param, generic_params);
|
walk_list!(visitor, visit_generic_param, generic_params);
|
||||||
try_visit!(visitor.visit_fn_decl(decl));
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
}
|
}
|
||||||
|
TyKind::UnsafeBinder(binder) => {
|
||||||
|
walk_list!(visitor, visit_generic_param, &binder.generic_params);
|
||||||
|
try_visit!(visitor.visit_ty(&binder.inner_ty));
|
||||||
|
}
|
||||||
TyKind::Path(maybe_qself, path) => {
|
TyKind::Path(maybe_qself, path) => {
|
||||||
try_visit!(visitor.visit_qself(maybe_qself));
|
try_visit!(visitor.visit_qself(maybe_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
|
@ -1226,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||||
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
|
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
|
||||||
ExprKind::Lit(_token) => {}
|
ExprKind::Lit(_token) => {}
|
||||||
ExprKind::IncludedBytes(_bytes) => {}
|
ExprKind::IncludedBytes(_bytes) => {}
|
||||||
|
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||||
|
try_visit!(visitor.visit_expr(expr));
|
||||||
|
visit_opt!(visitor, visit_ty, ty);
|
||||||
|
}
|
||||||
ExprKind::Err(_guar) => {}
|
ExprKind::Err(_guar) => {}
|
||||||
ExprKind::Dummy => {}
|
ExprKind::Dummy => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||||
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
||||||
|
|
||||||
|
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
|
||||||
|
*kind,
|
||||||
|
self.lower_expr(expr),
|
||||||
|
ty.as_ref().map(|ty| {
|
||||||
|
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
ExprKind::Dummy => {
|
ExprKind::Dummy => {
|
||||||
span_bug!(e.span, "lowered ExprKind::Dummy")
|
span_bug!(e.span, "lowered ExprKind::Dummy")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
param_names: self.lower_fn_params_to_names(&f.decl),
|
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
TyKind::UnsafeBinder(f) => {
|
||||||
|
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||||
|
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
||||||
|
generic_params,
|
||||||
|
inner_ty: self.lower_ty(&f.inner_ty, itctx),
|
||||||
|
}))
|
||||||
|
}
|
||||||
TyKind::Never => hir::TyKind::Never,
|
TyKind::Never => hir::TyKind::Never,
|
||||||
TyKind::Tup(tys) => hir::TyKind::Tup(
|
TyKind::Tup(tys) => hir::TyKind::Tup(
|
||||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
||||||
|
|
|
@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(return_type_notation, "return type notation is experimental");
|
gate_all!(return_type_notation, "return type notation is experimental");
|
||||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||||
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
|
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
|
||||||
|
gate_all!(unsafe_binders, "unsafe binder types are experimental");
|
||||||
|
|
||||||
if !visitor.features.never_patterns() {
|
if !visitor.features.never_patterns() {
|
||||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||||
|
|
|
@ -1198,6 +1198,14 @@ impl<'a> State<'a> {
|
||||||
ast::TyKind::BareFn(f) => {
|
ast::TyKind::BareFn(f) => {
|
||||||
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
|
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
|
||||||
}
|
}
|
||||||
|
ast::TyKind::UnsafeBinder(f) => {
|
||||||
|
self.ibox(INDENT_UNIT);
|
||||||
|
self.word("unsafe");
|
||||||
|
self.print_generic_params(&f.generic_params);
|
||||||
|
self.nbsp();
|
||||||
|
self.print_type(&f.inner_ty);
|
||||||
|
self.end();
|
||||||
|
}
|
||||||
ast::TyKind::Path(None, path) => {
|
ast::TyKind::Path(None, path) => {
|
||||||
self.print_path(path, false, 0);
|
self.print_path(path, false, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -772,6 +772,25 @@ impl<'a> State<'a> {
|
||||||
self.word_nbsp("try");
|
self.word_nbsp("try");
|
||||||
self.print_block_with_attrs(blk, attrs)
|
self.print_block_with_attrs(blk, attrs)
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||||
|
self.word("builtin # ");
|
||||||
|
match kind {
|
||||||
|
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"),
|
||||||
|
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
|
||||||
|
}
|
||||||
|
self.popen();
|
||||||
|
self.ibox(0);
|
||||||
|
self.print_expr(expr, FixupContext::default());
|
||||||
|
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
self.word(",");
|
||||||
|
self.space();
|
||||||
|
self.print_type(ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.end();
|
||||||
|
self.pclose();
|
||||||
|
}
|
||||||
ast::ExprKind::Err(_) => {
|
ast::ExprKind::Err(_) => {
|
||||||
self.popen();
|
self.popen();
|
||||||
self.word("/*ERROR*/");
|
self.word("/*ERROR*/");
|
||||||
|
|
|
@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||||
| ExprKind::While(_, _, _)
|
| ExprKind::While(_, _, _)
|
||||||
| ExprKind::Yeet(_)
|
| ExprKind::Yeet(_)
|
||||||
| ExprKind::Become(_)
|
| ExprKind::Become(_)
|
||||||
| ExprKind::Yield(_) => {}
|
| ExprKind::Yield(_)
|
||||||
|
| ExprKind::UnsafeBinderCast(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -635,6 +635,8 @@ declare_features! (
|
||||||
/// Allows creation of instances of a struct by moving fields that have
|
/// Allows creation of instances of a struct by moving fields that have
|
||||||
/// not changed from prior instances of the same struct (RFC #2528)
|
/// not changed from prior instances of the same struct (RFC #2528)
|
||||||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||||
|
/// Allows using `unsafe<'a> &'a T` unsafe binder types.
|
||||||
|
(incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)),
|
||||||
/// Allows declaring fields `unsafe`.
|
/// Allows declaring fields `unsafe`.
|
||||||
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
|
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
|
||||||
/// Allows const generic parameters to be defined with types that
|
/// Allows const generic parameters to be defined with types that
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_ast::{
|
||||||
};
|
};
|
||||||
pub use rustc_ast::{
|
pub use rustc_ast::{
|
||||||
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
|
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
|
||||||
ImplPolarity, IsAuto, Movability, Mutability, UnOp,
|
ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::sorted_map::SortedMap;
|
use rustc_data_structures::sorted_map::SortedMap;
|
||||||
|
@ -1740,6 +1740,7 @@ impl Expr<'_> {
|
||||||
| ExprKind::Struct(..)
|
| ExprKind::Struct(..)
|
||||||
| ExprKind::Tup(_)
|
| ExprKind::Tup(_)
|
||||||
| ExprKind::Type(..)
|
| ExprKind::Type(..)
|
||||||
|
| ExprKind::UnsafeBinderCast(..)
|
||||||
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
||||||
|
|
||||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||||
|
@ -1769,6 +1770,9 @@ impl Expr<'_> {
|
||||||
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
|
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
|
||||||
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
|
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
|
||||||
|
|
||||||
|
// Unsafe binder cast preserves place-ness of the sub-expression.
|
||||||
|
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
|
||||||
|
|
||||||
ExprKind::Unary(UnOp::Deref, _) => true,
|
ExprKind::Unary(UnOp::Deref, _) => true,
|
||||||
|
|
||||||
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
|
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
|
||||||
|
@ -1850,7 +1854,8 @@ impl Expr<'_> {
|
||||||
| ExprKind::Field(base, _)
|
| ExprKind::Field(base, _)
|
||||||
| ExprKind::Index(base, _, _)
|
| ExprKind::Index(base, _, _)
|
||||||
| ExprKind::AddrOf(.., base)
|
| ExprKind::AddrOf(.., base)
|
||||||
| ExprKind::Cast(base, _) => {
|
| ExprKind::Cast(base, _)
|
||||||
|
| ExprKind::UnsafeBinderCast(_, base, _) => {
|
||||||
// This isn't exactly true for `Index` and all `Unary`, but we are using this
|
// This isn't exactly true for `Index` and all `Unary`, but we are using this
|
||||||
// method exclusively for diagnostics and there's a *cultural* pressure against
|
// method exclusively for diagnostics and there's a *cultural* pressure against
|
||||||
// them being used only for its side-effects.
|
// them being used only for its side-effects.
|
||||||
|
@ -2144,6 +2149,10 @@ pub enum ExprKind<'hir> {
|
||||||
/// A suspension point for coroutines (i.e., `yield <expr>`).
|
/// A suspension point for coroutines (i.e., `yield <expr>`).
|
||||||
Yield(&'hir Expr<'hir>, YieldSource),
|
Yield(&'hir Expr<'hir>, YieldSource),
|
||||||
|
|
||||||
|
/// Operators which can be used to interconvert `unsafe` binder types.
|
||||||
|
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
|
||||||
|
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
|
||||||
|
|
||||||
/// A placeholder for an expression that wasn't syntactically well formed in some way.
|
/// A placeholder for an expression that wasn't syntactically well formed in some way.
|
||||||
Err(rustc_span::ErrorGuaranteed),
|
Err(rustc_span::ErrorGuaranteed),
|
||||||
}
|
}
|
||||||
|
@ -2780,6 +2789,12 @@ pub struct BareFnTy<'hir> {
|
||||||
pub param_names: &'hir [Ident],
|
pub param_names: &'hir [Ident],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
|
pub struct UnsafeBinderTy<'hir> {
|
||||||
|
pub generic_params: &'hir [GenericParam<'hir>],
|
||||||
|
pub inner_ty: &'hir Ty<'hir>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub struct OpaqueTy<'hir> {
|
pub struct OpaqueTy<'hir> {
|
||||||
pub hir_id: HirId,
|
pub hir_id: HirId,
|
||||||
|
@ -2878,6 +2893,8 @@ pub enum TyKind<'hir> {
|
||||||
Ref(&'hir Lifetime, MutTy<'hir>),
|
Ref(&'hir Lifetime, MutTy<'hir>),
|
||||||
/// A bare function (e.g., `fn(usize) -> bool`).
|
/// A bare function (e.g., `fn(usize) -> bool`).
|
||||||
BareFn(&'hir BareFnTy<'hir>),
|
BareFn(&'hir BareFnTy<'hir>),
|
||||||
|
/// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`).
|
||||||
|
UnsafeBinder(&'hir UnsafeBinderTy<'hir>),
|
||||||
/// The never type (`!`).
|
/// The never type (`!`).
|
||||||
Never,
|
Never,
|
||||||
/// A tuple (`(A, B, C, D, ...)`).
|
/// A tuple (`(A, B, C, D, ...)`).
|
||||||
|
|
|
@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||||
ExprKind::Yield(ref subexpression, _) => {
|
ExprKind::Yield(ref subexpression, _) => {
|
||||||
try_visit!(visitor.visit_expr(subexpression));
|
try_visit!(visitor.visit_expr(subexpression));
|
||||||
}
|
}
|
||||||
|
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||||
|
try_visit!(visitor.visit_expr(expr));
|
||||||
|
visit_opt!(visitor, visit_ty, ty);
|
||||||
|
}
|
||||||
ExprKind::Lit(_) | ExprKind::Err(_) => {}
|
ExprKind::Lit(_) | ExprKind::Err(_) => {}
|
||||||
}
|
}
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
|
@ -886,6 +890,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
|
||||||
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
|
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
|
||||||
try_visit!(visitor.visit_fn_decl(function_declaration.decl));
|
try_visit!(visitor.visit_fn_decl(function_declaration.decl));
|
||||||
}
|
}
|
||||||
|
TyKind::UnsafeBinder(ref unsafe_binder) => {
|
||||||
|
walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
|
||||||
|
try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
|
||||||
|
}
|
||||||
TyKind::Path(ref qpath) => {
|
TyKind::Path(ref qpath) => {
|
||||||
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
|
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
||||||
self.outer_index.shift_out(1);
|
self.outer_index.shift_out(1);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
hir::TyKind::UnsafeBinder(_) => {
|
||||||
|
self.outer_index.shift_in(1);
|
||||||
|
let res = intravisit::walk_ty(self, ty);
|
||||||
|
self.outer_index.shift_out(1);
|
||||||
|
res
|
||||||
|
}
|
||||||
_ => intravisit::walk_ty(self, ty),
|
_ => intravisit::walk_ty(self, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
intravisit::walk_ty(this, ty);
|
intravisit::walk_ty(this, ty);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
hir::TyKind::UnsafeBinder(binder) => {
|
||||||
|
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
|
||||||
|
binder
|
||||||
|
.generic_params
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(late_bound_idx, param)| {
|
||||||
|
(
|
||||||
|
(param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
|
||||||
|
late_arg_as_bound_arg(self.tcx, param),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unzip();
|
||||||
|
|
||||||
|
deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
|
||||||
|
|
||||||
|
self.record_late_bound_vars(ty.hir_id, binders);
|
||||||
|
let scope = Scope::Binder {
|
||||||
|
hir_id: ty.hir_id,
|
||||||
|
bound_vars,
|
||||||
|
s: self.scope,
|
||||||
|
scope_type: BinderScopeType::Normal,
|
||||||
|
where_bound_origin: None,
|
||||||
|
};
|
||||||
|
self.with(scope, |this| {
|
||||||
|
// a bare fn has no bounds, so everything
|
||||||
|
// contained within is scoped within its binder.
|
||||||
|
intravisit::walk_ty(this, ty);
|
||||||
|
});
|
||||||
|
}
|
||||||
hir::TyKind::TraitObject(bounds, lifetime, _) => {
|
hir::TyKind::TraitObject(bounds, lifetime, _) => {
|
||||||
debug!(?bounds, ?lifetime, "TraitObject");
|
debug!(?bounds, ?lifetime, "TraitObject");
|
||||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||||
|
|
|
@ -2312,6 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
|
self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
hir::TyKind::UnsafeBinder(_binder) => {
|
||||||
|
let guar = self
|
||||||
|
.dcx()
|
||||||
|
.struct_span_err(hir_ty.span, "unsafe binders are not yet implemented")
|
||||||
|
.emit();
|
||||||
|
Ty::new_error(tcx, guar)
|
||||||
|
}
|
||||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||||
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
|
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
|
||||||
// Don't continue with type analysis if the `dyn` keyword is missing
|
// Don't continue with type analysis if the `dyn` keyword is missing
|
||||||
|
|
|
@ -288,6 +288,9 @@ impl<'a> State<'a> {
|
||||||
hir::TyKind::BareFn(f) => {
|
hir::TyKind::BareFn(f) => {
|
||||||
self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
|
self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
|
||||||
}
|
}
|
||||||
|
hir::TyKind::UnsafeBinder(unsafe_binder) => {
|
||||||
|
self.print_unsafe_binder(unsafe_binder);
|
||||||
|
}
|
||||||
hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
|
hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
|
||||||
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
|
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
|
||||||
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
|
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
|
||||||
|
@ -339,6 +342,15 @@ impl<'a> State<'a> {
|
||||||
self.end()
|
self.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) {
|
||||||
|
self.ibox(INDENT_UNIT);
|
||||||
|
self.word("unsafe");
|
||||||
|
self.print_generic_params(unsafe_binder.generic_params);
|
||||||
|
self.nbsp();
|
||||||
|
self.print_type(unsafe_binder.inner_ty);
|
||||||
|
self.end();
|
||||||
|
}
|
||||||
|
|
||||||
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
|
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
|
||||||
self.hardbreak_if_not_bol();
|
self.hardbreak_if_not_bol();
|
||||||
self.maybe_print_comment(item.span.lo());
|
self.maybe_print_comment(item.span.lo());
|
||||||
|
@ -1530,6 +1542,19 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
self.word(")");
|
self.word(")");
|
||||||
}
|
}
|
||||||
|
hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||||
|
match kind {
|
||||||
|
hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
|
||||||
|
hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
|
||||||
|
}
|
||||||
|
self.print_expr(expr);
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
self.word(",");
|
||||||
|
self.space();
|
||||||
|
self.print_type(ty);
|
||||||
|
}
|
||||||
|
self.word(")");
|
||||||
|
}
|
||||||
hir::ExprKind::Yield(expr, _) => {
|
hir::ExprKind::Yield(expr, _) => {
|
||||||
self.word_space("yield");
|
self.word_space("yield");
|
||||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||||
|
|
|
@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// Assignment does call `drop_in_place`, though, but its safety
|
// Assignment does call `drop_in_place`, though, but its safety
|
||||||
// requirements are not the same.
|
// requirements are not the same.
|
||||||
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
|
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
|
||||||
|
|
||||||
|
// Place-preserving expressions only constitute reads if their
|
||||||
|
// parent expression constitutes a read.
|
||||||
|
ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
|
||||||
|
self.expr_guaranteed_to_constitute_read_for_never(expr)
|
||||||
|
}
|
||||||
|
|
||||||
ExprKind::Assign(lhs, _, _) => {
|
ExprKind::Assign(lhs, _, _) => {
|
||||||
// Only the LHS does not constitute a read
|
// Only the LHS does not constitute a read
|
||||||
expr.hir_id != lhs.hir_id
|
expr.hir_id != lhs.hir_id
|
||||||
|
@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
| ExprKind::Binary(_, _, _)
|
| ExprKind::Binary(_, _, _)
|
||||||
| ExprKind::Unary(_, _)
|
| ExprKind::Unary(_, _)
|
||||||
| ExprKind::Cast(_, _)
|
| ExprKind::Cast(_, _)
|
||||||
| ExprKind::Type(_, _)
|
|
||||||
| ExprKind::DropTemps(_)
|
| ExprKind::DropTemps(_)
|
||||||
| ExprKind::If(_, _, _)
|
| ExprKind::If(_, _, _)
|
||||||
| ExprKind::Closure(_)
|
| ExprKind::Closure(_)
|
||||||
|
@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.check_expr_index(base, idx, expr, brackets_span)
|
self.check_expr_index(base, idx, expr, brackets_span)
|
||||||
}
|
}
|
||||||
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
|
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
|
||||||
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||||
|
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
|
||||||
|
}
|
||||||
|
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1634,6 +1643,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_expr_unsafe_binder_cast(
|
||||||
|
&self,
|
||||||
|
_kind: hir::UnsafeBinderCastKind,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
_hir_ty: Option<&'tcx hir::Ty<'tcx>>,
|
||||||
|
_expected: Expectation<'tcx>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
let guar =
|
||||||
|
self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
|
||||||
|
Ty::new_error(self.tcx, guar)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr_array(
|
fn check_expr_array(
|
||||||
&self,
|
&self,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
args: &'tcx [hir::Expr<'tcx>],
|
||||||
|
|
|
@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
self.walk_expr(subexpr)?;
|
self.walk_expr(subexpr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
|
||||||
|
self.walk_expr(subexpr)?;
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
|
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
|
||||||
// *base
|
// *base
|
||||||
self.walk_expr(base)?;
|
self.walk_expr(base)?;
|
||||||
|
@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
|
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// both type ascription and unsafe binder casts don't affect
|
||||||
|
// the place-ness of the subexpression.
|
||||||
hir::ExprKind::Type(e, _) => self.cat_expr(e),
|
hir::ExprKind::Type(e, _) => self.cat_expr(e),
|
||||||
|
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
|
||||||
|
|
||||||
hir::ExprKind::AddrOf(..)
|
hir::ExprKind::AddrOf(..)
|
||||||
| hir::ExprKind::Call(..)
|
| hir::ExprKind::Call(..)
|
||||||
|
|
|
@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
|
||||||
| ExprKind::DropTemps(..)
|
| ExprKind::DropTemps(..)
|
||||||
| ExprKind::Let(..) => false,
|
| ExprKind::Let(..) => false,
|
||||||
|
|
||||||
|
ExprKind::UnsafeBinderCast(..) => false,
|
||||||
|
|
||||||
// Not applicable
|
// Not applicable
|
||||||
ExprKind::Type(..) | ExprKind::Err(..) => false,
|
ExprKind::Type(..) | ExprKind::Err(..) => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
|
||||||
hir::ExprKind::Unary(_, expr)
|
hir::ExprKind::Unary(_, expr)
|
||||||
| hir::ExprKind::Cast(expr, _)
|
| hir::ExprKind::Cast(expr, _)
|
||||||
| hir::ExprKind::Type(expr, _)
|
| hir::ExprKind::Type(expr, _)
|
||||||
|
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
|
||||||
| hir::ExprKind::Yield(expr, _)
|
| hir::ExprKind::Yield(expr, _)
|
||||||
| hir::ExprKind::AddrOf(_, _, expr)
|
| hir::ExprKind::AddrOf(_, _, expr)
|
||||||
| hir::ExprKind::Match(expr, _, _)
|
| hir::ExprKind::Match(expr, _, _)
|
||||||
|
|
|
@ -915,6 +915,11 @@ impl<'tcx> Cx<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
|
||||||
|
unreachable!("unsafe binders are not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
|
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
|
||||||
hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
|
hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
|
||||||
hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
|
hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
|
||||||
|
|
|
@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr};
|
||||||
use rustc_ast::{
|
use rustc_ast::{
|
||||||
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
|
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
|
||||||
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
|
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
|
||||||
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp,
|
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
|
||||||
};
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
|
@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> {
|
||||||
Ok(match ident.name {
|
Ok(match ident.name {
|
||||||
sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
|
sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
|
||||||
sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
|
sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
|
||||||
|
sym::wrap_binder => {
|
||||||
|
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
|
||||||
|
}
|
||||||
|
sym::unwrap_binder => {
|
||||||
|
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> {
|
||||||
Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
|
Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_expr_unsafe_binder_cast(
|
||||||
|
&mut self,
|
||||||
|
lo: Span,
|
||||||
|
kind: UnsafeBinderCastKind,
|
||||||
|
) -> PResult<'a, P<Expr>> {
|
||||||
|
let expr = self.parse_expr()?;
|
||||||
|
let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None };
|
||||||
|
let span = lo.to(self.token.span);
|
||||||
|
Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a string literal if the next token is a string literal.
|
/// Returns a string literal if the next token is a string literal.
|
||||||
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
|
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
|
||||||
/// and returns `None` if the next token is not literal at all.
|
/// and returns `None` if the next token is not literal at all.
|
||||||
|
@ -4016,7 +4033,9 @@ impl MutVisitor for CondChecker<'_> {
|
||||||
mut_visit::walk_expr(self, e);
|
mut_visit::walk_expr(self, e);
|
||||||
self.forbid_let_reason = forbid_let_reason;
|
self.forbid_let_reason = forbid_let_reason;
|
||||||
}
|
}
|
||||||
ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {
|
ExprKind::Cast(ref mut op, _)
|
||||||
|
| ExprKind::Type(ref mut op, _)
|
||||||
|
| ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
|
||||||
let forbid_let_reason = self.forbid_let_reason;
|
let forbid_let_reason = self.forbid_let_reason;
|
||||||
self.forbid_let_reason = Some(OtherForbidden);
|
self.forbid_let_reason = Some(OtherForbidden);
|
||||||
self.visit_expr(op);
|
self.visit_expr(op);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_ast::{
|
||||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
|
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
|
||||||
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
|
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
|
||||||
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
|
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
|
||||||
TyKind,
|
TyKind, UnsafeBinderTy,
|
||||||
};
|
};
|
||||||
use rustc_errors::{Applicability, PResult};
|
use rustc_errors::{Applicability, PResult};
|
||||||
use rustc_span::symbol::{Ident, kw, sym};
|
use rustc_span::symbol::{Ident, kw, sym};
|
||||||
|
@ -348,6 +348,10 @@ impl<'a> Parser<'a> {
|
||||||
TyKind::Err(guar)
|
TyKind::Err(guar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if self.check_keyword(kw::Unsafe)
|
||||||
|
&& self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
|
||||||
|
{
|
||||||
|
self.parse_unsafe_binder_ty()?
|
||||||
} else {
|
} else {
|
||||||
let msg = format!("expected type, found {}", super::token_descr(&self.token));
|
let msg = format!("expected type, found {}", super::token_descr(&self.token));
|
||||||
let mut err = self.dcx().struct_span_err(lo, msg);
|
let mut err = self.dcx().struct_span_err(lo, msg);
|
||||||
|
@ -369,6 +373,19 @@ impl<'a> Parser<'a> {
|
||||||
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
|
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> {
|
||||||
|
let lo = self.token.span;
|
||||||
|
assert!(self.eat_keyword(kw::Unsafe));
|
||||||
|
self.expect_lt()?;
|
||||||
|
let generic_params = self.parse_generic_params()?;
|
||||||
|
self.expect_gt()?;
|
||||||
|
let inner_ty = self.parse_ty()?;
|
||||||
|
let span = lo.to(self.prev_token.span);
|
||||||
|
self.psess.gated_spans.gate(sym::unsafe_binders, span);
|
||||||
|
|
||||||
|
Ok(TyKind::UnsafeBinder(P(UnsafeBinderTy { generic_params, inner_ty })))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses either:
|
/// Parses either:
|
||||||
/// - `(TYPE)`, a parenthesized type.
|
/// - `(TYPE)`, a parenthesized type.
|
||||||
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
|
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
|
||||||
|
|
|
@ -315,9 +315,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
|
fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
|
||||||
record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [
|
record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [
|
||||||
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps,
|
ConstBlock,
|
||||||
Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf,
|
Array,
|
||||||
Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err
|
Call,
|
||||||
|
MethodCall,
|
||||||
|
Tup,
|
||||||
|
Binary,
|
||||||
|
Unary,
|
||||||
|
Lit,
|
||||||
|
Cast,
|
||||||
|
Type,
|
||||||
|
DropTemps,
|
||||||
|
Let,
|
||||||
|
If,
|
||||||
|
Loop,
|
||||||
|
Match,
|
||||||
|
Closure,
|
||||||
|
Block,
|
||||||
|
Assign,
|
||||||
|
AssignOp,
|
||||||
|
Field,
|
||||||
|
Index,
|
||||||
|
Path,
|
||||||
|
AddrOf,
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
Ret,
|
||||||
|
Become,
|
||||||
|
InlineAsm,
|
||||||
|
OffsetOf,
|
||||||
|
Struct,
|
||||||
|
Repeat,
|
||||||
|
Yield,
|
||||||
|
UnsafeBinderCast,
|
||||||
|
Err
|
||||||
]);
|
]);
|
||||||
hir_visit::walk_expr(self, e)
|
hir_visit::walk_expr(self, e)
|
||||||
}
|
}
|
||||||
|
@ -335,6 +366,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Ptr,
|
Ptr,
|
||||||
Ref,
|
Ref,
|
||||||
BareFn,
|
BareFn,
|
||||||
|
UnsafeBinder,
|
||||||
Never,
|
Never,
|
||||||
Tup,
|
Tup,
|
||||||
Path,
|
Path,
|
||||||
|
@ -571,7 +603,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
|
If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
|
||||||
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
|
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
|
||||||
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
|
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
|
||||||
Become, IncludedBytes, Gen, Err, Dummy
|
Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
ast_visit::walk_expr(self, e)
|
ast_visit::walk_expr(self, e)
|
||||||
|
@ -585,6 +617,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Ref,
|
Ref,
|
||||||
PinnedRef,
|
PinnedRef,
|
||||||
BareFn,
|
BareFn,
|
||||||
|
UnsafeBinder,
|
||||||
Never,
|
Never,
|
||||||
Tup,
|
Tup,
|
||||||
Path,
|
Path,
|
||||||
|
|
|
@ -447,6 +447,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
||||||
| hir::ExprKind::InlineAsm(..)
|
| hir::ExprKind::InlineAsm(..)
|
||||||
| hir::ExprKind::OffsetOf(..)
|
| hir::ExprKind::OffsetOf(..)
|
||||||
| hir::ExprKind::Type(..)
|
| hir::ExprKind::Type(..)
|
||||||
|
| hir::ExprKind::UnsafeBinderCast(..)
|
||||||
| hir::ExprKind::Err(_)
|
| hir::ExprKind::Err(_)
|
||||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||||
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {}
|
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {}
|
||||||
|
@ -1051,6 +1052,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
hir::ExprKind::AddrOf(_, _, ref e)
|
hir::ExprKind::AddrOf(_, _, ref e)
|
||||||
| hir::ExprKind::Cast(ref e, _)
|
| hir::ExprKind::Cast(ref e, _)
|
||||||
| hir::ExprKind::Type(ref e, _)
|
| hir::ExprKind::Type(ref e, _)
|
||||||
|
| hir::ExprKind::UnsafeBinderCast(_, ref e, _)
|
||||||
| hir::ExprKind::DropTemps(ref e)
|
| hir::ExprKind::DropTemps(ref e)
|
||||||
| hir::ExprKind::Unary(_, ref e)
|
| hir::ExprKind::Unary(_, ref e)
|
||||||
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ),
|
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ),
|
||||||
|
@ -1443,6 +1445,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||||
| hir::ExprKind::Path(_)
|
| hir::ExprKind::Path(_)
|
||||||
| hir::ExprKind::Yield(..)
|
| hir::ExprKind::Yield(..)
|
||||||
| hir::ExprKind::Type(..)
|
| hir::ExprKind::Type(..)
|
||||||
|
| hir::ExprKind::UnsafeBinderCast(..)
|
||||||
| hir::ExprKind::Err(_) => {}
|
| hir::ExprKind::Err(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,7 @@ impl CheckInlineAssembly {
|
||||||
| ExprKind::Lit(..)
|
| ExprKind::Lit(..)
|
||||||
| ExprKind::Cast(..)
|
| ExprKind::Cast(..)
|
||||||
| ExprKind::Type(..)
|
| ExprKind::Type(..)
|
||||||
|
| ExprKind::UnsafeBinderCast(..)
|
||||||
| ExprKind::Loop(..)
|
| ExprKind::Loop(..)
|
||||||
| ExprKind::Match(..)
|
| ExprKind::Match(..)
|
||||||
| ExprKind::If(..)
|
| ExprKind::If(..)
|
||||||
|
|
|
@ -887,6 +887,28 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
TyKind::UnsafeBinder(unsafe_binder) => {
|
||||||
|
// FIXME(unsafe_binder): Better span
|
||||||
|
let span = ty.span;
|
||||||
|
self.with_generic_param_rib(
|
||||||
|
&unsafe_binder.generic_params,
|
||||||
|
RibKind::Normal,
|
||||||
|
LifetimeRibKind::Generics {
|
||||||
|
binder: ty.id,
|
||||||
|
kind: LifetimeBinderKind::BareFnType,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
|this| {
|
||||||
|
this.visit_generic_params(&unsafe_binder.generic_params, false);
|
||||||
|
this.with_lifetime_rib(
|
||||||
|
// We don't allow anonymous `unsafe &'_ ()` binders,
|
||||||
|
// although I guess we could.
|
||||||
|
LifetimeRibKind::AnonymousReportError,
|
||||||
|
|this| this.visit_ty(&unsafe_binder.inner_ty),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
TyKind::Array(element_ty, length) => {
|
TyKind::Array(element_ty, length) => {
|
||||||
self.visit_ty(element_ty);
|
self.visit_ty(element_ty);
|
||||||
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
|
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
|
||||||
|
|
|
@ -2105,6 +2105,7 @@ symbols! {
|
||||||
unreachable_macro,
|
unreachable_macro,
|
||||||
unrestricted_attribute_tokens,
|
unrestricted_attribute_tokens,
|
||||||
unsafe_attributes,
|
unsafe_attributes,
|
||||||
|
unsafe_binders,
|
||||||
unsafe_block_in_unsafe_fn,
|
unsafe_block_in_unsafe_fn,
|
||||||
unsafe_cell,
|
unsafe_cell,
|
||||||
unsafe_cell_raw_get,
|
unsafe_cell_raw_get,
|
||||||
|
@ -2128,6 +2129,7 @@ symbols! {
|
||||||
unwind_attributes,
|
unwind_attributes,
|
||||||
unwind_safe_trait,
|
unwind_safe_trait,
|
||||||
unwrap,
|
unwrap,
|
||||||
|
unwrap_binder,
|
||||||
unwrap_or,
|
unwrap_or,
|
||||||
use_extern_macros,
|
use_extern_macros,
|
||||||
use_nested_groups,
|
use_nested_groups,
|
||||||
|
@ -2186,6 +2188,7 @@ symbols! {
|
||||||
windows,
|
windows,
|
||||||
windows_subsystem,
|
windows_subsystem,
|
||||||
with_negative_coherence,
|
with_negative_coherence,
|
||||||
|
wrap_binder,
|
||||||
wrapping_add,
|
wrapping_add,
|
||||||
wrapping_div,
|
wrapping_div,
|
||||||
wrapping_mul,
|
wrapping_mul,
|
||||||
|
|
|
@ -354,6 +354,8 @@ pub mod random;
|
||||||
pub mod range;
|
pub mod range;
|
||||||
pub mod result;
|
pub mod result;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
#[unstable(feature = "unsafe_binders", issue = "130516")]
|
||||||
|
pub mod unsafe_binder;
|
||||||
|
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
|
|
25
library/core/src/unsafe_binder.rs
Normal file
25
library/core/src/unsafe_binder.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//! Operators used to turn types into unsafe binders and back.
|
||||||
|
|
||||||
|
/// Unwrap an unsafe binder into its underlying type.
|
||||||
|
#[allow_internal_unstable(builtin_syntax)]
|
||||||
|
#[unstable(feature = "unsafe_binders", issue = "130516")]
|
||||||
|
pub macro unwrap_binder {
|
||||||
|
($expr:expr) => {
|
||||||
|
builtin # unwrap_binder ( $expr )
|
||||||
|
},
|
||||||
|
($expr:expr ; $ty:ty) => {
|
||||||
|
builtin # unwrap_binder ( $expr, $ty )
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap a type into an unsafe binder.
|
||||||
|
#[allow_internal_unstable(builtin_syntax)]
|
||||||
|
#[unstable(feature = "unsafe_binders", issue = "130516")]
|
||||||
|
pub macro wrap_binder {
|
||||||
|
($expr:expr) => {
|
||||||
|
builtin # wrap_binder ( $expr )
|
||||||
|
},
|
||||||
|
($expr:expr ; $ty:ty) => {
|
||||||
|
builtin # wrap_binder ( $expr, $ty )
|
||||||
|
},
|
||||||
|
}
|
|
@ -544,6 +544,8 @@ pub use core::u64;
|
||||||
#[stable(feature = "i128", since = "1.26.0")]
|
#[stable(feature = "i128", since = "1.26.0")]
|
||||||
#[allow(deprecated, deprecated_in_future)]
|
#[allow(deprecated, deprecated_in_future)]
|
||||||
pub use core::u128;
|
pub use core::u128;
|
||||||
|
#[unstable(feature = "unsafe_binders", issue = "130516")]
|
||||||
|
pub use core::unsafe_binder;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow(deprecated, deprecated_in_future)]
|
#[allow(deprecated, deprecated_in_future)]
|
||||||
pub use core::usize;
|
pub use core::usize;
|
||||||
|
|
|
@ -1841,6 +1841,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||||
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
|
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
|
||||||
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
||||||
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
|
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
|
||||||
|
TyKind::UnsafeBinder(..) => {
|
||||||
|
unimplemented!("unsafe binders are not supported yet")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -819,6 +819,7 @@ impl TyCoercionStability {
|
||||||
| TyKind::TraitObject(..)
|
| TyKind::TraitObject(..)
|
||||||
| TyKind::InferDelegation(..)
|
| TyKind::InferDelegation(..)
|
||||||
| TyKind::Err(_) => Self::Reborrow,
|
| TyKind::Err(_) => Self::Reborrow,
|
||||||
|
TyKind::UnsafeBinder(..) => Self::None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,8 @@ fn never_loop_expr<'tcx>(
|
||||||
| ExprKind::Field(e, _)
|
| ExprKind::Field(e, _)
|
||||||
| ExprKind::AddrOf(_, _, e)
|
| ExprKind::AddrOf(_, _, e)
|
||||||
| ExprKind::Repeat(e, _)
|
| ExprKind::Repeat(e, _)
|
||||||
| ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id),
|
| ExprKind::DropTemps(e)
|
||||||
|
| ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id),
|
||||||
ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
|
ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
|
||||||
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
|
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
|
||||||
ExprKind::MethodCall(_, receiver, es, _) => {
|
ExprKind::MethodCall(_, receiver, es, _) => {
|
||||||
|
|
|
@ -623,6 +623,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||||
kind!("DropTemps({expr})");
|
kind!("DropTemps({expr})");
|
||||||
self.expr(expr);
|
self.expr(expr);
|
||||||
},
|
},
|
||||||
|
ExprKind::UnsafeBinderCast(..) => {
|
||||||
|
unimplemented!("unsafe binders are not implemented yet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,7 +303,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
|
||||||
| ExprKind::AddrOf(..)
|
| ExprKind::AddrOf(..)
|
||||||
| ExprKind::Repeat(..)
|
| ExprKind::Repeat(..)
|
||||||
| ExprKind::Block(Block { stmts: [], .. }, _)
|
| ExprKind::Block(Block { stmts: [], .. }, _)
|
||||||
| ExprKind::OffsetOf(..) => (),
|
| ExprKind::OffsetOf(..)
|
||||||
|
| ExprKind::UnsafeBinderCast(..) => (),
|
||||||
|
|
||||||
// Assignment might be to a local defined earlier, so don't eagerly evaluate.
|
// Assignment might be to a local defined earlier, so don't eagerly evaluate.
|
||||||
// Blocks with multiple statements might be expensive, so don't eagerly evaluate.
|
// Blocks with multiple statements might be expensive, so don't eagerly evaluate.
|
||||||
|
|
|
@ -370,6 +370,10 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||||
&& self.eq_expr(l_receiver, r_receiver)
|
&& self.eq_expr(l_receiver, r_receiver)
|
||||||
&& self.eq_exprs(l_args, r_args)
|
&& self.eq_exprs(l_args, r_args)
|
||||||
},
|
},
|
||||||
|
(&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) =>
|
||||||
|
lkind == rkind && self.eq_expr(le, re),
|
||||||
|
(&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) =>
|
||||||
|
lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt),
|
||||||
(&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
|
(&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
|
||||||
self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
|
self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
|
||||||
},
|
},
|
||||||
|
@ -424,6 +428,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||||
| &ExprKind::Type(..)
|
| &ExprKind::Type(..)
|
||||||
| &ExprKind::Unary(..)
|
| &ExprKind::Unary(..)
|
||||||
| &ExprKind::Yield(..)
|
| &ExprKind::Yield(..)
|
||||||
|
| &ExprKind::UnsafeBinderCast(..)
|
||||||
|
|
||||||
// --- Special cases that do not have a positive branch.
|
// --- Special cases that do not have a positive branch.
|
||||||
|
|
||||||
|
@ -1032,6 +1037,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
std::mem::discriminant(&lop).hash(&mut self.s);
|
std::mem::discriminant(&lop).hash(&mut self.s);
|
||||||
self.hash_expr(le);
|
self.hash_expr(le);
|
||||||
},
|
},
|
||||||
|
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||||
|
std::mem::discriminant(&kind).hash(&mut self.s);
|
||||||
|
self.hash_expr(expr);
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
self.hash_ty(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
ExprKind::Err(_) => {},
|
ExprKind::Err(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1241,6 +1253,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
TyKind::Typeof(anon_const) => {
|
TyKind::Typeof(anon_const) => {
|
||||||
self.hash_body(anon_const.body);
|
self.hash_body(anon_const.body);
|
||||||
},
|
},
|
||||||
|
TyKind::UnsafeBinder(binder) => {
|
||||||
|
self.hash_ty(binder.inner_ty);
|
||||||
|
}
|
||||||
TyKind::Err(_)
|
TyKind::Err(_)
|
||||||
| TyKind::Infer
|
| TyKind::Infer
|
||||||
| TyKind::Never
|
| TyKind::Never
|
||||||
|
|
|
@ -151,7 +151,8 @@ impl<'a> Sugg<'a> {
|
||||||
| ExprKind::Become(..)
|
| ExprKind::Become(..)
|
||||||
| ExprKind::Struct(..)
|
| ExprKind::Struct(..)
|
||||||
| ExprKind::Tup(..)
|
| ExprKind::Tup(..)
|
||||||
| ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
|
| ExprKind::Err(_)
|
||||||
|
| ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
|
||||||
ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
|
ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
|
||||||
ExprKind::Assign(lhs, rhs, _) => {
|
ExprKind::Assign(lhs, rhs, _) => {
|
||||||
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
|
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
|
||||||
|
@ -226,7 +227,8 @@ impl<'a> Sugg<'a> {
|
||||||
| ast::ExprKind::While(..)
|
| ast::ExprKind::While(..)
|
||||||
| ast::ExprKind::Await(..)
|
| ast::ExprKind::Await(..)
|
||||||
| ast::ExprKind::Err(_)
|
| ast::ExprKind::Err(_)
|
||||||
| ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)),
|
| ast::ExprKind::Dummy
|
||||||
|
| ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)),
|
||||||
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
|
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
|
||||||
AssocOp::DotDot,
|
AssocOp::DotDot,
|
||||||
lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),
|
lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),
|
||||||
|
|
|
@ -694,6 +694,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
|
||||||
| ExprKind::Continue(_)
|
| ExprKind::Continue(_)
|
||||||
| ExprKind::InlineAsm(_)
|
| ExprKind::InlineAsm(_)
|
||||||
| ExprKind::OffsetOf(..)
|
| ExprKind::OffsetOf(..)
|
||||||
|
| ExprKind::UnsafeBinderCast(..)
|
||||||
| ExprKind::Err(_) => (),
|
| ExprKind::Err(_) => (),
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
|
|
|
@ -413,7 +413,8 @@ pub(crate) fn format_expr(
|
||||||
ast::ExprKind::FormatArgs(..)
|
ast::ExprKind::FormatArgs(..)
|
||||||
| ast::ExprKind::Type(..)
|
| ast::ExprKind::Type(..)
|
||||||
| ast::ExprKind::IncludedBytes(..)
|
| ast::ExprKind::IncludedBytes(..)
|
||||||
| ast::ExprKind::OffsetOf(..) => {
|
| ast::ExprKind::OffsetOf(..)
|
||||||
|
| ast::ExprKind::UnsafeBinderCast(..) => {
|
||||||
// These don't normally occur in the AST because macros aren't expanded. However,
|
// These don't normally occur in the AST because macros aren't expanded. However,
|
||||||
// rustfmt tries to parse macro arguments when formatting macros, so it's not totally
|
// rustfmt tries to parse macro arguments when formatting macros, so it's not totally
|
||||||
// impossible for rustfmt to come across one of these nodes when formatting a file.
|
// impossible for rustfmt to come across one of these nodes when formatting a file.
|
||||||
|
|
|
@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty {
|
||||||
let pat = pat.rewrite_result(context, shape)?;
|
let pat = pat.rewrite_result(context, shape)?;
|
||||||
Ok(format!("{ty} is {pat}"))
|
Ok(format!("{ty} is {pat}"))
|
||||||
}
|
}
|
||||||
|
ast::TyKind::UnsafeBinder(ref binder) => {
|
||||||
|
let mut result = String::new();
|
||||||
|
if let Some(ref lifetime_str) =
|
||||||
|
rewrite_bound_params(context, shape, &binder.generic_params)
|
||||||
|
{
|
||||||
|
result.push_str("unsafe<");
|
||||||
|
result.push_str(lifetime_str);
|
||||||
|
result.push_str("> ");
|
||||||
|
}
|
||||||
|
|
||||||
|
let inner_ty_shape = if context.use_block_indent() {
|
||||||
|
shape
|
||||||
|
.offset_left(result.len())
|
||||||
|
.max_width_error(shape.width, self.span())?
|
||||||
|
} else {
|
||||||
|
shape
|
||||||
|
.visual_indent(result.len())
|
||||||
|
.sub_width(result.len())
|
||||||
|
.max_width_error(shape.width, self.span())?
|
||||||
|
};
|
||||||
|
|
||||||
|
let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?;
|
||||||
|
result.push_str(&rewrite);
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
|
||||||
| ast::ExprKind::IncludedBytes(..)
|
| ast::ExprKind::IncludedBytes(..)
|
||||||
| ast::ExprKind::InlineAsm(..)
|
| ast::ExprKind::InlineAsm(..)
|
||||||
| ast::ExprKind::OffsetOf(..)
|
| ast::ExprKind::OffsetOf(..)
|
||||||
|
| ast::ExprKind::UnsafeBinderCast(..)
|
||||||
| ast::ExprKind::Let(..)
|
| ast::ExprKind::Let(..)
|
||||||
| ast::ExprKind::Path(..)
|
| ast::ExprKind::Path(..)
|
||||||
| ast::ExprKind::Range(..)
|
| ast::ExprKind::Range(..)
|
||||||
|
|
11
src/tools/rustfmt/tests/source/unsafe-binders.rs
Normal file
11
src/tools/rustfmt/tests/source/unsafe-binders.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fn foo() -> unsafe<'a>
|
||||||
|
&'a () {}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: unsafe<'a>
|
||||||
|
&'a (),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar(unsafe<'a> &'a ());
|
||||||
|
|
||||||
|
impl Trait for unsafe<'a> &'a () {}
|
9
src/tools/rustfmt/tests/target/unsafe-binders.rs
Normal file
9
src/tools/rustfmt/tests/target/unsafe-binders.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fn foo() -> unsafe<'a> &'a () {}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: unsafe<'a> &'a (),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar(unsafe<'a> &'a ());
|
||||||
|
|
||||||
|
impl Trait for unsafe<'a> &'a () {}
|
7
tests/ui/feature-gates/feature-gate-unsafe-binders.rs
Normal file
7
tests/ui/feature-gates/feature-gate-unsafe-binders.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#[cfg(any())]
|
||||||
|
fn test() {
|
||||||
|
let x: unsafe<> ();
|
||||||
|
//~^ ERROR unsafe binder types are experimental
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
13
tests/ui/feature-gates/feature-gate-unsafe-binders.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-unsafe-binders.stderr
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0658]: unsafe binder types are experimental
|
||||||
|
--> $DIR/feature-gate-unsafe-binders.rs:3:12
|
||||||
|
|
|
||||||
|
LL | let x: unsafe<> ();
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
|
||||||
|
= help: add `#![feature(unsafe_binders)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
13
tests/ui/unsafe-binders/expr.rs
Normal file
13
tests/ui/unsafe-binders/expr.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#![feature(unsafe_binders)]
|
||||||
|
//~^ WARN the feature `unsafe_binders` is incomplete
|
||||||
|
|
||||||
|
use std::unsafe_binder::{wrap_binder, unwrap_binder};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 1;
|
||||||
|
let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
|
||||||
|
//~^ ERROR unsafe binders are not yet implemented
|
||||||
|
//~| ERROR unsafe binders are not yet implemented
|
||||||
|
let rx = *unwrap_binder!(binder);
|
||||||
|
//~^ ERROR unsafe binders are not yet implemented
|
||||||
|
}
|
29
tests/ui/unsafe-binders/expr.stderr
Normal file
29
tests/ui/unsafe-binders/expr.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/expr.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(unsafe_binders)]
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/expr.rs:8:17
|
||||||
|
|
|
||||||
|
LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/expr.rs:8:51
|
||||||
|
|
|
||||||
|
LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/expr.rs:11:30
|
||||||
|
|
|
||||||
|
LL | let rx = *unwrap_binder!(binder);
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors; 1 warning emitted
|
||||||
|
|
19
tests/ui/unsafe-binders/lifetime-resolution.rs
Normal file
19
tests/ui/unsafe-binders/lifetime-resolution.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#![feature(unsafe_binders)]
|
||||||
|
//~^ WARN the feature `unsafe_binders` is incomplete
|
||||||
|
|
||||||
|
fn foo<'a>() {
|
||||||
|
let good: unsafe<'b> &'a &'b ();
|
||||||
|
//~^ ERROR unsafe binders are not yet implemented
|
||||||
|
|
||||||
|
let missing: unsafe<> &'missing ();
|
||||||
|
//~^ ERROR unsafe binders are not yet implemented
|
||||||
|
//~| ERROR use of undeclared lifetime name `'missing`
|
||||||
|
|
||||||
|
fn inner<'b>() {
|
||||||
|
let outer: unsafe<> &'a &'b ();
|
||||||
|
//~^ ERROR unsafe binders are not yet implemented
|
||||||
|
//~| can't use generic parameters from outer item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
65
tests/ui/unsafe-binders/lifetime-resolution.stderr
Normal file
65
tests/ui/unsafe-binders/lifetime-resolution.stderr
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
error[E0261]: use of undeclared lifetime name `'missing`
|
||||||
|
--> $DIR/lifetime-resolution.rs:8:28
|
||||||
|
|
|
||||||
|
LL | let missing: unsafe<> &'missing ();
|
||||||
|
| ^^^^^^^^ undeclared lifetime
|
||||||
|
|
|
||||||
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
|
||||||
|
help: consider making the type lifetime-generic with a new `'missing` lifetime
|
||||||
|
|
|
||||||
|
LL | let missing: unsafe<'missing, > &'missing ();
|
||||||
|
| +++++++++
|
||||||
|
help: consider introducing lifetime `'missing` here
|
||||||
|
|
|
||||||
|
LL | fn foo<'missing, 'a>() {
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error[E0401]: can't use generic parameters from outer item
|
||||||
|
--> $DIR/lifetime-resolution.rs:13:30
|
||||||
|
|
|
||||||
|
LL | fn foo<'a>() {
|
||||||
|
| -- lifetime parameter from outer item
|
||||||
|
...
|
||||||
|
LL | let outer: unsafe<> &'a &'b ();
|
||||||
|
| ^^ use of generic parameter from outer item
|
||||||
|
|
|
||||||
|
help: consider making the type lifetime-generic with a new `'a` lifetime
|
||||||
|
|
|
||||||
|
LL | let outer: unsafe<'a, > &'a &'b ();
|
||||||
|
| +++
|
||||||
|
help: consider introducing lifetime `'a` here
|
||||||
|
|
|
||||||
|
LL | fn inner<'a, 'b>() {
|
||||||
|
| +++
|
||||||
|
|
||||||
|
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/lifetime-resolution.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(unsafe_binders)]
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/lifetime-resolution.rs:5:15
|
||||||
|
|
|
||||||
|
LL | let good: unsafe<'b> &'a &'b ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/lifetime-resolution.rs:8:18
|
||||||
|
|
|
||||||
|
LL | let missing: unsafe<> &'missing ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/lifetime-resolution.rs:13:20
|
||||||
|
|
|
||||||
|
LL | let outer: unsafe<> &'a &'b ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors; 1 warning emitted
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0261, E0401.
|
||||||
|
For more information about an error, try `rustc --explain E0261`.
|
7
tests/ui/unsafe-binders/simple.rs
Normal file
7
tests/ui/unsafe-binders/simple.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#![feature(unsafe_binders)]
|
||||||
|
//~^ WARN the feature `unsafe_binders` is incomplete
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x: unsafe<'a> &'a ();
|
||||||
|
//~^ ERROR unsafe binders are not yet implemented
|
||||||
|
}
|
17
tests/ui/unsafe-binders/simple.stderr
Normal file
17
tests/ui/unsafe-binders/simple.stderr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/simple.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(unsafe_binders)]
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
error: unsafe binders are not yet implemented
|
||||||
|
--> $DIR/simple.rs:5:12
|
||||||
|
|
|
||||||
|
LL | let x: unsafe<'a> &'a ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue