Auto merge of #123396 - jhpratt:rollup-oa54mh1, r=jhpratt
Rollup of 5 pull requests Successful merges: - #122865 (Split hir ty lowerer's error reporting code in check functions to mod errors.) - #122935 (rename ptr::from_exposed_addr -> ptr::with_exposed_provenance) - #123182 (Avoid expanding to unstable internal method) - #123203 (Add `Context::ext`) - #123380 (Improve bootstrap comments) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b688d53a17
@ -2279,7 +2279,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CastKind::PointerFromExposedAddress => {
|
CastKind::PointerWithExposedProvenance => {
|
||||||
let ty_from = op.ty(body, tcx);
|
let ty_from = op.ty(body, tcx);
|
||||||
let cast_ty_from = CastTy::from_ty(ty_from);
|
let cast_ty_from = CastTy::from_ty(ty_from);
|
||||||
let cast_ty_to = CastTy::from_ty(*ty);
|
let cast_ty_to = CastTy::from_ty(*ty);
|
||||||
@ -2289,7 +2289,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
|
|||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
rvalue,
|
rvalue,
|
||||||
"Invalid PointerFromExposedAddress cast {:?} -> {:?}",
|
"Invalid PointerWithExposedProvenance cast {:?} -> {:?}",
|
||||||
ty_from,
|
ty_from,
|
||||||
ty
|
ty
|
||||||
)
|
)
|
||||||
|
@ -650,7 +650,7 @@ fn codegen_stmt<'tcx>(
|
|||||||
| CastKind::FnPtrToPtr
|
| CastKind::FnPtrToPtr
|
||||||
| CastKind::PtrToPtr
|
| CastKind::PtrToPtr
|
||||||
| CastKind::PointerExposeAddress
|
| CastKind::PointerExposeAddress
|
||||||
| CastKind::PointerFromExposedAddress,
|
| CastKind::PointerWithExposedProvenance,
|
||||||
ref operand,
|
ref operand,
|
||||||
to_ty,
|
to_ty,
|
||||||
) => {
|
) => {
|
||||||
|
@ -965,7 +965,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
|
sym::simd_expose_addr | sym::simd_with_exposed_provenance | sym::simd_cast_ptr => {
|
||||||
intrinsic_args!(fx, args => (arg); intrinsic);
|
intrinsic_args!(fx, args => (arg); intrinsic);
|
||||||
ret.write_cvalue_transmute(fx, arg);
|
ret.write_cvalue_transmute(fx, arg);
|
||||||
}
|
}
|
||||||
|
@ -2139,7 +2139,7 @@ macro_rules! bitwise_red {
|
|||||||
return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
|
return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == sym::simd_from_exposed_addr {
|
if name == sym::simd_with_exposed_provenance {
|
||||||
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
|
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
|
||||||
require!(
|
require!(
|
||||||
in_len == out_len,
|
in_len == out_len,
|
||||||
|
@ -509,7 +509,7 @@ pub fn codegen_rvalue_operand(
|
|||||||
// Since int2ptr can have arbitrary integer types as input (so we have to do
|
// Since int2ptr can have arbitrary integer types as input (so we have to do
|
||||||
// sign extension and all that), it is currently best handled in the same code
|
// sign extension and all that), it is currently best handled in the same code
|
||||||
// path as the other integer-to-X casts.
|
// path as the other integer-to-X casts.
|
||||||
| mir::CastKind::PointerFromExposedAddress => {
|
| mir::CastKind::PointerWithExposedProvenance => {
|
||||||
assert!(bx.cx().is_backend_immediate(cast));
|
assert!(bx.cx().is_backend_immediate(cast));
|
||||||
let ll_t_out = bx.cx().immediate_backend_type(cast);
|
let ll_t_out = bx.cx().immediate_backend_type(cast);
|
||||||
if operand.layout.abi.is_uninhabited() {
|
if operand.layout.abi.is_uninhabited() {
|
||||||
|
@ -40,9 +40,9 @@ pub fn cast(
|
|||||||
self.write_immediate(*res, dest)?;
|
self.write_immediate(*res, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
CastKind::PointerFromExposedAddress => {
|
CastKind::PointerWithExposedProvenance => {
|
||||||
let src = self.read_immediate(src)?;
|
let src = self.read_immediate(src)?;
|
||||||
let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?;
|
let res = self.pointer_with_exposed_provenance_cast(&src, cast_layout)?;
|
||||||
self.write_immediate(*res, dest)?;
|
self.write_immediate(*res, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ pub fn pointer_expose_address_cast(
|
|||||||
Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
|
Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pointer_from_exposed_address_cast(
|
pub fn pointer_with_exposed_provenance_cast(
|
||||||
&self,
|
&self,
|
||||||
src: &ImmTy<'tcx, M::Provenance>,
|
src: &ImmTy<'tcx, M::Provenance>,
|
||||||
cast_to: TyAndLayout<'tcx>,
|
cast_to: TyAndLayout<'tcx>,
|
||||||
|
@ -547,7 +547,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
|||||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
|
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
|
||||||
self.check_op(ops::RawPtrToIntCast);
|
self.check_op(ops::RawPtrToIntCast);
|
||||||
}
|
}
|
||||||
Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
|
Rvalue::Cast(CastKind::PointerWithExposedProvenance, _, _) => {
|
||||||
// Since no pointer can ever get exposed (rejected above), this is easy to support.
|
// Since no pointer can ever get exposed (rejected above), this is easy to support.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,7 +1076,7 @@ macro_rules! check_kinds {
|
|||||||
// FIXME(dyn-star): make sure nothing needs to be done here.
|
// FIXME(dyn-star): make sure nothing needs to be done here.
|
||||||
}
|
}
|
||||||
// FIXME: Add Checks for these
|
// FIXME: Add Checks for these
|
||||||
CastKind::PointerFromExposedAddress
|
CastKind::PointerWithExposedProvenance
|
||||||
| CastKind::PointerExposeAddress
|
| CastKind::PointerExposeAddress
|
||||||
| CastKind::PointerCoercion(_) => {}
|
| CastKind::PointerCoercion(_) => {}
|
||||||
CastKind::IntToInt | CastKind::IntToFloat => {
|
CastKind::IntToInt | CastKind::IntToFloat => {
|
||||||
|
@ -48,6 +48,23 @@ pub fn path_all(
|
|||||||
ast::Path { span, segments, tokens: None }
|
ast::Path { span, segments, tokens: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn macro_call(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
path: ast::Path,
|
||||||
|
delim: ast::token::Delimiter,
|
||||||
|
tokens: ast::tokenstream::TokenStream,
|
||||||
|
) -> P<ast::MacCall> {
|
||||||
|
P(ast::MacCall {
|
||||||
|
path,
|
||||||
|
args: P(ast::DelimArgs {
|
||||||
|
dspan: ast::tokenstream::DelimSpan { open: span, close: span },
|
||||||
|
delim,
|
||||||
|
tokens,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
|
pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
|
||||||
ast::MutTy { ty, mutbl }
|
ast::MutTy { ty, mutbl }
|
||||||
}
|
}
|
||||||
@ -265,6 +282,10 @@ pub fn expr_field(&self, span: Span, expr: P<Expr>, field: Ident) -> P<ast::Expr
|
|||||||
self.expr(span, ast::ExprKind::Field(expr, field))
|
self.expr(span, ast::ExprKind::Field(expr, field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_macro_call(&self, span: Span, call: P<ast::MacCall>) -> P<ast::Expr> {
|
||||||
|
self.expr(span, ast::ExprKind::MacCall(call))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expr_binary(
|
pub fn expr_binary(
|
||||||
&self,
|
&self,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
@ -410,16 +431,19 @@ pub fn expr_tuple(&self, sp: Span, exprs: ThinVec<P<ast::Expr>>) -> P<ast::Expr>
|
|||||||
self.expr(sp, ast::ExprKind::Tup(exprs))
|
self.expr(sp, ast::ExprKind::Tup(exprs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_fail(&self, span: Span, msg: Symbol) -> P<ast::Expr> {
|
|
||||||
self.expr_call_global(
|
|
||||||
span,
|
|
||||||
[sym::std, sym::rt, sym::begin_panic].iter().map(|s| Ident::new(*s, span)).collect(),
|
|
||||||
thin_vec![self.expr_str(span, msg)],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
|
pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
|
||||||
self.expr_fail(span, Symbol::intern("internal error: entered unreachable code"))
|
self.expr_macro_call(
|
||||||
|
span,
|
||||||
|
self.macro_call(
|
||||||
|
span,
|
||||||
|
self.path_global(
|
||||||
|
span,
|
||||||
|
[sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(),
|
||||||
|
),
|
||||||
|
ast::token::Delimiter::Parenthesis,
|
||||||
|
ast::tokenstream::TokenStream::default(),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
|
pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
|
||||||
|
@ -628,7 +628,7 @@ pub fn check_intrinsic_type(
|
|||||||
| sym::simd_as
|
| sym::simd_as
|
||||||
| sym::simd_cast_ptr
|
| sym::simd_cast_ptr
|
||||||
| sym::simd_expose_addr
|
| sym::simd_expose_addr
|
||||||
| sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)),
|
| sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)),
|
||||||
sym::simd_bitmask => (2, 0, vec![param(0)], param(1)),
|
sym::simd_bitmask => (2, 0, vec![param(0)], param(1)),
|
||||||
sym::simd_select | sym::simd_select_bitmask => {
|
sym::simd_select | sym::simd_select_bitmask => {
|
||||||
(2, 0, vec![param(0), param(1), param(1)], param(1))
|
(2, 0, vec![param(0), param(1), param(1)], param(1))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
||||||
ParenthesizedFnTraitExpansion,
|
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
|
||||||
};
|
};
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use crate::hir_ty_lowering::HirTyLowerer;
|
use crate::hir_ty_lowering::HirTyLowerer;
|
||||||
@ -8,19 +8,26 @@
|
|||||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::sorted_map::SortedMap;
|
use rustc_data_structures::sorted_map::SortedMap;
|
||||||
use rustc_data_structures::unord::UnordMap;
|
use rustc_data_structures::unord::UnordMap;
|
||||||
|
use rustc_errors::MultiSpan;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
|
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::traits::FulfillmentError;
|
use rustc_infer::traits::FulfillmentError;
|
||||||
use rustc_middle::query::Key;
|
use rustc_middle::query::Key;
|
||||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, suggest_constraining_type_param};
|
||||||
|
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
||||||
|
use rustc_middle::ty::{Binder, TraitRef};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
|
use rustc_span::BytePos;
|
||||||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||||
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
|
use rustc_trait_selection::traits::{
|
||||||
|
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
||||||
@ -1024,6 +1031,170 @@ pub(crate) fn maybe_report_similar_assoc_fn(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn report_prohibit_generics_error<'a>(
|
||||||
|
&self,
|
||||||
|
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||||
|
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
|
||||||
|
err_extend: GenericsArgsErrExtend<'_>,
|
||||||
|
) -> ErrorGuaranteed {
|
||||||
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
|
enum ProhibitGenericsArg {
|
||||||
|
Lifetime,
|
||||||
|
Type,
|
||||||
|
Const,
|
||||||
|
Infer,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut prohibit_args = FxIndexSet::default();
|
||||||
|
args_visitors.for_each(|arg| {
|
||||||
|
match arg {
|
||||||
|
hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
|
||||||
|
hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
|
||||||
|
hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
|
||||||
|
hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let types_and_spans: Vec<_> = segments
|
||||||
|
.clone()
|
||||||
|
.flat_map(|segment| {
|
||||||
|
if segment.args().args.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((
|
||||||
|
match segment.res {
|
||||||
|
hir::def::Res::PrimTy(ty) => {
|
||||||
|
format!("{} `{}`", segment.res.descr(), ty.name())
|
||||||
|
}
|
||||||
|
hir::def::Res::Def(_, def_id)
|
||||||
|
if let Some(name) = self.tcx().opt_item_name(def_id) =>
|
||||||
|
{
|
||||||
|
format!("{} `{name}`", segment.res.descr())
|
||||||
|
}
|
||||||
|
hir::def::Res::Err => "this type".to_string(),
|
||||||
|
_ => segment.res.descr().to_string(),
|
||||||
|
},
|
||||||
|
segment.ident.span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let this_type = match &types_and_spans[..] {
|
||||||
|
[.., _, (last, _)] => format!(
|
||||||
|
"{} and {last}",
|
||||||
|
types_and_spans[..types_and_spans.len() - 1]
|
||||||
|
.iter()
|
||||||
|
.map(|(x, _)| x.as_str())
|
||||||
|
.intersperse(", ")
|
||||||
|
.collect::<String>()
|
||||||
|
),
|
||||||
|
[(only, _)] => only.to_string(),
|
||||||
|
[] => "this type".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let arg_spans: Vec<Span> = segments
|
||||||
|
.clone()
|
||||||
|
.flat_map(|segment| segment.args().args)
|
||||||
|
.map(|arg| arg.span())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut kinds = Vec::with_capacity(4);
|
||||||
|
prohibit_args.iter().for_each(|arg| match arg {
|
||||||
|
ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
|
||||||
|
ProhibitGenericsArg::Type => kinds.push("type"),
|
||||||
|
ProhibitGenericsArg::Const => kinds.push("const"),
|
||||||
|
ProhibitGenericsArg::Infer => kinds.push("generic"),
|
||||||
|
});
|
||||||
|
|
||||||
|
let (kind, s) = match kinds[..] {
|
||||||
|
[.., _, last] => (
|
||||||
|
format!(
|
||||||
|
"{} and {last}",
|
||||||
|
kinds[..kinds.len() - 1]
|
||||||
|
.iter()
|
||||||
|
.map(|&x| x)
|
||||||
|
.intersperse(", ")
|
||||||
|
.collect::<String>()
|
||||||
|
),
|
||||||
|
"s",
|
||||||
|
),
|
||||||
|
[only] => (only.to_string(), ""),
|
||||||
|
[] => unreachable!("expected at least one generic to prohibit"),
|
||||||
|
};
|
||||||
|
let last_span = *arg_spans.last().unwrap();
|
||||||
|
let span: MultiSpan = arg_spans.into();
|
||||||
|
let mut err = struct_span_code_err!(
|
||||||
|
self.tcx().dcx(),
|
||||||
|
span,
|
||||||
|
E0109,
|
||||||
|
"{kind} arguments are not allowed on {this_type}",
|
||||||
|
);
|
||||||
|
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
|
||||||
|
for (what, span) in types_and_spans {
|
||||||
|
err.span_label(span, format!("not allowed on {what}"));
|
||||||
|
}
|
||||||
|
generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
|
||||||
|
let reported = err.emit();
|
||||||
|
self.set_tainted_by_errors(reported);
|
||||||
|
reported
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_trait_object_addition_traits_error(
|
||||||
|
&self,
|
||||||
|
regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
|
||||||
|
) -> ErrorGuaranteed {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let first_trait = ®ular_traits[0];
|
||||||
|
let additional_trait = ®ular_traits[1];
|
||||||
|
let mut err = struct_span_code_err!(
|
||||||
|
tcx.dcx(),
|
||||||
|
additional_trait.bottom().1,
|
||||||
|
E0225,
|
||||||
|
"only auto traits can be used as additional traits in a trait object"
|
||||||
|
);
|
||||||
|
additional_trait.label_with_exp_info(
|
||||||
|
&mut err,
|
||||||
|
"additional non-auto trait",
|
||||||
|
"additional use",
|
||||||
|
);
|
||||||
|
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
|
||||||
|
err.help(format!(
|
||||||
|
"consider creating a new trait with all of these as supertraits and using that \
|
||||||
|
trait here instead: `trait NewTrait: {} {{}}`",
|
||||||
|
regular_traits
|
||||||
|
.iter()
|
||||||
|
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
|
||||||
|
.map(|t| t.trait_ref().print_only_trait_path().to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" + "),
|
||||||
|
));
|
||||||
|
err.note(
|
||||||
|
"auto-traits like `Send` and `Sync` are traits that have special properties; \
|
||||||
|
for more information on them, visit \
|
||||||
|
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
|
||||||
|
);
|
||||||
|
let reported = err.emit();
|
||||||
|
self.set_tainted_by_errors(reported);
|
||||||
|
reported
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_trait_object_with_no_traits_error(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
|
||||||
|
) -> ErrorGuaranteed {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let trait_alias_span = trait_bounds
|
||||||
|
.iter()
|
||||||
|
.map(|&(trait_ref, _)| trait_ref.def_id())
|
||||||
|
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
|
||||||
|
.map(|trait_ref| tcx.def_span(trait_ref));
|
||||||
|
let reported =
|
||||||
|
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
|
||||||
|
self.set_tainted_by_errors(reported);
|
||||||
|
reported
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emits an error regarding forbidden type binding associations
|
/// Emits an error regarding forbidden type binding associations
|
||||||
@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
|
|||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
segment: Option<(&hir::PathSegment<'_>, Span)>,
|
segment: Option<(&hir::PathSegment<'_>, Span)>,
|
||||||
) {
|
) -> ErrorGuaranteed {
|
||||||
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
|
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
|
||||||
span,
|
span,
|
||||||
fn_trait_expansion: if let Some((segment, span)) = segment
|
fn_trait_expansion: if let Some((segment, span)) = segment
|
||||||
@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fn_trait_to_string(
|
pub(crate) fn fn_trait_to_string(
|
||||||
@ -1099,3 +1270,208 @@ pub(crate) fn fn_trait_to_string(
|
|||||||
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
|
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used for generics args error extend.
|
||||||
|
pub enum GenericsArgsErrExtend<'tcx> {
|
||||||
|
EnumVariant {
|
||||||
|
qself: &'tcx hir::Ty<'tcx>,
|
||||||
|
assoc_segment: &'tcx hir::PathSegment<'tcx>,
|
||||||
|
adt_def: AdtDef<'tcx>,
|
||||||
|
},
|
||||||
|
OpaqueTy,
|
||||||
|
PrimTy(hir::PrimTy),
|
||||||
|
SelfTyAlias {
|
||||||
|
def_id: DefId,
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
SelfTyParam(Span),
|
||||||
|
TyParam(DefId),
|
||||||
|
DefVariant,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generics_args_err_extend<'a>(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
err_extend: GenericsArgsErrExtend<'_>,
|
||||||
|
) {
|
||||||
|
match err_extend {
|
||||||
|
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
|
||||||
|
err.note("enum variants can't have type parameters");
|
||||||
|
let type_name = tcx.item_name(adt_def.did());
|
||||||
|
let msg = format!(
|
||||||
|
"you might have meant to specify type parameters on enum \
|
||||||
|
`{type_name}`"
|
||||||
|
);
|
||||||
|
let Some(args) = assoc_segment.args else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
// Get the span of the generics args *including* the leading `::`.
|
||||||
|
// We do so by stretching args.span_ext to the left by 2. Earlier
|
||||||
|
// it was done based on the end of assoc segment but that sometimes
|
||||||
|
// led to impossible spans and caused issues like #116473
|
||||||
|
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
|
||||||
|
if tcx.generics_of(adt_def.did()).count() == 0 {
|
||||||
|
// FIXME(estebank): we could also verify that the arguments being
|
||||||
|
// work for the `enum`, instead of just looking if it takes *any*.
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
args_span,
|
||||||
|
format!("{type_name} doesn't have generic parameters"),
|
||||||
|
"",
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
|
||||||
|
err.note(msg);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let (qself_sugg_span, is_self) =
|
||||||
|
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||||
|
// If the path segment already has type params, we want to overwrite
|
||||||
|
// them.
|
||||||
|
match &path.segments {
|
||||||
|
// `segment` is the previous to last element on the path,
|
||||||
|
// which would normally be the `enum` itself, while the last
|
||||||
|
// `_` `PathSegment` corresponds to the variant.
|
||||||
|
[
|
||||||
|
..,
|
||||||
|
hir::PathSegment {
|
||||||
|
ident, args, res: Res::Def(DefKind::Enum, _), ..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
] => (
|
||||||
|
// We need to include the `::` in `Type::Variant::<Args>`
|
||||||
|
// to point the span to `::<Args>`, not just `<Args>`.
|
||||||
|
ident
|
||||||
|
.span
|
||||||
|
.shrink_to_hi()
|
||||||
|
.to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
[segment] => {
|
||||||
|
(
|
||||||
|
// We need to include the `::` in `Type::Variant::<Args>`
|
||||||
|
// to point the span to `::<Args>`, not just `<Args>`.
|
||||||
|
segment.ident.span.shrink_to_hi().to(segment
|
||||||
|
.args
|
||||||
|
.map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
|
||||||
|
kw::SelfUpper == segment.ident.name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
err.note(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err.note(msg);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let suggestion = vec![
|
||||||
|
if is_self {
|
||||||
|
// Account for people writing `Self::Variant::<Args>`, where
|
||||||
|
// `Self` is the enum, and suggest replacing `Self` with the
|
||||||
|
// appropriate type: `Type::<Args>::Variant`.
|
||||||
|
(qself.span, format!("{type_name}{snippet}"))
|
||||||
|
} else {
|
||||||
|
(qself_sugg_span, snippet)
|
||||||
|
},
|
||||||
|
(args_span, String::new()),
|
||||||
|
];
|
||||||
|
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
|
||||||
|
}
|
||||||
|
GenericsArgsErrExtend::PrimTy(prim_ty) => {
|
||||||
|
let name = prim_ty.name_str();
|
||||||
|
for segment in segments {
|
||||||
|
if let Some(args) = segment.args {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
segment.ident.span.shrink_to_hi().to(args.span_ext),
|
||||||
|
format!("primitive type `{name}` doesn't have generic parameters"),
|
||||||
|
"",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GenericsArgsErrExtend::OpaqueTy => {
|
||||||
|
err.note("`impl Trait` types can't have type parameters");
|
||||||
|
}
|
||||||
|
GenericsArgsErrExtend::DefVariant => {
|
||||||
|
err.note("enum variants can't have type parameters");
|
||||||
|
}
|
||||||
|
GenericsArgsErrExtend::TyParam(def_id) => {
|
||||||
|
if let Some(span) = tcx.def_ident_span(def_id) {
|
||||||
|
let name = tcx.item_name(def_id);
|
||||||
|
err.span_note(span, format!("type parameter `{name}` defined here"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GenericsArgsErrExtend::SelfTyParam(span) => {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"the `Self` type doesn't accept type parameters",
|
||||||
|
"",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
|
||||||
|
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
|
||||||
|
let span_of_impl = tcx.span_of_impl(def_id);
|
||||||
|
let def_id = match *ty.kind() {
|
||||||
|
ty::Adt(self_def, _) => self_def.did(),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_name = tcx.item_name(def_id);
|
||||||
|
let span_of_ty = tcx.def_ident_span(def_id);
|
||||||
|
let generics = tcx.generics_of(def_id).count();
|
||||||
|
|
||||||
|
let msg = format!("`Self` is of type `{ty}`");
|
||||||
|
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
|
||||||
|
let mut span: MultiSpan = vec![t_sp].into();
|
||||||
|
span.push_span_label(
|
||||||
|
i_sp,
|
||||||
|
format!("`Self` is on type `{type_name}` in this `impl`"),
|
||||||
|
);
|
||||||
|
let mut postfix = "";
|
||||||
|
if generics == 0 {
|
||||||
|
postfix = ", which doesn't have generic parameters";
|
||||||
|
}
|
||||||
|
span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
|
||||||
|
err.span_note(span, msg);
|
||||||
|
} else {
|
||||||
|
err.note(msg);
|
||||||
|
}
|
||||||
|
for segment in segments {
|
||||||
|
if let Some(args) = segment.args
|
||||||
|
&& segment.ident.name == kw::SelfUpper
|
||||||
|
{
|
||||||
|
if generics == 0 {
|
||||||
|
// FIXME(estebank): we could also verify that the arguments being
|
||||||
|
// work for the `enum`, instead of just looking if it takes *any*.
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
segment.ident.span.shrink_to_hi().to(args.span_ext),
|
||||||
|
"the `Self` type doesn't accept type parameters",
|
||||||
|
"",
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
segment.ident.span,
|
||||||
|
format!(
|
||||||
|
"the `Self` type doesn't accept type parameters, use the \
|
||||||
|
concrete type's name `{type_name}` instead if you want to \
|
||||||
|
specify its type parameters"
|
||||||
|
),
|
||||||
|
type_name,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
//! trait references and bounds.
|
//! trait references and bounds.
|
||||||
|
|
||||||
mod bounds;
|
mod bounds;
|
||||||
mod errors;
|
pub mod errors;
|
||||||
pub mod generics;
|
pub mod generics;
|
||||||
mod lint;
|
mod lint;
|
||||||
mod object_safety;
|
mod object_safety;
|
||||||
@ -22,14 +22,14 @@
|
|||||||
use crate::bounds::Bounds;
|
use crate::bounds::Bounds;
|
||||||
use crate::collect::HirPlaceholderCollector;
|
use crate::collect::HirPlaceholderCollector;
|
||||||
use crate::errors::AmbiguousLifetimeBound;
|
use crate::errors::AmbiguousLifetimeBound;
|
||||||
use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
|
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
|
||||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||||
use crate::middle::resolve_bound_vars as rbv;
|
use crate::middle::resolve_bound_vars as rbv;
|
||||||
use crate::require_c_abi_if_c_variadic;
|
use crate::require_c_abi_if_c_variadic;
|
||||||
use rustc_ast::TraitObjectSyntax;
|
use rustc_ast::TraitObjectSyntax;
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, MultiSpan,
|
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||||
@ -46,7 +46,7 @@
|
|||||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||||
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
|
use rustc_span::{sym, Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||||
@ -632,7 +632,10 @@ pub fn lower_impl_trait_ref(
|
|||||||
trait_ref: &hir::TraitRef<'tcx>,
|
trait_ref: &hir::TraitRef<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
) -> ty::TraitRef<'tcx> {
|
) -> ty::TraitRef<'tcx> {
|
||||||
self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
|
let _ = self.prohibit_generic_args(
|
||||||
|
trait_ref.path.segments.split_last().unwrap().1.iter(),
|
||||||
|
GenericsArgsErrExtend::None,
|
||||||
|
);
|
||||||
|
|
||||||
self.lower_mono_trait_ref(
|
self.lower_mono_trait_ref(
|
||||||
trait_ref.path.span,
|
trait_ref.path.span,
|
||||||
@ -681,7 +684,10 @@ pub(crate) fn lower_poly_trait_ref(
|
|||||||
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
|
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
|
||||||
let trait_segment = trait_ref.path.segments.last().unwrap();
|
let trait_segment = trait_ref.path.segments.last().unwrap();
|
||||||
|
|
||||||
self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
|
let _ = self.prohibit_generic_args(
|
||||||
|
trait_ref.path.segments.split_last().unwrap().1.iter(),
|
||||||
|
GenericsArgsErrExtend::None,
|
||||||
|
);
|
||||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
|
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
|
||||||
|
|
||||||
let (generic_args, arg_count) = self.lower_generic_args_of_path(
|
let (generic_args, arg_count) = self.lower_generic_args_of_path(
|
||||||
@ -995,8 +1001,8 @@ pub fn lower_assoc_path(
|
|||||||
hir_ref_id: hir::HirId,
|
hir_ref_id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
qself_ty: Ty<'tcx>,
|
qself_ty: Ty<'tcx>,
|
||||||
qself: &hir::Ty<'_>,
|
qself: &'tcx hir::Ty<'tcx>,
|
||||||
assoc_segment: &hir::PathSegment<'tcx>,
|
assoc_segment: &'tcx hir::PathSegment<'tcx>,
|
||||||
permit_variants: bool,
|
permit_variants: bool,
|
||||||
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
|
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
|
||||||
debug!(%qself_ty, ?assoc_segment.ident);
|
debug!(%qself_ty, ?assoc_segment.ident);
|
||||||
@ -1020,99 +1026,10 @@ pub fn lower_assoc_path(
|
|||||||
if let Some(variant_def) = variant_def {
|
if let Some(variant_def) = variant_def {
|
||||||
if permit_variants {
|
if permit_variants {
|
||||||
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
||||||
self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
err.note("enum variants can't have type parameters");
|
slice::from_ref(assoc_segment).iter(),
|
||||||
let type_name = tcx.item_name(adt_def.did());
|
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
|
||||||
let msg = format!(
|
);
|
||||||
"you might have meant to specify type parameters on enum \
|
|
||||||
`{type_name}`"
|
|
||||||
);
|
|
||||||
let Some(args) = assoc_segment.args else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// Get the span of the generics args *including* the leading `::`.
|
|
||||||
// We do so by stretching args.span_ext to the left by 2. Earlier
|
|
||||||
// it was done based on the end of assoc segment but that sometimes
|
|
||||||
// led to impossible spans and caused issues like #116473
|
|
||||||
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
|
|
||||||
if tcx.generics_of(adt_def.did()).count() == 0 {
|
|
||||||
// FIXME(estebank): we could also verify that the arguments being
|
|
||||||
// work for the `enum`, instead of just looking if it takes *any*.
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
args_span,
|
|
||||||
format!("{type_name} doesn't have generic parameters"),
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span)
|
|
||||||
else {
|
|
||||||
err.note(msg);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let (qself_sugg_span, is_self) =
|
|
||||||
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
|
|
||||||
&qself.kind
|
|
||||||
{
|
|
||||||
// If the path segment already has type params, we want to overwrite
|
|
||||||
// them.
|
|
||||||
match &path.segments {
|
|
||||||
// `segment` is the previous to last element on the path,
|
|
||||||
// which would normally be the `enum` itself, while the last
|
|
||||||
// `_` `PathSegment` corresponds to the variant.
|
|
||||||
[
|
|
||||||
..,
|
|
||||||
hir::PathSegment {
|
|
||||||
ident,
|
|
||||||
args,
|
|
||||||
res: Res::Def(DefKind::Enum, _),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
_,
|
|
||||||
] => (
|
|
||||||
// We need to include the `::` in `Type::Variant::<Args>`
|
|
||||||
// to point the span to `::<Args>`, not just `<Args>`.
|
|
||||||
ident.span.shrink_to_hi().to(args
|
|
||||||
.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
[segment] => (
|
|
||||||
// We need to include the `::` in `Type::Variant::<Args>`
|
|
||||||
// to point the span to `::<Args>`, not just `<Args>`.
|
|
||||||
segment.ident.span.shrink_to_hi().to(segment
|
|
||||||
.args
|
|
||||||
.map_or(segment.ident.span.shrink_to_hi(), |a| {
|
|
||||||
a.span_ext
|
|
||||||
})),
|
|
||||||
kw::SelfUpper == segment.ident.name,
|
|
||||||
),
|
|
||||||
_ => {
|
|
||||||
err.note(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err.note(msg);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let suggestion = vec![
|
|
||||||
if is_self {
|
|
||||||
// Account for people writing `Self::Variant::<Args>`, where
|
|
||||||
// `Self` is the enum, and suggest replacing `Self` with the
|
|
||||||
// appropriate type: `Type::<Args>::Variant`.
|
|
||||||
(qself.span, format!("{type_name}{snippet}"))
|
|
||||||
} else {
|
|
||||||
(qself_sugg_span, snippet)
|
|
||||||
},
|
|
||||||
(args_span, String::new()),
|
|
||||||
];
|
|
||||||
err.multipart_suggestion_verbose(
|
|
||||||
msg,
|
|
||||||
suggestion,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
|
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
|
||||||
} else {
|
} else {
|
||||||
variant_resolution = Some(variant_def.def_id);
|
variant_resolution = Some(variant_def.def_id);
|
||||||
@ -1624,111 +1541,26 @@ fn lower_qpath(
|
|||||||
pub fn prohibit_generic_args<'a>(
|
pub fn prohibit_generic_args<'a>(
|
||||||
&self,
|
&self,
|
||||||
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||||
extend: impl Fn(&mut Diag<'_>),
|
err_extend: GenericsArgsErrExtend<'_>,
|
||||||
) -> bool {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let args = segments.clone().flat_map(|segment| segment.args().args);
|
let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
|
||||||
|
let mut result = Ok(());
|
||||||
let (lt, ty, ct, inf) =
|
if let Some(_) = args_visitors.clone().next() {
|
||||||
args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
|
result = Err(self.report_prohibit_generics_error(
|
||||||
hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
|
segments.clone(),
|
||||||
hir::GenericArg::Type(_) => (lt, true, ct, inf),
|
args_visitors,
|
||||||
hir::GenericArg::Const(_) => (lt, ty, true, inf),
|
err_extend,
|
||||||
hir::GenericArg::Infer(_) => (lt, ty, ct, true),
|
));
|
||||||
});
|
|
||||||
let mut emitted = false;
|
|
||||||
if lt || ty || ct || inf {
|
|
||||||
let types_and_spans: Vec<_> = segments
|
|
||||||
.clone()
|
|
||||||
.flat_map(|segment| {
|
|
||||||
if segment.args().args.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((
|
|
||||||
match segment.res {
|
|
||||||
Res::PrimTy(ty) => {
|
|
||||||
format!("{} `{}`", segment.res.descr(), ty.name())
|
|
||||||
}
|
|
||||||
Res::Def(_, def_id)
|
|
||||||
if let Some(name) = self.tcx().opt_item_name(def_id) =>
|
|
||||||
{
|
|
||||||
format!("{} `{name}`", segment.res.descr())
|
|
||||||
}
|
|
||||||
Res::Err => "this type".to_string(),
|
|
||||||
_ => segment.res.descr().to_string(),
|
|
||||||
},
|
|
||||||
segment.ident.span,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let this_type = match &types_and_spans[..] {
|
|
||||||
[.., _, (last, _)] => format!(
|
|
||||||
"{} and {last}",
|
|
||||||
types_and_spans[..types_and_spans.len() - 1]
|
|
||||||
.iter()
|
|
||||||
.map(|(x, _)| x.as_str())
|
|
||||||
.intersperse(", ")
|
|
||||||
.collect::<String>()
|
|
||||||
),
|
|
||||||
[(only, _)] => only.to_string(),
|
|
||||||
[] => "this type".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
|
|
||||||
|
|
||||||
let mut kinds = Vec::with_capacity(4);
|
|
||||||
if lt {
|
|
||||||
kinds.push("lifetime");
|
|
||||||
}
|
|
||||||
if ty {
|
|
||||||
kinds.push("type");
|
|
||||||
}
|
|
||||||
if ct {
|
|
||||||
kinds.push("const");
|
|
||||||
}
|
|
||||||
if inf {
|
|
||||||
kinds.push("generic");
|
|
||||||
}
|
|
||||||
let (kind, s) = match kinds[..] {
|
|
||||||
[.., _, last] => (
|
|
||||||
format!(
|
|
||||||
"{} and {last}",
|
|
||||||
kinds[..kinds.len() - 1]
|
|
||||||
.iter()
|
|
||||||
.map(|&x| x)
|
|
||||||
.intersperse(", ")
|
|
||||||
.collect::<String>()
|
|
||||||
),
|
|
||||||
"s",
|
|
||||||
),
|
|
||||||
[only] => (only.to_string(), ""),
|
|
||||||
[] => unreachable!("expected at least one generic to prohibit"),
|
|
||||||
};
|
|
||||||
let last_span = *arg_spans.last().unwrap();
|
|
||||||
let span: MultiSpan = arg_spans.into();
|
|
||||||
let mut err = struct_span_code_err!(
|
|
||||||
self.tcx().dcx(),
|
|
||||||
span,
|
|
||||||
E0109,
|
|
||||||
"{kind} arguments are not allowed on {this_type}",
|
|
||||||
);
|
|
||||||
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
|
|
||||||
for (what, span) in types_and_spans {
|
|
||||||
err.span_label(span, format!("not allowed on {what}"));
|
|
||||||
}
|
|
||||||
extend(&mut err);
|
|
||||||
self.set_tainted_by_errors(err.emit());
|
|
||||||
emitted = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for segment in segments {
|
for segment in segments {
|
||||||
// Only emit the first error to avoid overloading the user with error messages.
|
// Only emit the first error to avoid overloading the user with error messages.
|
||||||
if let Some(b) = segment.args().bindings.first() {
|
if let Some(b) = segment.args().bindings.first() {
|
||||||
prohibit_assoc_item_binding(self.tcx(), b.span, None);
|
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitted
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Probe path segments that are semantically allowed to have generic arguments.
|
/// Probe path segments that are semantically allowed to have generic arguments.
|
||||||
@ -1893,9 +1725,8 @@ pub fn lower_path(
|
|||||||
// Check for desugared `impl Trait`.
|
// Check for desugared `impl Trait`.
|
||||||
assert!(tcx.is_type_alias_impl_trait(did));
|
assert!(tcx.is_type_alias_impl_trait(did));
|
||||||
let item_segment = path.segments.split_last().unwrap();
|
let item_segment = path.segments.split_last().unwrap();
|
||||||
self.prohibit_generic_args(item_segment.1.iter(), |err| {
|
let _ = self
|
||||||
err.note("`impl Trait` types can't have type parameters");
|
.prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
|
||||||
});
|
|
||||||
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
|
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
|
||||||
Ty::new_opaque(tcx, did, args)
|
Ty::new_opaque(tcx, did, args)
|
||||||
}
|
}
|
||||||
@ -1908,7 +1739,10 @@ pub fn lower_path(
|
|||||||
did,
|
did,
|
||||||
) => {
|
) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
|
let _ = self.prohibit_generic_args(
|
||||||
|
path.segments.split_last().unwrap().1.iter(),
|
||||||
|
GenericsArgsErrExtend::None,
|
||||||
|
);
|
||||||
self.lower_path_segment(span, did, path.segments.last().unwrap())
|
self.lower_path_segment(span, did, path.segments.last().unwrap())
|
||||||
}
|
}
|
||||||
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
|
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
|
||||||
@ -1920,13 +1754,11 @@ pub fn lower_path(
|
|||||||
self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
|
self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
|
||||||
let indices: FxHashSet<_> =
|
let indices: FxHashSet<_> =
|
||||||
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
||||||
self.prohibit_generic_args(
|
let _ = self.prohibit_generic_args(
|
||||||
path.segments.iter().enumerate().filter_map(|(index, seg)| {
|
path.segments.iter().enumerate().filter_map(|(index, seg)| {
|
||||||
if !indices.contains(&index) { Some(seg) } else { None }
|
if !indices.contains(&index) { Some(seg) } else { None }
|
||||||
}),
|
}),
|
||||||
|err| {
|
GenericsArgsErrExtend::DefVariant,
|
||||||
err.note("enum variants can't have type parameters");
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
|
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
|
||||||
@ -1934,27 +1766,25 @@ pub fn lower_path(
|
|||||||
}
|
}
|
||||||
Res::Def(DefKind::TyParam, def_id) => {
|
Res::Def(DefKind::TyParam, def_id) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
if let Some(span) = tcx.def_ident_span(def_id) {
|
path.segments.iter(),
|
||||||
let name = tcx.item_name(def_id);
|
GenericsArgsErrExtend::TyParam(def_id),
|
||||||
err.span_note(span, format!("type parameter `{name}` defined here"));
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
self.lower_ty_param(hir_id)
|
self.lower_ty_param(hir_id)
|
||||||
}
|
}
|
||||||
Res::SelfTyParam { .. } => {
|
Res::SelfTyParam { .. } => {
|
||||||
// `Self` in trait or type alias.
|
// `Self` in trait or type alias.
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
|
path.segments.iter(),
|
||||||
if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
|
if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
|
||||||
err.span_suggestion_verbose(
|
GenericsArgsErrExtend::SelfTyParam(
|
||||||
ident.span.shrink_to_hi().to(args.span_ext),
|
ident.span.shrink_to_hi().to(args.span_ext),
|
||||||
"the `Self` type doesn't accept type parameters",
|
)
|
||||||
"",
|
} else {
|
||||||
Applicability::MaybeIncorrect,
|
GenericsArgsErrExtend::None
|
||||||
);
|
},
|
||||||
}
|
);
|
||||||
});
|
|
||||||
tcx.types.self_param
|
tcx.types.self_param
|
||||||
}
|
}
|
||||||
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
|
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
|
||||||
@ -1962,65 +1792,10 @@ pub fn lower_path(
|
|||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
// Try to evaluate any array length constants.
|
// Try to evaluate any array length constants.
|
||||||
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
|
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
|
||||||
let span_of_impl = tcx.span_of_impl(def_id);
|
let _ = self.prohibit_generic_args(
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
path.segments.iter(),
|
||||||
let def_id = match *ty.kind() {
|
GenericsArgsErrExtend::SelfTyAlias { def_id, span },
|
||||||
ty::Adt(self_def, _) => self_def.did(),
|
);
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_name = tcx.item_name(def_id);
|
|
||||||
let span_of_ty = tcx.def_ident_span(def_id);
|
|
||||||
let generics = tcx.generics_of(def_id).count();
|
|
||||||
|
|
||||||
let msg = format!("`Self` is of type `{ty}`");
|
|
||||||
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
|
|
||||||
let mut span: MultiSpan = vec![t_sp].into();
|
|
||||||
span.push_span_label(
|
|
||||||
i_sp,
|
|
||||||
format!("`Self` is on type `{type_name}` in this `impl`"),
|
|
||||||
);
|
|
||||||
let mut postfix = "";
|
|
||||||
if generics == 0 {
|
|
||||||
postfix = ", which doesn't have generic parameters";
|
|
||||||
}
|
|
||||||
span.push_span_label(
|
|
||||||
t_sp,
|
|
||||||
format!("`Self` corresponds to this type{postfix}"),
|
|
||||||
);
|
|
||||||
err.span_note(span, msg);
|
|
||||||
} else {
|
|
||||||
err.note(msg);
|
|
||||||
}
|
|
||||||
for segment in path.segments {
|
|
||||||
if let Some(args) = segment.args
|
|
||||||
&& segment.ident.name == kw::SelfUpper
|
|
||||||
{
|
|
||||||
if generics == 0 {
|
|
||||||
// FIXME(estebank): we could also verify that the arguments being
|
|
||||||
// work for the `enum`, instead of just looking if it takes *any*.
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
segment.ident.span.shrink_to_hi().to(args.span_ext),
|
|
||||||
"the `Self` type doesn't accept type parameters",
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
segment.ident.span,
|
|
||||||
format!(
|
|
||||||
"the `Self` type doesn't accept type parameters, use the \
|
|
||||||
concrete type's name `{type_name}` instead if you want to \
|
|
||||||
specify its type parameters"
|
|
||||||
),
|
|
||||||
type_name,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// HACK(min_const_generics): Forbid generic `Self` types
|
// HACK(min_const_generics): Forbid generic `Self` types
|
||||||
// here as we can't easily do that during nameres.
|
// here as we can't easily do that during nameres.
|
||||||
//
|
//
|
||||||
@ -2061,7 +1836,10 @@ pub fn lower_path(
|
|||||||
}
|
}
|
||||||
Res::Def(DefKind::AssocTy, def_id) => {
|
Res::Def(DefKind::AssocTy, def_id) => {
|
||||||
debug_assert!(path.segments.len() >= 2);
|
debug_assert!(path.segments.len() >= 2);
|
||||||
self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
|
let _ = self.prohibit_generic_args(
|
||||||
|
path.segments[..path.segments.len() - 2].iter(),
|
||||||
|
GenericsArgsErrExtend::None,
|
||||||
|
);
|
||||||
// HACK: until we support `<Type as ~const Trait>`, assume all of them are.
|
// HACK: until we support `<Type as ~const Trait>`, assume all of them are.
|
||||||
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
|
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
|
||||||
ty::BoundConstness::ConstIfConst
|
ty::BoundConstness::ConstIfConst
|
||||||
@ -2079,19 +1857,10 @@ pub fn lower_path(
|
|||||||
}
|
}
|
||||||
Res::PrimTy(prim_ty) => {
|
Res::PrimTy(prim_ty) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
let name = prim_ty.name_str();
|
path.segments.iter(),
|
||||||
for segment in path.segments {
|
GenericsArgsErrExtend::PrimTy(prim_ty),
|
||||||
if let Some(args) = segment.args {
|
);
|
||||||
err.span_suggestion_verbose(
|
|
||||||
segment.ident.span.shrink_to_hi().to(args.span_ext),
|
|
||||||
format!("primitive type `{name}` doesn't have generic parameters"),
|
|
||||||
"",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match prim_ty {
|
match prim_ty {
|
||||||
hir::PrimTy::Bool => tcx.types.bool,
|
hir::PrimTy::Bool => tcx.types.bool,
|
||||||
hir::PrimTy::Char => tcx.types.char,
|
hir::PrimTy::Char => tcx.types.char,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::bounds::Bounds;
|
use crate::bounds::Bounds;
|
||||||
use crate::errors::TraitObjectDeclaredWithNoTraits;
|
|
||||||
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
|
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::{codes::*, struct_span_code_err};
|
use rustc_errors::{codes::*, struct_span_code_err};
|
||||||
@ -86,47 +85,9 @@ pub(super) fn lower_trait_object_ty(
|
|||||||
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
||||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
||||||
if regular_traits.len() > 1 {
|
if regular_traits.len() > 1 {
|
||||||
let first_trait = ®ular_traits[0];
|
let _ = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||||
let additional_trait = ®ular_traits[1];
|
} else if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||||
let mut err = struct_span_code_err!(
|
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
|
||||||
tcx.dcx(),
|
|
||||||
additional_trait.bottom().1,
|
|
||||||
E0225,
|
|
||||||
"only auto traits can be used as additional traits in a trait object"
|
|
||||||
);
|
|
||||||
additional_trait.label_with_exp_info(
|
|
||||||
&mut err,
|
|
||||||
"additional non-auto trait",
|
|
||||||
"additional use",
|
|
||||||
);
|
|
||||||
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
|
|
||||||
err.help(format!(
|
|
||||||
"consider creating a new trait with all of these as supertraits and using that \
|
|
||||||
trait here instead: `trait NewTrait: {} {{}}`",
|
|
||||||
regular_traits
|
|
||||||
.iter()
|
|
||||||
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
|
|
||||||
.map(|t| t.trait_ref().print_only_trait_path().to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" + "),
|
|
||||||
));
|
|
||||||
err.note(
|
|
||||||
"auto-traits like `Send` and `Sync` are traits that have special properties; \
|
|
||||||
for more information on them, visit \
|
|
||||||
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
|
|
||||||
);
|
|
||||||
self.set_tainted_by_errors(err.emit());
|
|
||||||
}
|
|
||||||
|
|
||||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
|
||||||
let trait_alias_span = trait_bounds
|
|
||||||
.iter()
|
|
||||||
.map(|&(trait_ref, _)| trait_ref.def_id())
|
|
||||||
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
|
|
||||||
.map(|trait_ref| tcx.def_span(trait_ref));
|
|
||||||
let reported =
|
|
||||||
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
|
|
||||||
self.set_tainted_by_errors(reported);
|
|
||||||
return Ty::new_error(tcx, reported);
|
return Ty::new_error(tcx, reported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ hir_typeck_invalid_callee = expected function, found {$ty}
|
|||||||
hir_typeck_lossy_provenance_int2ptr =
|
hir_typeck_lossy_provenance_int2ptr =
|
||||||
strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
|
strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
|
||||||
.suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
|
.suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
|
||||||
.help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
|
.help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
|
||||||
|
|
||||||
hir_typeck_lossy_provenance_ptr2int =
|
hir_typeck_lossy_provenance_ptr2int =
|
||||||
under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
|
under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
||||||
|
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
|
||||||
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||||
check_generic_arg_count_for_call, lower_generic_args,
|
check_generic_arg_count_for_call, lower_generic_args,
|
||||||
};
|
};
|
||||||
@ -1177,11 +1178,11 @@ pub fn instantiate_value_path(
|
|||||||
|
|
||||||
let indices: FxHashSet<_> =
|
let indices: FxHashSet<_> =
|
||||||
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
||||||
let generics_has_err = self.lowerer().prohibit_generic_args(
|
let generics_err = self.lowerer().prohibit_generic_args(
|
||||||
segments.iter().enumerate().filter_map(|(index, seg)| {
|
segments.iter().enumerate().filter_map(|(index, seg)| {
|
||||||
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
|
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
|
||||||
}),
|
}),
|
||||||
|_| {},
|
GenericsArgsErrExtend::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Res::Local(hid) = res {
|
if let Res::Local(hid) = res {
|
||||||
@ -1191,7 +1192,7 @@ pub fn instantiate_value_path(
|
|||||||
return (ty, res);
|
return (ty, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
if generics_has_err {
|
if let Err(_) = generics_err {
|
||||||
// Don't try to infer type parameters when prohibited generic arguments were given.
|
// Don't try to infer type parameters when prohibited generic arguments were given.
|
||||||
user_self_ty = None;
|
user_self_ty = None;
|
||||||
}
|
}
|
||||||
|
@ -2749,7 +2749,7 @@
|
|||||||
/// memory the pointer is allowed to read/write. Casting an integer, which
|
/// memory the pointer is allowed to read/write. Casting an integer, which
|
||||||
/// doesn't have provenance, to a pointer requires the compiler to assign
|
/// doesn't have provenance, to a pointer requires the compiler to assign
|
||||||
/// (guess) provenance. The compiler assigns "all exposed valid" (see the
|
/// (guess) provenance. The compiler assigns "all exposed valid" (see the
|
||||||
/// docs of [`ptr::from_exposed_addr`] for more information about this
|
/// docs of [`ptr::with_exposed_provenance`] for more information about this
|
||||||
/// "exposing"). This penalizes the optimiser and is not well suited for
|
/// "exposing"). This penalizes the optimiser and is not well suited for
|
||||||
/// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
|
/// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
|
||||||
/// platforms).
|
/// platforms).
|
||||||
@ -2757,11 +2757,11 @@
|
|||||||
/// It is much better to use [`ptr::with_addr`] instead to specify the
|
/// It is much better to use [`ptr::with_addr`] instead to specify the
|
||||||
/// provenance you want. If using this function is not possible because the
|
/// provenance you want. If using this function is not possible because the
|
||||||
/// code relies on exposed provenance then there is as an escape hatch
|
/// code relies on exposed provenance then there is as an escape hatch
|
||||||
/// [`ptr::from_exposed_addr`].
|
/// [`ptr::with_exposed_provenance`].
|
||||||
///
|
///
|
||||||
/// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
|
/// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
|
||||||
/// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
|
/// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
|
||||||
/// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr.html
|
/// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html
|
||||||
pub FUZZY_PROVENANCE_CASTS,
|
pub FUZZY_PROVENANCE_CASTS,
|
||||||
Allow,
|
Allow,
|
||||||
"a fuzzy integer to pointer cast is used",
|
"a fuzzy integer to pointer cast is used",
|
||||||
|
@ -426,7 +426,7 @@ pub fn is_safe_to_remove(&self) -> bool {
|
|||||||
| CastKind::FnPtrToPtr
|
| CastKind::FnPtrToPtr
|
||||||
| CastKind::PtrToPtr
|
| CastKind::PtrToPtr
|
||||||
| CastKind::PointerCoercion(_)
|
| CastKind::PointerCoercion(_)
|
||||||
| CastKind::PointerFromExposedAddress
|
| CastKind::PointerWithExposedProvenance
|
||||||
| CastKind::DynStar
|
| CastKind::DynStar
|
||||||
| CastKind::Transmute,
|
| CastKind::Transmute,
|
||||||
_,
|
_,
|
||||||
|
@ -1312,8 +1312,8 @@ pub enum CastKind {
|
|||||||
/// See the docs on `expose_addr` for more details.
|
/// See the docs on `expose_addr` for more details.
|
||||||
PointerExposeAddress,
|
PointerExposeAddress,
|
||||||
/// An address-to-pointer cast that picks up an exposed provenance.
|
/// An address-to-pointer cast that picks up an exposed provenance.
|
||||||
/// See the docs on `from_exposed_addr` for more details.
|
/// See the docs on `with_exposed_provenance` for more details.
|
||||||
PointerFromExposedAddress,
|
PointerWithExposedProvenance,
|
||||||
/// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are
|
/// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are
|
||||||
/// translated into `&raw mut/const *r`, i.e., they are not actually casts.
|
/// translated into `&raw mut/const *r`, i.e., they are not actually casts.
|
||||||
PointerCoercion(PointerCoercion),
|
PointerCoercion(PointerCoercion),
|
||||||
|
@ -85,7 +85,7 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin
|
|||||||
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
|
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
|
||||||
mir::CastKind::PointerExposeAddress
|
mir::CastKind::PointerExposeAddress
|
||||||
}
|
}
|
||||||
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerFromExposedAddress,
|
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance,
|
||||||
(_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
|
(_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
|
||||||
(Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
|
(Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
|
||||||
(Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
|
(Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
|
||||||
|
@ -268,7 +268,7 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
|||||||
use rustc_middle::mir::CastKind::*;
|
use rustc_middle::mir::CastKind::*;
|
||||||
match self {
|
match self {
|
||||||
PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
|
PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
|
||||||
PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
|
PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
|
||||||
PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
|
PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
|
||||||
DynStar => stable_mir::mir::CastKind::DynStar,
|
DynStar => stable_mir::mir::CastKind::DynStar,
|
||||||
IntToInt => stable_mir::mir::CastKind::IntToInt,
|
IntToInt => stable_mir::mir::CastKind::IntToInt,
|
||||||
|
@ -1675,7 +1675,6 @@
|
|||||||
simd_fmin,
|
simd_fmin,
|
||||||
simd_fpow,
|
simd_fpow,
|
||||||
simd_fpowi,
|
simd_fpowi,
|
||||||
simd_from_exposed_addr,
|
|
||||||
simd_fsin,
|
simd_fsin,
|
||||||
simd_fsqrt,
|
simd_fsqrt,
|
||||||
simd_gather,
|
simd_gather,
|
||||||
@ -1714,6 +1713,7 @@
|
|||||||
simd_shuffle_generic,
|
simd_shuffle_generic,
|
||||||
simd_sub,
|
simd_sub,
|
||||||
simd_trunc,
|
simd_trunc,
|
||||||
|
simd_with_exposed_provenance,
|
||||||
simd_xor,
|
simd_xor,
|
||||||
since,
|
since,
|
||||||
sinf128,
|
sinf128,
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
|
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
|
||||||
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
|
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
|
||||||
};
|
};
|
||||||
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
|
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
|
||||||
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
|
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
|
||||||
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
|
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
|
||||||
|
|
||||||
|
@ -972,7 +972,7 @@ pub enum PointerCoercion {
|
|||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum CastKind {
|
pub enum CastKind {
|
||||||
PointerExposeAddress,
|
PointerExposeAddress,
|
||||||
PointerFromExposedAddress,
|
PointerWithExposedProvenance,
|
||||||
PointerCoercion(PointerCoercion),
|
PointerCoercion(PointerCoercion),
|
||||||
DynStar,
|
DynStar,
|
||||||
IntToInt,
|
IntToInt,
|
||||||
|
@ -549,6 +549,10 @@
|
|||||||
///
|
///
|
||||||
/// `U` must be a vector of pointers, with the same length as `T`.
|
/// `U` must be a vector of pointers, with the same length as `T`.
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub fn simd_with_exposed_provenance<T, U>(addr: T) -> U;
|
||||||
|
#[rustc_nounwind]
|
||||||
|
#[cfg(bootstrap)]
|
||||||
pub fn simd_from_exposed_addr<T, U>(addr: T) -> U;
|
pub fn simd_from_exposed_addr<T, U>(addr: T) -> U;
|
||||||
|
|
||||||
/// Swap bytes of each element.
|
/// Swap bytes of each element.
|
||||||
@ -655,3 +659,6 @@
|
|||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
pub fn simd_flog<T>(a: T) -> T;
|
pub fn simd_flog<T>(a: T) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
pub use simd_from_exposed_addr as simd_with_exposed_provenance;
|
||||||
|
@ -165,7 +165,7 @@ pub fn to_bits(self) -> usize
|
|||||||
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
|
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "1.67.0",
|
since = "1.67.0",
|
||||||
note = "replaced by the `ptr::from_exposed_addr` function, or update \
|
note = "replaced by the `ptr::with_exposed_provenance` function, or update \
|
||||||
your code to follow the strict provenance rules using its APIs"
|
your code to follow the strict provenance rules using its APIs"
|
||||||
)]
|
)]
|
||||||
#[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
|
#[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
|
||||||
@ -187,7 +187,7 @@ pub fn from_bits(bits: usize) -> Self
|
|||||||
///
|
///
|
||||||
/// If using those APIs is not possible because there is no way to preserve a pointer with the
|
/// If using those APIs is not possible because there is no way to preserve a pointer with the
|
||||||
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
||||||
/// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
|
/// or [`expose_addr`][pointer::expose_addr] and [`with_exposed_provenance`][with_exposed_provenance]
|
||||||
/// instead. However, note that this makes your code less portable and less amenable to tools
|
/// instead. However, note that this makes your code less portable and less amenable to tools
|
||||||
/// that check for compliance with the Rust memory model.
|
/// that check for compliance with the Rust memory model.
|
||||||
///
|
///
|
||||||
@ -211,30 +211,30 @@ pub fn addr(self) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
|
/// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
|
||||||
/// use in [`from_exposed_addr`][].
|
/// use in [`with_exposed_provenance`][].
|
||||||
///
|
///
|
||||||
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
|
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
|
||||||
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
|
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
|
||||||
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
|
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
|
||||||
/// later call [`from_exposed_addr`][] to reconstitute the original pointer including its
|
/// later call [`with_exposed_provenance`][] to reconstitute the original pointer including its
|
||||||
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
|
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
|
||||||
///
|
///
|
||||||
/// Using this method means that code is *not* following [Strict
|
/// Using this method means that code is *not* following [Strict
|
||||||
/// Provenance][super#strict-provenance] rules. Supporting
|
/// Provenance][super#strict-provenance] rules. Supporting
|
||||||
/// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by
|
/// [`with_exposed_provenance`][] complicates specification and reasoning and may not be supported by
|
||||||
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
|
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
|
||||||
/// use [`addr`][pointer::addr] wherever possible.
|
/// use [`addr`][pointer::addr] wherever possible.
|
||||||
///
|
///
|
||||||
/// On most platforms this will produce a value with the same bytes as the original pointer,
|
/// On most platforms this will produce a value with the same bytes as the original pointer,
|
||||||
/// because all the bytes are dedicated to describing the address. Platforms which need to store
|
/// because all the bytes are dedicated to describing the address. Platforms which need to store
|
||||||
/// additional information in the pointer may not support this operation, since the 'expose'
|
/// additional information in the pointer may not support this operation, since the 'expose'
|
||||||
/// side-effect which is required for [`from_exposed_addr`][] to work is typically not
|
/// side-effect which is required for [`with_exposed_provenance`][] to work is typically not
|
||||||
/// available.
|
/// available.
|
||||||
///
|
///
|
||||||
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
|
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
|
||||||
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
|
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
|
||||||
///
|
///
|
||||||
/// [`from_exposed_addr`]: from_exposed_addr
|
/// [`with_exposed_provenance`]: with_exposed_provenance
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
||||||
|
@ -340,13 +340,13 @@
|
|||||||
//! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance.
|
//! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance.
|
||||||
//! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI].
|
//! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI].
|
||||||
//!
|
//!
|
||||||
//! Exposed Provenance is provided by the [`expose_addr`] and [`from_exposed_addr`] methods, which
|
//! Exposed Provenance is provided by the [`expose_addr`] and [`with_exposed_provenance`] methods, which
|
||||||
//! are meant to replace `as` casts between pointers and integers. [`expose_addr`] is a lot like
|
//! are meant to replace `as` casts between pointers and integers. [`expose_addr`] is a lot like
|
||||||
//! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed'
|
//! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed'
|
||||||
//! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but
|
//! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but
|
||||||
//! is not materialized in actual executions, except in tools like [Miri].) [`from_exposed_addr`]
|
//! is not materialized in actual executions, except in tools like [Miri].) [`with_exposed_provenance`]
|
||||||
//! can be used to construct a pointer with one of these previously 'exposed' provenances.
|
//! can be used to construct a pointer with one of these previously 'exposed' provenances.
|
||||||
//! [`from_exposed_addr`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
|
//! [`with_exposed_provenance`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is
|
||||||
//! no indication of what the correct provenance for the returned pointer is -- and that is exactly
|
//! no indication of what the correct provenance for the returned pointer is -- and that is exactly
|
||||||
//! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! There is no
|
//! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! There is no
|
||||||
//! algorithm that decides which provenance will be used. You can think of this as "guessing" the
|
//! algorithm that decides which provenance will be used. You can think of this as "guessing" the
|
||||||
@ -355,10 +355,10 @@
|
|||||||
//! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will
|
//! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will
|
||||||
//! be used, the program has undefined behavior.
|
//! be used, the program has undefined behavior.
|
||||||
//!
|
//!
|
||||||
//! Using [`expose_addr`] or [`from_exposed_addr`] (or the `as` casts) means that code is
|
//! Using [`expose_addr`] or [`with_exposed_provenance`] (or the `as` casts) means that code is
|
||||||
//! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to
|
//! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to
|
||||||
//! determine how far one can get in Rust without the use of [`expose_addr`] and
|
//! determine how far one can get in Rust without the use of [`expose_addr`] and
|
||||||
//! [`from_exposed_addr`], and to encourage code to be written with Strict Provenance APIs only.
|
//! [`with_exposed_provenance`], and to encourage code to be written with Strict Provenance APIs only.
|
||||||
//! Maximizing the amount of such code is a major win for avoiding specification complexity and to
|
//! Maximizing the amount of such code is a major win for avoiding specification complexity and to
|
||||||
//! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the
|
//! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the
|
||||||
//! confidence in (unsafe) Rust code.
|
//! confidence in (unsafe) Rust code.
|
||||||
@ -375,7 +375,7 @@
|
|||||||
//! [`addr`]: pointer::addr
|
//! [`addr`]: pointer::addr
|
||||||
//! [`ptr::dangling`]: core::ptr::dangling
|
//! [`ptr::dangling`]: core::ptr::dangling
|
||||||
//! [`expose_addr`]: pointer::expose_addr
|
//! [`expose_addr`]: pointer::expose_addr
|
||||||
//! [`from_exposed_addr`]: from_exposed_addr
|
//! [`with_exposed_provenance`]: with_exposed_provenance
|
||||||
//! [Miri]: https://github.com/rust-lang/miri
|
//! [Miri]: https://github.com/rust-lang/miri
|
||||||
//! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
|
//! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
|
||||||
//! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228
|
//! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228
|
||||||
@ -581,7 +581,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
|
|||||||
/// little more than a usize address in disguise.
|
/// little more than a usize address in disguise.
|
||||||
///
|
///
|
||||||
/// This is different from `addr as *const T`, which creates a pointer that picks up a previously
|
/// This is different from `addr as *const T`, which creates a pointer that picks up a previously
|
||||||
/// exposed provenance. See [`from_exposed_addr`] for more details on that operation.
|
/// exposed provenance. See [`with_exposed_provenance`] for more details on that operation.
|
||||||
///
|
///
|
||||||
/// This API and its claimed semantics are part of the Strict Provenance experiment,
|
/// This API and its claimed semantics are part of the Strict Provenance experiment,
|
||||||
/// see the [module documentation][crate::ptr] for details.
|
/// see the [module documentation][crate::ptr] for details.
|
||||||
@ -592,7 +592,7 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
|
|||||||
pub const fn without_provenance<T>(addr: usize) -> *const T {
|
pub const fn without_provenance<T>(addr: usize) -> *const T {
|
||||||
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
|
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
|
||||||
// We use transmute rather than a cast so tools like Miri can tell that this
|
// We use transmute rather than a cast so tools like Miri can tell that this
|
||||||
// is *not* the same as from_exposed_addr.
|
// is *not* the same as with_exposed_provenance.
|
||||||
// SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
|
// SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
|
||||||
// pointer).
|
// pointer).
|
||||||
unsafe { mem::transmute(addr) }
|
unsafe { mem::transmute(addr) }
|
||||||
@ -625,7 +625,7 @@ pub const fn dangling<T>() -> *const T {
|
|||||||
/// little more than a usize address in disguise.
|
/// little more than a usize address in disguise.
|
||||||
///
|
///
|
||||||
/// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
|
/// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
|
||||||
/// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation.
|
/// exposed provenance. See [`with_exposed_provenance_mut`] for more details on that operation.
|
||||||
///
|
///
|
||||||
/// This API and its claimed semantics are part of the Strict Provenance experiment,
|
/// This API and its claimed semantics are part of the Strict Provenance experiment,
|
||||||
/// see the [module documentation][crate::ptr] for details.
|
/// see the [module documentation][crate::ptr] for details.
|
||||||
@ -636,7 +636,7 @@ pub const fn dangling<T>() -> *const T {
|
|||||||
pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
|
pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
|
||||||
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
|
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
|
||||||
// We use transmute rather than a cast so tools like Miri can tell that this
|
// We use transmute rather than a cast so tools like Miri can tell that this
|
||||||
// is *not* the same as from_exposed_addr.
|
// is *not* the same as with_exposed_provenance.
|
||||||
// SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
|
// SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that
|
||||||
// pointer).
|
// pointer).
|
||||||
unsafe { mem::transmute(addr) }
|
unsafe { mem::transmute(addr) }
|
||||||
@ -699,7 +699,7 @@ pub const fn dangling_mut<T>() -> *mut T {
|
|||||||
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||||
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
|
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
|
||||||
pub fn from_exposed_addr<T>(addr: usize) -> *const T
|
pub fn with_exposed_provenance<T>(addr: usize) -> *const T
|
||||||
where
|
where
|
||||||
T: Sized,
|
T: Sized,
|
||||||
{
|
{
|
||||||
@ -739,7 +739,7 @@ pub fn from_exposed_addr<T>(addr: usize) -> *const T
|
|||||||
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||||
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
|
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
|
||||||
pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T
|
pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T
|
||||||
where
|
where
|
||||||
T: Sized,
|
T: Sized,
|
||||||
{
|
{
|
||||||
|
@ -171,7 +171,7 @@ pub fn to_bits(self) -> usize
|
|||||||
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
|
#[unstable(feature = "ptr_to_from_bits", issue = "91126")]
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "1.67.0",
|
since = "1.67.0",
|
||||||
note = "replaced by the `ptr::from_exposed_addr_mut` function, or \
|
note = "replaced by the `ptr::with_exposed_provenance_mut` function, or \
|
||||||
update your code to follow the strict provenance rules using its APIs"
|
update your code to follow the strict provenance rules using its APIs"
|
||||||
)]
|
)]
|
||||||
#[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
|
#[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
|
||||||
@ -194,7 +194,7 @@ pub fn from_bits(bits: usize) -> Self
|
|||||||
///
|
///
|
||||||
/// If using those APIs is not possible because there is no way to preserve a pointer with the
|
/// If using those APIs is not possible because there is no way to preserve a pointer with the
|
||||||
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
||||||
/// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
|
/// or [`expose_addr`][pointer::expose_addr] and [`with_exposed_provenance`][with_exposed_provenance]
|
||||||
/// instead. However, note that this makes your code less portable and less amenable to tools
|
/// instead. However, note that this makes your code less portable and less amenable to tools
|
||||||
/// that check for compliance with the Rust memory model.
|
/// that check for compliance with the Rust memory model.
|
||||||
///
|
///
|
||||||
@ -218,30 +218,30 @@ pub fn addr(self) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
|
/// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
|
||||||
/// use in [`from_exposed_addr`][].
|
/// use in [`with_exposed_provenance`][].
|
||||||
///
|
///
|
||||||
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
|
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
|
||||||
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
|
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
|
||||||
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
|
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
|
||||||
/// later call [`from_exposed_addr_mut`][] to reconstitute the original pointer including its
|
/// later call [`with_exposed_provenance_mut`][] to reconstitute the original pointer including its
|
||||||
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
|
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
|
||||||
///
|
///
|
||||||
/// Using this method means that code is *not* following [Strict
|
/// Using this method means that code is *not* following [Strict
|
||||||
/// Provenance][super#strict-provenance] rules. Supporting
|
/// Provenance][super#strict-provenance] rules. Supporting
|
||||||
/// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported
|
/// [`with_exposed_provenance_mut`][] complicates specification and reasoning and may not be supported
|
||||||
/// by tools that help you to stay conformant with the Rust memory model, so it is recommended
|
/// by tools that help you to stay conformant with the Rust memory model, so it is recommended
|
||||||
/// to use [`addr`][pointer::addr] wherever possible.
|
/// to use [`addr`][pointer::addr] wherever possible.
|
||||||
///
|
///
|
||||||
/// On most platforms this will produce a value with the same bytes as the original pointer,
|
/// On most platforms this will produce a value with the same bytes as the original pointer,
|
||||||
/// because all the bytes are dedicated to describing the address. Platforms which need to store
|
/// because all the bytes are dedicated to describing the address. Platforms which need to store
|
||||||
/// additional information in the pointer may not support this operation, since the 'expose'
|
/// additional information in the pointer may not support this operation, since the 'expose'
|
||||||
/// side-effect which is required for [`from_exposed_addr_mut`][] to work is typically not
|
/// side-effect which is required for [`with_exposed_provenance_mut`][] to work is typically not
|
||||||
/// available.
|
/// available.
|
||||||
///
|
///
|
||||||
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
|
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
|
||||||
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
|
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
|
||||||
///
|
///
|
||||||
/// [`from_exposed_addr_mut`]: from_exposed_addr_mut
|
/// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
#[unstable(feature = "exposed_provenance", issue = "95228")]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use crate::mem::transmute;
|
use crate::mem::transmute;
|
||||||
|
|
||||||
|
use crate::any::Any;
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
@ -220,6 +221,12 @@ pub const fn new(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ExtData<'a> {
|
||||||
|
Some(&'a mut dyn Any),
|
||||||
|
None(()),
|
||||||
|
}
|
||||||
|
|
||||||
/// The context of an asynchronous task.
|
/// The context of an asynchronous task.
|
||||||
///
|
///
|
||||||
/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
|
/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
|
||||||
@ -229,6 +236,7 @@ pub const fn new(
|
|||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
waker: &'a Waker,
|
waker: &'a Waker,
|
||||||
local_waker: &'a LocalWaker,
|
local_waker: &'a LocalWaker,
|
||||||
|
ext: ExtData<'a>,
|
||||||
// Ensure we future-proof against variance changes by forcing
|
// Ensure we future-proof against variance changes by forcing
|
||||||
// the lifetime to be invariant (argument-position lifetimes
|
// the lifetime to be invariant (argument-position lifetimes
|
||||||
// are contravariant while return-position lifetimes are
|
// are contravariant while return-position lifetimes are
|
||||||
@ -257,6 +265,7 @@ pub const fn from_waker(waker: &'a Waker) -> Self {
|
|||||||
pub const fn waker(&self) -> &'a Waker {
|
pub const fn waker(&self) -> &'a Waker {
|
||||||
&self.waker
|
&self.waker
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the [`LocalWaker`] for the current task.
|
/// Returns a reference to the [`LocalWaker`] for the current task.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "local_waker", issue = "118959")]
|
#[unstable(feature = "local_waker", issue = "118959")]
|
||||||
@ -264,6 +273,17 @@ pub const fn waker(&self) -> &'a Waker {
|
|||||||
pub const fn local_waker(&self) -> &'a LocalWaker {
|
pub const fn local_waker(&self) -> &'a LocalWaker {
|
||||||
&self.local_waker
|
&self.local_waker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the extension data for the current task.
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
|
pub const fn ext(&mut self) -> &mut dyn Any {
|
||||||
|
match &mut self.ext {
|
||||||
|
ExtData::Some(data) => *data,
|
||||||
|
ExtData::None(unit) => unit,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||||
@ -300,6 +320,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
pub struct ContextBuilder<'a> {
|
pub struct ContextBuilder<'a> {
|
||||||
waker: &'a Waker,
|
waker: &'a Waker,
|
||||||
local_waker: &'a LocalWaker,
|
local_waker: &'a LocalWaker,
|
||||||
|
ext: ExtData<'a>,
|
||||||
// Ensure we future-proof against variance changes by forcing
|
// Ensure we future-proof against variance changes by forcing
|
||||||
// the lifetime to be invariant (argument-position lifetimes
|
// the lifetime to be invariant (argument-position lifetimes
|
||||||
// are contravariant while return-position lifetimes are
|
// are contravariant while return-position lifetimes are
|
||||||
@ -318,7 +339,39 @@ impl<'a> ContextBuilder<'a> {
|
|||||||
pub const fn from_waker(waker: &'a Waker) -> Self {
|
pub const fn from_waker(waker: &'a Waker) -> Self {
|
||||||
// SAFETY: LocalWaker is just Waker without thread safety
|
// SAFETY: LocalWaker is just Waker without thread safety
|
||||||
let local_waker = unsafe { transmute(waker) };
|
let local_waker = unsafe { transmute(waker) };
|
||||||
Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
|
Self {
|
||||||
|
waker: waker,
|
||||||
|
local_waker,
|
||||||
|
ext: ExtData::None(()),
|
||||||
|
_marker: PhantomData,
|
||||||
|
_marker2: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a ContextBuilder from an existing Context.
|
||||||
|
#[inline]
|
||||||
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
|
pub const fn from(cx: &'a mut Context<'_>) -> Self {
|
||||||
|
let ext = match &mut cx.ext {
|
||||||
|
ExtData::Some(ext) => ExtData::Some(*ext),
|
||||||
|
ExtData::None(()) => ExtData::None(()),
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
waker: cx.waker,
|
||||||
|
local_waker: cx.local_waker,
|
||||||
|
ext,
|
||||||
|
_marker: PhantomData,
|
||||||
|
_marker2: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method is used to set the value for the waker on `Context`.
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
|
pub const fn waker(self, waker: &'a Waker) -> Self {
|
||||||
|
Self { waker, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is used to set the value for the local waker on `Context`.
|
/// This method is used to set the value for the local waker on `Context`.
|
||||||
@ -329,13 +382,21 @@ pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
|
|||||||
Self { local_waker, ..self }
|
Self { local_waker, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method is used to set the value for the extension data on `Context`.
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
|
pub const fn ext(self, data: &'a mut dyn Any) -> Self {
|
||||||
|
Self { ext: ExtData::Some(data), ..self }
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds the `Context`.
|
/// Builds the `Context`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "local_waker", issue = "118959")]
|
#[unstable(feature = "local_waker", issue = "118959")]
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
pub const fn build(self) -> Context<'a> {
|
pub const fn build(self) -> Context<'a> {
|
||||||
let ContextBuilder { waker, local_waker, _marker, _marker2 } = self;
|
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
|
||||||
Context { waker, local_waker, _marker, _marker2 }
|
Context { waker, local_waker, ext, _marker, _marker2 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,13 +51,13 @@ pub trait SimdConstPtr: Copy + Sealed {
|
|||||||
fn with_addr(self, addr: Self::Usize) -> Self;
|
fn with_addr(self, addr: Self::Usize) -> Self;
|
||||||
|
|
||||||
/// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
|
/// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
|
||||||
/// in [`Self::from_exposed_addr`].
|
/// in [`Self::with_exposed_provenance`].
|
||||||
fn expose_addr(self) -> Self::Usize;
|
fn expose_addr(self) -> Self::Usize;
|
||||||
|
|
||||||
/// Convert an address back to a pointer, picking up a previously "exposed" provenance.
|
/// Convert an address back to a pointer, picking up a previously "exposed" provenance.
|
||||||
///
|
///
|
||||||
/// Equivalent to calling [`core::ptr::from_exposed_addr`] on each element.
|
/// Equivalent to calling [`core::ptr::with_exposed_provenance`] on each element.
|
||||||
fn from_exposed_addr(addr: Self::Usize) -> Self;
|
fn with_exposed_provenance(addr: Self::Usize) -> Self;
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
///
|
///
|
||||||
@ -137,9 +137,9 @@ fn expose_addr(self) -> Self::Usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_exposed_addr(addr: Self::Usize) -> Self {
|
fn with_exposed_provenance(addr: Self::Usize) -> Self {
|
||||||
// Safety: `self` is a pointer vector
|
// Safety: `self` is a pointer vector
|
||||||
unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
|
unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -48,13 +48,13 @@ pub trait SimdMutPtr: Copy + Sealed {
|
|||||||
fn with_addr(self, addr: Self::Usize) -> Self;
|
fn with_addr(self, addr: Self::Usize) -> Self;
|
||||||
|
|
||||||
/// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
|
/// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use
|
||||||
/// in [`Self::from_exposed_addr`].
|
/// in [`Self::with_exposed_provenance`].
|
||||||
fn expose_addr(self) -> Self::Usize;
|
fn expose_addr(self) -> Self::Usize;
|
||||||
|
|
||||||
/// Convert an address back to a pointer, picking up a previously "exposed" provenance.
|
/// Convert an address back to a pointer, picking up a previously "exposed" provenance.
|
||||||
///
|
///
|
||||||
/// Equivalent to calling [`core::ptr::from_exposed_addr_mut`] on each element.
|
/// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element.
|
||||||
fn from_exposed_addr(addr: Self::Usize) -> Self;
|
fn with_exposed_provenance(addr: Self::Usize) -> Self;
|
||||||
|
|
||||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||||
///
|
///
|
||||||
@ -134,9 +134,9 @@ fn expose_addr(self) -> Self::Usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_exposed_addr(addr: Self::Usize) -> Self {
|
fn with_exposed_provenance(addr: Self::Usize) -> Self {
|
||||||
// Safety: `self` is a pointer vector
|
// Safety: `self` is a pointer vector
|
||||||
unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
|
unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -80,10 +80,10 @@ fn cast_mut<const LANES: usize>() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_exposed_addr<const LANES: usize>() {
|
fn with_exposed_provenance<const LANES: usize>() {
|
||||||
test_helpers::test_unary_elementwise(
|
test_helpers::test_unary_elementwise(
|
||||||
&Simd::<*const u32, LANES>::from_exposed_addr,
|
&Simd::<*const u32, LANES>::with_exposed_provenance,
|
||||||
&core::ptr::from_exposed_addr::<u32>,
|
&core::ptr::with_exposed_provenance::<u32>,
|
||||||
&|_| true,
|
&|_| true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -103,10 +103,10 @@ fn cast_const<const LANES: usize>() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_exposed_addr<const LANES: usize>() {
|
fn with_exposed_provenance<const LANES: usize>() {
|
||||||
test_helpers::test_unary_elementwise(
|
test_helpers::test_unary_elementwise(
|
||||||
&Simd::<*mut u32, LANES>::from_exposed_addr,
|
&Simd::<*mut u32, LANES>::with_exposed_provenance,
|
||||||
&core::ptr::from_exposed_addr_mut::<u32>,
|
&core::ptr::with_exposed_provenance_mut::<u32>,
|
||||||
&|_| true,
|
&|_| true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ pub(crate) unsafe fn map_memory<T>(
|
|||||||
let result = a0;
|
let result = a0;
|
||||||
|
|
||||||
if result == SyscallResult::MemoryRange as usize {
|
if result == SyscallResult::MemoryRange as usize {
|
||||||
let start = core::ptr::from_exposed_addr_mut::<T>(a1);
|
let start = core::ptr::with_exposed_provenance_mut::<T>(a1);
|
||||||
let len = a2 / core::mem::size_of::<T>();
|
let len = a2 / core::mem::size_of::<T>();
|
||||||
let end = unsafe { start.add(len) };
|
let end = unsafe { start.add(len) };
|
||||||
Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
|
Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
|
||||||
|
@ -47,7 +47,7 @@ pub unsafe fn new_with_coreid(
|
|||||||
extern "C" fn thread_start(main: usize) {
|
extern "C" fn thread_start(main: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Finally, let's run some code.
|
// Finally, let's run some code.
|
||||||
Box::from_raw(ptr::from_exposed_addr::<Box<dyn FnOnce()>>(main).cast_mut())();
|
Box::from_raw(ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(main).cast_mut())();
|
||||||
|
|
||||||
// run all destructors
|
// run all destructors
|
||||||
run_dtors();
|
run_dtors();
|
||||||
|
@ -98,7 +98,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
unsafe extern "C" fn trampoline(exinf: isize) {
|
unsafe extern "C" fn trampoline(exinf: isize) {
|
||||||
let p_inner: *mut ThreadInner = crate::ptr::from_exposed_addr_mut(exinf as usize);
|
let p_inner: *mut ThreadInner = crate::ptr::with_exposed_provenance_mut(exinf as usize);
|
||||||
// Safety: `ThreadInner` is alive at this point
|
// Safety: `ThreadInner` is alive at this point
|
||||||
let inner = unsafe { &*p_inner };
|
let inner = unsafe { &*p_inner };
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ fn tls_ptr_addr() -> *mut *mut u8 {
|
|||||||
out(reg) tp,
|
out(reg) tp,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
core::ptr::from_exposed_addr_mut::<*mut u8>(tp)
|
core::ptr::with_exposed_provenance_mut::<*mut u8>(tp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an area of memory that's unique per thread. This area will
|
/// Create an area of memory that's unique per thread. This area will
|
||||||
|
@ -9,13 +9,13 @@ pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn set(key: Key, value: *mut u8) {
|
pub unsafe fn set(key: Key, value: *mut u8) {
|
||||||
let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
|
let key: *mut *mut u8 = core::ptr::with_exposed_provenance_mut(key);
|
||||||
*key = value;
|
*key = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get(key: Key) -> *mut u8 {
|
pub unsafe fn get(key: Key) -> *mut u8 {
|
||||||
let key: *mut *mut u8 = core::ptr::from_exposed_addr_mut(key);
|
let key: *mut *mut u8 = core::ptr::with_exposed_provenance_mut(key);
|
||||||
*key
|
*key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
|
|||||||
// Can never have null landing pad for sjlj -- that would have
|
// Can never have null landing pad for sjlj -- that would have
|
||||||
// been indicated by a -1 call site index.
|
// been indicated by a -1 call site index.
|
||||||
// FIXME(strict provenance)
|
// FIXME(strict provenance)
|
||||||
let lpad = ptr::from_exposed_addr((cs_lpad + 1) as usize);
|
let lpad = ptr::with_exposed_provenance((cs_lpad + 1) as usize);
|
||||||
return Ok(interpret_cs_action(action_table, cs_action_entry, lpad));
|
return Ok(interpret_cs_action(action_table, cs_action_entry, lpad));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -825,6 +825,7 @@ fn cp_rustc_component_to_ci_sysroot(
|
|||||||
#[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Rustc {
|
pub struct Rustc {
|
||||||
pub target: TargetSelection,
|
pub target: TargetSelection,
|
||||||
|
/// The **previous** compiler used to compile this compiler.
|
||||||
pub compiler: Compiler,
|
pub compiler: Compiler,
|
||||||
/// Whether to build a subset of crates, rather than the whole compiler.
|
/// Whether to build a subset of crates, rather than the whole compiler.
|
||||||
///
|
///
|
||||||
@ -1512,12 +1513,9 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
|||||||
run.never()
|
run.never()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the sysroot for the `compiler` specified that *this build system
|
/// Returns the sysroot that `compiler` is supposed to use.
|
||||||
/// generates*.
|
/// For the stage0 compiler, this is stage0-sysroot (because of the initial std build).
|
||||||
///
|
/// For all other stages, it's the same stage directory that the compiler lives in.
|
||||||
/// That is, the sysroot for the stage0 compiler is not what the compiler
|
|
||||||
/// thinks it is by default, but it's the same as the default for stages
|
|
||||||
/// 1-3.
|
|
||||||
fn run(self, builder: &Builder<'_>) -> PathBuf {
|
fn run(self, builder: &Builder<'_>) -> PathBuf {
|
||||||
let compiler = self.compiler;
|
let compiler = self.compiler;
|
||||||
let host_dir = builder.out.join(compiler.host.triple);
|
let host_dir = builder.out.join(compiler.host.triple);
|
||||||
|
@ -274,6 +274,7 @@ fn run(self, builder: &Builder<'_>) -> LlvmResult {
|
|||||||
target.to_string()
|
target.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again.
|
||||||
let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) {
|
let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) {
|
||||||
Ok(p) => return p,
|
Ok(p) => return p,
|
||||||
Err(m) => m,
|
Err(m) => m,
|
||||||
|
@ -112,7 +112,7 @@ fn check_rvalue<'tcx>(
|
|||||||
Rvalue::Repeat(operand, _)
|
Rvalue::Repeat(operand, _)
|
||||||
| Rvalue::Use(operand)
|
| Rvalue::Use(operand)
|
||||||
| Rvalue::Cast(
|
| Rvalue::Cast(
|
||||||
CastKind::PointerFromExposedAddress
|
CastKind::PointerWithExposedProvenance
|
||||||
| CastKind::IntToInt
|
| CastKind::IntToInt
|
||||||
| CastKind::FloatToInt
|
| CastKind::FloatToInt
|
||||||
| CastKind::IntToFloat
|
| CastKind::IntToFloat
|
||||||
|
@ -324,7 +324,7 @@ environment variable. We first document the most relevant and most commonly used
|
|||||||
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
|
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
|
||||||
any way.
|
any way.
|
||||||
* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and
|
* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and
|
||||||
[`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html).
|
[`ptr::with_exposed_provenance`](https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html).
|
||||||
This will necessarily miss some bugs as those operations are not efficiently and accurately
|
This will necessarily miss some bugs as those operations are not efficiently and accurately
|
||||||
implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is
|
implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is
|
||||||
subject to these operations.
|
subject to these operations.
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ProvenanceMode {
|
pub enum ProvenanceMode {
|
||||||
/// We support `expose_addr`/`from_exposed_addr` via "wildcard" provenance.
|
/// We support `expose_addr`/`with_exposed_provenance` via "wildcard" provenance.
|
||||||
/// However, we want on `from_exposed_addr` to alert the user of the precision loss.
|
/// However, we want on `with_exposed_provenance` to alert the user of the precision loss.
|
||||||
Default,
|
Default,
|
||||||
/// Like `Default`, but without the warning.
|
/// Like `Default`, but without the warning.
|
||||||
Permissive,
|
Permissive,
|
||||||
/// We error on `from_exposed_addr`, ensuring no precision loss.
|
/// We error on `with_exposed_provenance`, ensuring no precision loss.
|
||||||
Strict,
|
Strict,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
Int2PtrWithStrictProvenance =>
|
Int2PtrWithStrictProvenance =>
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`"
|
"integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`"
|
||||||
),
|
),
|
||||||
StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
|
StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
|
||||||
TreeBorrowsUb { title, .. } => write!(f, "{title}"),
|
TreeBorrowsUb { title, .. } => write!(f, "{title}"),
|
||||||
@ -593,7 +593,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
format!(
|
format!(
|
||||||
"This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,"
|
"This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -603,7 +603,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
format!(
|
format!(
|
||||||
"See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation."
|
"See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation."
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -615,7 +615,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
format!(
|
format!(
|
||||||
"You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics."
|
"You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics."
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
@ -514,7 +514,7 @@ enum Op {
|
|||||||
dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
|
dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
|
||||||
this.write_int(res, &dest)?;
|
this.write_int(res, &dest)?;
|
||||||
}
|
}
|
||||||
"cast" | "as" | "cast_ptr" | "expose_addr" | "from_exposed_addr" => {
|
"cast" | "as" | "cast_ptr" | "expose_addr" | "with_exposed_provenance" => {
|
||||||
let [op] = check_arg_count(args)?;
|
let [op] = check_arg_count(args)?;
|
||||||
let (op, op_len) = this.operand_to_simd(op)?;
|
let (op, op_len) = this.operand_to_simd(op)?;
|
||||||
let (dest, dest_len) = this.mplace_to_simd(dest)?;
|
let (dest, dest_len) = this.mplace_to_simd(dest)?;
|
||||||
@ -525,7 +525,7 @@ enum Op {
|
|||||||
let safe_cast = intrinsic_name == "as";
|
let safe_cast = intrinsic_name == "as";
|
||||||
let ptr_cast = intrinsic_name == "cast_ptr";
|
let ptr_cast = intrinsic_name == "cast_ptr";
|
||||||
let expose_cast = intrinsic_name == "expose_addr";
|
let expose_cast = intrinsic_name == "expose_addr";
|
||||||
let from_exposed_cast = intrinsic_name == "from_exposed_addr";
|
let from_exposed_cast = intrinsic_name == "with_exposed_provenance";
|
||||||
|
|
||||||
for i in 0..dest_len {
|
for i in 0..dest_len {
|
||||||
let op = this.read_immediate(&this.project_index(&op, i)?)?;
|
let op = this.read_immediate(&this.project_index(&op, i)?)?;
|
||||||
@ -559,7 +559,7 @@ enum Op {
|
|||||||
(ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast =>
|
(ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast =>
|
||||||
this.pointer_expose_address_cast(&op, dest.layout)?,
|
this.pointer_expose_address_cast(&op, dest.layout)?,
|
||||||
(ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
|
(ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
|
||||||
this.pointer_from_exposed_address_cast(&op, dest.layout)?,
|
this.pointer_with_exposed_provenance_cast(&op, dest.layout)?,
|
||||||
// Error otherwise
|
// Error otherwise
|
||||||
_ =>
|
_ =>
|
||||||
throw_unsup_format!(
|
throw_unsup_format!(
|
||||||
|
@ -7,6 +7,6 @@ fn main() {
|
|||||||
|
|
||||||
let x_usize: usize = x_ptr.addr();
|
let x_usize: usize = x_ptr.addr();
|
||||||
// Cast back an address that did *not* get exposed.
|
// Cast back an address that did *not* get exposed.
|
||||||
let ptr = std::ptr::from_exposed_addr::<i32>(x_usize);
|
let ptr = std::ptr::with_exposed_provenance::<i32>(x_usize);
|
||||||
assert_eq!(unsafe { *ptr }, 3); //~ ERROR: is a dangling pointer
|
assert_eq!(unsafe { *ptr }, 3); //~ ERROR: is a dangling pointer
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let addr = &0 as *const i32 as usize;
|
let addr = &0 as *const i32 as usize;
|
||||||
let _ptr = std::ptr::from_exposed_addr::<i32>(addr); //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported
|
let _ptr = std::ptr::with_exposed_provenance::<i32>(addr); //~ ERROR: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`
|
error: unsupported operation: integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`
|
||||||
--> $DIR/strict_provenance_cast.rs:LL:CC
|
--> $DIR/strict_provenance_cast.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | let _ptr = std::ptr::from_exposed_addr::<i32>(addr);
|
LL | let _ptr = std::ptr::with_exposed_provenance::<i32>(addr);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`
|
||||||
|
|
|
|
||||||
= help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
|
= help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
|
||||||
= note: BACKTRACE:
|
= note: BACKTRACE:
|
||||||
|
@ -7,6 +7,6 @@ fn main() {
|
|||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic
|
let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic
|
||||||
let addr = (&x as *const i32).expose_addr();
|
let addr = (&x as *const i32).expose_addr();
|
||||||
let ptr = std::ptr::from_exposed_addr_mut::<i32>(addr);
|
let ptr = std::ptr::with_exposed_provenance_mut::<i32>(addr);
|
||||||
unsafe { *ptr = 0 }; //~ ERROR: /write access using <wildcard> .* no exposed tags have suitable permission in the borrow stack/
|
unsafe { *ptr = 0 }; //~ ERROR: /write access using <wildcard> .* no exposed tags have suitable permission in the borrow stack/
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ warning: integer-to-pointer cast
|
|||||||
LL | let r2 = ((r as usize) + 0) as *mut i32;
|
LL | let r2 = ((r as usize) + 0) as *mut i32;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
||||||
|
|
|
|
||||||
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
|
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
|
||||||
= help: which means that Miri might miss pointer bugs in this program.
|
= help: which means that Miri might miss pointer bugs in this program.
|
||||||
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
|
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
|
||||||
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
||||||
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
|
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
|
||||||
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
||||||
= note: BACKTRACE:
|
= note: BACKTRACE:
|
||||||
= note: inside `into_raw` at $DIR/box.rs:LL:CC
|
= note: inside `into_raw` at $DIR/box.rs:LL:CC
|
||||||
|
@ -4,11 +4,11 @@ warning: integer-to-pointer cast
|
|||||||
LL | let x: &Foo = unsafe { &*(16 as *const Foo) };
|
LL | let x: &Foo = unsafe { &*(16 as *const Foo) };
|
||||||
| ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
| ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
||||||
|
|
|
|
||||||
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
|
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
|
||||||
= help: which means that Miri might miss pointer bugs in this program.
|
= help: which means that Miri might miss pointer bugs in this program.
|
||||||
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
|
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
|
||||||
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
||||||
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
|
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
|
||||||
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
||||||
= note: BACKTRACE:
|
= note: BACKTRACE:
|
||||||
= note: inside `main` at $DIR/extern_types.rs:LL:CC
|
= note: inside `main` at $DIR/extern_types.rs:LL:CC
|
||||||
|
@ -8,5 +8,5 @@ fn main() {
|
|||||||
// Pointer casts
|
// Pointer casts
|
||||||
let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast();
|
let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast();
|
||||||
let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_addr();
|
let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_addr();
|
||||||
let _ptrs = Simd::<*const i32, 4>::from_exposed_addr(addrs);
|
let _ptrs = Simd::<*const i32, 4>::with_exposed_provenance(addrs);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ fn ptr_roundtrip_out_of_bounds() {
|
|||||||
|
|
||||||
let x_usize = x_ptr.wrapping_offset(128).expose_addr();
|
let x_usize = x_ptr.wrapping_offset(128).expose_addr();
|
||||||
|
|
||||||
let ptr = ptr::from_exposed_addr::<i32>(x_usize).wrapping_offset(-128);
|
let ptr = ptr::with_exposed_provenance::<i32>(x_usize).wrapping_offset(-128);
|
||||||
assert_eq!(unsafe { *ptr }, 3);
|
assert_eq!(unsafe { *ptr }, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ fn ptr_roundtrip_confusion() {
|
|||||||
let x_usize = x_ptr.expose_addr();
|
let x_usize = x_ptr.expose_addr();
|
||||||
let y_usize = y_ptr.expose_addr();
|
let y_usize = y_ptr.expose_addr();
|
||||||
|
|
||||||
let ptr = ptr::from_exposed_addr::<i32>(y_usize);
|
let ptr = ptr::with_exposed_provenance::<i32>(y_usize);
|
||||||
let ptr = ptr.with_addr(x_usize);
|
let ptr = ptr.with_addr(x_usize);
|
||||||
assert_eq!(unsafe { *ptr }, 0);
|
assert_eq!(unsafe { *ptr }, 0);
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ fn ptr_roundtrip_imperfect() {
|
|||||||
|
|
||||||
let x_usize = x_ptr.expose_addr() + 128;
|
let x_usize = x_ptr.expose_addr() + 128;
|
||||||
|
|
||||||
let ptr = ptr::from_exposed_addr::<u8>(x_usize).wrapping_offset(-128);
|
let ptr = ptr::with_exposed_provenance::<u8>(x_usize).wrapping_offset(-128);
|
||||||
assert_eq!(unsafe { *ptr }, 3);
|
assert_eq!(unsafe { *ptr }, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ fn ptr_roundtrip_null() {
|
|||||||
let null = x_null_ptr.expose_addr();
|
let null = x_null_ptr.expose_addr();
|
||||||
assert_eq!(null, 0);
|
assert_eq!(null, 0);
|
||||||
|
|
||||||
let x_null_ptr_copy = ptr::from_exposed_addr::<i32>(null); // just a roundtrip, so has provenance of x (angelically)
|
let x_null_ptr_copy = ptr::with_exposed_provenance::<i32>(null); // just a roundtrip, so has provenance of x (angelically)
|
||||||
let x_ptr_copy = x_null_ptr_copy.with_addr(x_ptr.addr()); // addr of x and provenance of x
|
let x_ptr_copy = x_null_ptr_copy.with_addr(x_ptr.addr()); // addr of x and provenance of x
|
||||||
assert_eq!(unsafe { *x_ptr_copy }, 42);
|
assert_eq!(unsafe { *x_ptr_copy }, 42);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ fn not_so_innocent(x: &mut u32) -> usize {
|
|||||||
// 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers).
|
// 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers).
|
||||||
// And indeed if `variant == true` it is the only possible choice.
|
// And indeed if `variant == true` it is the only possible choice.
|
||||||
// But if `variant == false` then 2 is the only possible choice!
|
// But if `variant == false` then 2 is the only possible choice!
|
||||||
let x_wildcard = ptr::from_exposed_addr_mut::<i32>(x_raw2_addr);
|
let x_wildcard = ptr::with_exposed_provenance_mut::<i32>(x_raw2_addr);
|
||||||
|
|
||||||
if variant {
|
if variant {
|
||||||
// If we picked 2, this will invalidate 3.
|
// If we picked 2, this will invalidate 3.
|
||||||
|
@ -4,11 +4,11 @@ warning: integer-to-pointer cast
|
|||||||
LL | let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>;
|
LL | let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
||||||
|
|
|
|
||||||
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,
|
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
|
||||||
= help: which means that Miri might miss pointer bugs in this program.
|
= help: which means that Miri might miss pointer bugs in this program.
|
||||||
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.
|
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
|
||||||
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
|
||||||
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.
|
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
|
||||||
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
|
||||||
= note: BACKTRACE:
|
= note: BACKTRACE:
|
||||||
= note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC
|
= note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC
|
||||||
|
@ -9,7 +9,7 @@ fn main() {
|
|||||||
|
|
||||||
// Expose the allocation and use the exposed pointer, creating an unknown bottom
|
// Expose the allocation and use the exposed pointer, creating an unknown bottom
|
||||||
unsafe {
|
unsafe {
|
||||||
let p: *mut u8 = ptr::from_exposed_addr::<u8>(ptr.expose_addr()) as *mut u8;
|
let p: *mut u8 = ptr::with_exposed_provenance::<u8>(ptr.expose_addr()) as *mut u8;
|
||||||
*p = 1;
|
*p = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ fn int_to_ptr(_1: usize) -> *const i32 {
|
|||||||
let mut _0: *const i32;
|
let mut _0: *const i32;
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
_0 = _1 as *const i32 (PointerFromExposedAddress);
|
_0 = _1 as *const i32 (PointerWithExposedProvenance);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
_3 = main as fn() (PointerCoercion(ReifyFnPointer));
|
_3 = main as fn() (PointerCoercion(ReifyFnPointer));
|
||||||
_2 = move _3 as usize (PointerExposeAddress);
|
_2 = move _3 as usize (PointerExposeAddress);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_1 = move _2 as *const fn() (PointerFromExposedAddress);
|
_1 = move _2 as *const fn() (PointerWithExposedProvenance);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
|
@ -5,6 +5,6 @@ fn main() {
|
|||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer));
|
// CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer));
|
||||||
// CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeAddress);
|
// CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeAddress);
|
||||||
// CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerFromExposedAddress);
|
// CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance);
|
||||||
let _ = main as usize as *const fn();
|
let _ = main as usize as *const fn();
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ fn main() {
|
|||||||
|
|
||||||
is_unwindsafe(async {
|
is_unwindsafe(async {
|
||||||
//~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
//~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
|
//~| ERROR the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
||||||
use std::ptr::null;
|
use std::ptr::null;
|
||||||
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
let waker = unsafe {
|
let waker = unsafe {
|
||||||
|
@ -6,19 +6,18 @@ LL | is_unwindsafe(async {
|
|||||||
| |_____|
|
| |_____|
|
||||||
| ||
|
| ||
|
||||||
LL | ||
|
LL | ||
|
||||||
|
LL | ||
|
||||||
LL | || use std::ptr::null;
|
LL | || use std::ptr::null;
|
||||||
LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
|
||||||
... ||
|
... ||
|
||||||
LL | || drop(cx_ref);
|
LL | || drop(cx_ref);
|
||||||
LL | || });
|
LL | || });
|
||||||
| ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
| ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
| |_____|
|
| |_____|
|
||||||
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`
|
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
|
||||||
|
|
|
|
||||||
= help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe`
|
= help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
|
||||||
= note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
|
|
||||||
note: future does not implement `UnwindSafe` as this value is used across an await
|
note: future does not implement `UnwindSafe` as this value is used across an await
|
||||||
--> $DIR/async-is-unwindsafe.rs:25:18
|
--> $DIR/async-is-unwindsafe.rs:26:18
|
||||||
|
|
|
|
||||||
LL | let cx_ref = &mut cx;
|
LL | let cx_ref = &mut cx;
|
||||||
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
||||||
@ -31,6 +30,38 @@ note: required by a bound in `is_unwindsafe`
|
|||||||
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
||||||
|
--> $DIR/async-is-unwindsafe.rs:12:5
|
||||||
|
|
|
||||||
|
LL | is_unwindsafe(async {
|
||||||
|
| _____^_____________-
|
||||||
|
| |_____|
|
||||||
|
| ||
|
||||||
|
LL | ||
|
||||||
|
LL | ||
|
||||||
|
LL | || use std::ptr::null;
|
||||||
|
... ||
|
||||||
|
LL | || drop(cx_ref);
|
||||||
|
LL | || });
|
||||||
|
| ||_____-^ `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
||||||
|
| |_____|
|
||||||
|
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
|
||||||
|
|
|
||||||
|
= help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut (dyn Any + 'static)`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
|
||||||
|
note: future does not implement `UnwindSafe` as this value is used across an await
|
||||||
|
--> $DIR/async-is-unwindsafe.rs:26:18
|
||||||
|
|
|
||||||
|
LL | let mut cx = Context::from_waker(&waker);
|
||||||
|
| ------ has type `Context<'_>` which does not implement `UnwindSafe`
|
||||||
|
...
|
||||||
|
LL | async {}.await; // this needs an inner await point
|
||||||
|
| ^^^^^ await occurs here, with `mut cx` maybe used later
|
||||||
|
note: required by a bound in `is_unwindsafe`
|
||||||
|
--> $DIR/async-is-unwindsafe.rs:3:26
|
||||||
|
|
|
||||||
|
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
16
tests/ui/derives/auxiliary/rustc-serialize.rs
Normal file
16
tests/ui/derives/auxiliary/rustc-serialize.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
pub trait Decoder {
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
|
||||||
|
where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
|
||||||
|
fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
|
||||||
|
-> Result<T, Self::Error>
|
||||||
|
where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Decodable: Sized {
|
||||||
|
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
|
||||||
|
}
|
11
tests/ui/derives/rustc-decodable-issue-123156.rs
Normal file
11
tests/ui/derives/rustc-decodable-issue-123156.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//@ check-pass
|
||||||
|
//@ edition:2021
|
||||||
|
//@ aux-build:rustc-serialize.rs
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![allow(deprecated, soft_unstable)]
|
||||||
|
|
||||||
|
extern crate rustc_serialize;
|
||||||
|
|
||||||
|
#[derive(RustcDecodable)]
|
||||||
|
pub enum Foo {}
|
10
tests/ui/derives/rustc-decodable-issue-123156.stderr
Normal file
10
tests/ui/derives/rustc-decodable-issue-123156.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Future incompatibility report: Future breakage diagnostic:
|
||||||
|
warning: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code
|
||||||
|
--> $DIR/rustc-decodable-issue-123156.rs:10:10
|
||||||
|
|
|
||||||
|
LL | #[derive(RustcDecodable)]
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>
|
||||||
|
|
@ -4,7 +4,7 @@ error: strict provenance disallows casting integer `usize` to pointer `*const u8
|
|||||||
LL | let dangling = 16_usize as *const u8;
|
LL | let dangling = 16_usize as *const u8;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
|
= help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9
|
--> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9
|
||||||
|
|
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
extern "rust-intrinsic" {
|
extern "rust-intrinsic" {
|
||||||
fn simd_cast_ptr<T, U>(x: T) -> U;
|
fn simd_cast_ptr<T, U>(x: T) -> U;
|
||||||
fn simd_expose_addr<T, U>(x: T) -> U;
|
fn simd_expose_addr<T, U>(x: T) -> U;
|
||||||
fn simd_from_exposed_addr<T, U>(x: T) -> U;
|
fn simd_with_exposed_provenance<T, U>(x: T) -> U;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@ -24,10 +24,10 @@ fn main() {
|
|||||||
|
|
||||||
let exposed_addr: V<usize> = simd_expose_addr(const_ptrs);
|
let exposed_addr: V<usize> = simd_expose_addr(const_ptrs);
|
||||||
|
|
||||||
let from_exposed_addr: V<*mut i8> = simd_from_exposed_addr(exposed_addr);
|
let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr);
|
||||||
|
|
||||||
assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]);
|
assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]);
|
||||||
assert!(exposed_addr.0 == [ptr as usize, 0]);
|
assert!(exposed_addr.0 == [ptr as usize, 0]);
|
||||||
assert!(from_exposed_addr.0 == ptrs.0);
|
assert!(with_exposed_provenance.0 == ptrs.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,6 @@ fn main() {
|
|||||||
let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
//~^ ERROR expected a pattern, found an expression
|
//~^ ERROR expected a pattern, found an expression
|
||||||
//~| ERROR cannot find type `T` in this scope
|
//~| ERROR cannot find type `T` in this scope
|
||||||
//~| ERROR type and const arguments are not allowed on builtin type `str`
|
//~| ERROR const and type arguments are not allowed on builtin type `str`
|
||||||
//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
|
//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ error[E0412]: cannot find type `T` in this scope
|
|||||||
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
| ^ not found in this scope
|
| ^ not found in this scope
|
||||||
|
|
||||||
error[E0109]: type and const arguments are not allowed on builtin type `str`
|
error[E0109]: const and type arguments are not allowed on builtin type `str`
|
||||||
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
|
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
|
||||||
|
|
|
|
||||||
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
| --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ type and const arguments not allowed
|
| --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ const and type arguments not allowed
|
||||||
| |
|
| |
|
||||||
| not allowed on builtin type `str`
|
| not allowed on builtin type `str`
|
||||||
|
|
|
|
||||||
|
Loading…
Reference in New Issue
Block a user