Auto merge of #139766 - jhpratt:rollup-afrfmnk, r=jhpratt
Rollup of 10 pull requests Successful merges: - #137043 (Initial `UnsafePinned` implementation [Part 1: Libs]) - #138962 (Expect an array when expected and acutal types are both arrays during cast) - #139001 (add `naked_functions_rustic_abi` feature gate) - #139379 (Use delayed bug for normalization errors in drop elaboration) - #139582 (Various coercion cleanups) - #139628 (Suggest remove redundant `$()?` around `vis`) - #139644 (Micro-optimize `InstSimplify`'s `simplify_primitive_clone`) - #139674 (In `rustc_mir_transform`, iterate over index newtypes instead of ints) - #139740 (Convert `tests/ui/lint/dead-code/self-assign.rs` to a known-bug test) - #139741 (fix smir's run! doc and import) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
15f58c46da
73 changed files with 825 additions and 391 deletions
|
@ -315,7 +315,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
repr: &ReprOptions,
|
repr: &ReprOptions,
|
||||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||||
is_enum: bool,
|
is_enum: bool,
|
||||||
is_unsafe_cell: bool,
|
is_special_no_niche: bool,
|
||||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||||
|
@ -348,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
repr,
|
repr,
|
||||||
variants,
|
variants,
|
||||||
is_enum,
|
is_enum,
|
||||||
is_unsafe_cell,
|
is_special_no_niche,
|
||||||
scalar_valid_range,
|
scalar_valid_range,
|
||||||
always_sized,
|
always_sized,
|
||||||
present_first,
|
present_first,
|
||||||
|
@ -505,7 +505,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
repr: &ReprOptions,
|
repr: &ReprOptions,
|
||||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||||
is_enum: bool,
|
is_enum: bool,
|
||||||
is_unsafe_cell: bool,
|
is_special_no_niche: bool,
|
||||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||||
always_sized: bool,
|
always_sized: bool,
|
||||||
present_first: VariantIdx,
|
present_first: VariantIdx,
|
||||||
|
@ -524,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
let mut st = self.univariant(&variants[v], repr, kind)?;
|
let mut st = self.univariant(&variants[v], repr, kind)?;
|
||||||
st.variants = Variants::Single { index: v };
|
st.variants = Variants::Single { index: v };
|
||||||
|
|
||||||
if is_unsafe_cell {
|
if is_special_no_niche {
|
||||||
let hide_niches = |scalar: &mut _| match scalar {
|
let hide_niches = |scalar: &mut _| match scalar {
|
||||||
Scalar::Initialized { value, valid_range } => {
|
Scalar::Initialized { value, valid_range } => {
|
||||||
*valid_range = WrappingRange::full(value.size(dl))
|
*valid_range = WrappingRange::full(value.size(dl))
|
||||||
|
|
|
@ -12,7 +12,7 @@ use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_attr_parsing::{AttributeKind, find_attr};
|
use rustc_attr_parsing::{AttributeKind, find_attr};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||||
use rustc_errors::{Applicability, ErrorGuaranteed};
|
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint_defs::BuiltinLintDiag;
|
use rustc_lint_defs::BuiltinLintDiag;
|
||||||
|
@ -27,19 +27,18 @@ use rustc_span::hygiene::Transparency;
|
||||||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
|
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
|
||||||
use tracing::{debug, instrument, trace, trace_span};
|
use tracing::{debug, instrument, trace, trace_span};
|
||||||
|
|
||||||
use super::diagnostics;
|
|
||||||
use super::macro_parser::{NamedMatches, NamedParseResult};
|
use super::macro_parser::{NamedMatches, NamedParseResult};
|
||||||
|
use super::{SequenceRepetition, diagnostics};
|
||||||
use crate::base::{
|
use crate::base::{
|
||||||
DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
|
DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
|
||||||
SyntaxExtensionKind, TTMacroExpander,
|
SyntaxExtensionKind, TTMacroExpander,
|
||||||
};
|
};
|
||||||
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
|
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
|
||||||
use crate::mbe;
|
|
||||||
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
|
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
|
||||||
use crate::mbe::macro_check;
|
|
||||||
use crate::mbe::macro_parser::NamedMatch::*;
|
use crate::mbe::macro_parser::NamedMatch::*;
|
||||||
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
|
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
|
||||||
use crate::mbe::transcribe::transcribe;
|
use crate::mbe::transcribe::transcribe;
|
||||||
|
use crate::mbe::{self, KleeneOp, macro_check};
|
||||||
|
|
||||||
pub(crate) struct ParserAnyMacro<'a> {
|
pub(crate) struct ParserAnyMacro<'a> {
|
||||||
parser: Parser<'a>,
|
parser: Parser<'a>,
|
||||||
|
@ -640,6 +639,37 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if a `vis` nonterminal fragment is unnecessarily wrapped in an optional repetition.
|
||||||
|
///
|
||||||
|
/// When a `vis` fragment (which can already be empty) is wrapped in `$(...)?`,
|
||||||
|
/// this suggests removing the redundant repetition syntax since it provides no additional benefit.
|
||||||
|
fn check_redundant_vis_repetition(
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
sess: &Session,
|
||||||
|
seq: &SequenceRepetition,
|
||||||
|
span: &DelimSpan,
|
||||||
|
) {
|
||||||
|
let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
|
||||||
|
let is_vis = seq.tts.first().map_or(false, |tt| {
|
||||||
|
matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
|
||||||
|
});
|
||||||
|
|
||||||
|
if is_vis && is_zero_or_one {
|
||||||
|
err.note("a `vis` fragment can already be empty");
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"remove the `$(` and `)?`",
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
sess.source_map().span_extend_to_prev_char_before(span.open, '$', true),
|
||||||
|
"".to_string(),
|
||||||
|
),
|
||||||
|
(span.close.with_hi(seq.kleene.span.hi()), "".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that the lhs contains no repetition which could match an empty token
|
/// Checks that the lhs contains no repetition which could match an empty token
|
||||||
/// tree, because then the matcher would hang indefinitely.
|
/// tree, because then the matcher would hang indefinitely.
|
||||||
fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> {
|
fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> {
|
||||||
|
@ -654,8 +684,10 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
|
||||||
TokenTree::Sequence(span, seq) => {
|
TokenTree::Sequence(span, seq) => {
|
||||||
if is_empty_token_tree(sess, seq) {
|
if is_empty_token_tree(sess, seq) {
|
||||||
let sp = span.entire();
|
let sp = span.entire();
|
||||||
let guar = sess.dcx().span_err(sp, "repetition matches empty token tree");
|
let mut err =
|
||||||
return Err(guar);
|
sess.dcx().struct_span_err(sp, "repetition matches empty token tree");
|
||||||
|
check_redundant_vis_repetition(&mut err, sess, seq, span);
|
||||||
|
return Err(err.emit());
|
||||||
}
|
}
|
||||||
check_lhs_no_empty_seq(sess, &seq.tts)?
|
check_lhs_no_empty_seq(sess, &seq.tts)?
|
||||||
}
|
}
|
||||||
|
|
|
@ -565,6 +565,8 @@ declare_features! (
|
||||||
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
||||||
/// Allows using `#[naked]` on functions.
|
/// Allows using `#[naked]` on functions.
|
||||||
(unstable, naked_functions, "1.9.0", Some(90957)),
|
(unstable, naked_functions, "1.9.0", Some(90957)),
|
||||||
|
/// Allows using `#[naked]` on `extern "Rust"` functions.
|
||||||
|
(unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)),
|
||||||
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
|
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
|
||||||
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
|
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
|
||||||
/// Allows specifying the as-needed link modifier
|
/// Allows specifying the as-needed link modifier
|
||||||
|
|
|
@ -182,6 +182,7 @@ language_item_table! {
|
||||||
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
|
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
|
||||||
|
|
||||||
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
|
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
|
UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
|
|
||||||
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
|
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||||
|
@ -235,6 +236,8 @@ language_item_table! {
|
||||||
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
|
|
||||||
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
|
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
|
||||||
|
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
|
||||||
|
|
||||||
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
|
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
|
||||||
|
|
||||||
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
|
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
|
|
|
@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
m_cast: ty::TypeAndMut<'tcx>,
|
m_cast: ty::TypeAndMut<'tcx>,
|
||||||
) -> Result<CastKind, CastError<'tcx>> {
|
) -> Result<CastKind, CastError<'tcx>> {
|
||||||
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
|
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
|
||||||
if m_expr.mutbl >= m_cast.mutbl {
|
if m_expr.mutbl >= m_cast.mutbl
|
||||||
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
&& let ty::Array(ety, _) = m_expr.ty.kind()
|
||||||
// Due to the limitations of LLVM global constants,
|
&& fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
|
||||||
// region pointers end up pointing at copies of
|
{
|
||||||
// vector elements instead of the original values.
|
// Due to the limitations of LLVM global constants,
|
||||||
// To allow raw pointers to work correctly, we
|
// region pointers end up pointing at copies of
|
||||||
// need to special-case obtaining a raw pointer
|
// vector elements instead of the original values.
|
||||||
// from a region pointer to a vector.
|
// To allow raw pointers to work correctly, we
|
||||||
|
// need to special-case obtaining a raw pointer
|
||||||
|
// from a region pointer to a vector.
|
||||||
|
|
||||||
// Coerce to a raw pointer so that we generate RawPtr in MIR.
|
// Coerce to a raw pointer so that we generate RawPtr in MIR.
|
||||||
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
|
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
|
||||||
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
|
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
bug!(
|
bug!(
|
||||||
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
||||||
self.expr_ty,
|
self.expr_ty,
|
||||||
array_ptr_type,
|
array_ptr_type,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
// this will report a type mismatch if needed
|
// this will report a type mismatch if needed
|
||||||
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
|
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
|
||||||
return Ok(CastKind::ArrayPtrCast);
|
return Ok(CastKind::ArrayPtrCast);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(CastError::IllegalCast)
|
Err(CastError::IllegalCast)
|
||||||
|
|
|
@ -103,15 +103,6 @@ fn coerce_mutbls<'tcx>(
|
||||||
if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
|
if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do not require any adjustments, i.e. coerce `x -> x`.
|
|
||||||
fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
|
|
||||||
move |target| vec![Adjustment { kind, target }]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This always returns `Ok(...)`.
|
/// This always returns `Ok(...)`.
|
||||||
fn success<'tcx>(
|
fn success<'tcx>(
|
||||||
adj: Vec<Adjustment<'tcx>>,
|
adj: Vec<Adjustment<'tcx>>,
|
||||||
|
@ -131,7 +122,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
|
Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
|
fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
|
||||||
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
|
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
|
||||||
self.commit_if_ok(|_| {
|
self.commit_if_ok(|_| {
|
||||||
let at = self.at(&self.cause, self.fcx.param_env);
|
let at = self.at(&self.cause, self.fcx.param_env);
|
||||||
|
@ -161,13 +152,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unify two types (using sub or lub).
|
||||||
|
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||||
|
self.unify_raw(a, b)
|
||||||
|
.and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations))
|
||||||
|
}
|
||||||
|
|
||||||
/// Unify two types (using sub or lub) and produce a specific coercion.
|
/// Unify two types (using sub or lub) and produce a specific coercion.
|
||||||
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
|
fn unify_and(
|
||||||
where
|
&self,
|
||||||
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
a: Ty<'tcx>,
|
||||||
{
|
b: Ty<'tcx>,
|
||||||
self.unify(a, b)
|
adjustments: impl IntoIterator<Item = Adjustment<'tcx>>,
|
||||||
.and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
|
final_adjustment: Adjust,
|
||||||
|
) -> CoerceResult<'tcx> {
|
||||||
|
self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| {
|
||||||
|
success(
|
||||||
|
adjustments
|
||||||
|
.into_iter()
|
||||||
|
.chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment }))
|
||||||
|
.collect(),
|
||||||
|
ty,
|
||||||
|
obligations,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
|
@ -180,10 +188,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
// Coercing from `!` to any type is allowed:
|
// Coercing from `!` to any type is allowed:
|
||||||
if a.is_never() {
|
if a.is_never() {
|
||||||
if self.coerce_never {
|
if self.coerce_never {
|
||||||
return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
|
return success(
|
||||||
|
vec![Adjustment { kind: Adjust::NeverToAny, target: b }],
|
||||||
|
b,
|
||||||
|
PredicateObligations::new(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise the only coercion we can do is unification.
|
// Otherwise the only coercion we can do is unification.
|
||||||
return self.unify_and(a, b, identity);
|
return self.unify(a, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +203,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
// we have no information about the source type. This will always
|
// we have no information about the source type. This will always
|
||||||
// ultimately fall back to some form of subtyping.
|
// ultimately fall back to some form of subtyping.
|
||||||
if a.is_ty_var() {
|
if a.is_ty_var() {
|
||||||
return self.coerce_from_inference_variable(a, b, identity);
|
return self.coerce_from_inference_variable(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consider coercing the subtype to a DST
|
// Consider coercing the subtype to a DST
|
||||||
|
@ -247,7 +259,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
ty::FnPtr(a_sig_tys, a_hdr) => {
|
ty::FnPtr(a_sig_tys, a_hdr) => {
|
||||||
// We permit coercion of fn pointers to drop the
|
// We permit coercion of fn pointers to drop the
|
||||||
// unsafe qualifier.
|
// unsafe qualifier.
|
||||||
self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b)
|
self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b)
|
||||||
}
|
}
|
||||||
ty::Closure(closure_def_id_a, args_a) => {
|
ty::Closure(closure_def_id_a, args_a) => {
|
||||||
// Non-capturing closures are coercible to
|
// Non-capturing closures are coercible to
|
||||||
|
@ -257,7 +269,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Otherwise, just use unification rules.
|
// Otherwise, just use unification rules.
|
||||||
self.unify_and(a, b, identity)
|
self.unify(a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,12 +277,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
/// Coercing *from* an inference variable. In this case, we have no information
|
/// Coercing *from* an inference variable. In this case, we have no information
|
||||||
/// about the source type, so we can't really do a true coercion and we always
|
/// about the source type, so we can't really do a true coercion and we always
|
||||||
/// fall back to subtyping (`unify_and`).
|
/// fall back to subtyping (`unify_and`).
|
||||||
fn coerce_from_inference_variable(
|
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||||
&self,
|
|
||||||
a: Ty<'tcx>,
|
|
||||||
b: Ty<'tcx>,
|
|
||||||
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
|
||||||
) -> CoerceResult<'tcx> {
|
|
||||||
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
|
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
|
||||||
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
|
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
|
||||||
assert!(self.shallow_resolve(b) == b);
|
assert!(self.shallow_resolve(b) == b);
|
||||||
|
@ -298,12 +305,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
|
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
|
||||||
target_ty, obligations
|
target_ty, obligations
|
||||||
);
|
);
|
||||||
let adjustments = make_adjustments(target_ty);
|
success(vec![], target_ty, obligations)
|
||||||
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
|
|
||||||
} else {
|
} else {
|
||||||
// One unresolved type variable: just apply subtyping, we may be able
|
// One unresolved type variable: just apply subtyping, we may be able
|
||||||
// to do something useful.
|
// to do something useful.
|
||||||
self.unify_and(a, b, make_adjustments)
|
self.unify(a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +337,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
||||||
(r_a, mt_a)
|
(r_a, mt_a)
|
||||||
}
|
}
|
||||||
_ => return self.unify_and(a, b, identity),
|
_ => return self.unify(a, b),
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = self.cause.span;
|
let span = self.cause.span;
|
||||||
|
@ -437,7 +443,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
referent_ty,
|
referent_ty,
|
||||||
mutbl_b, // [1] above
|
mutbl_b, // [1] above
|
||||||
);
|
);
|
||||||
match self.unify(derefd_ty_a, b) {
|
match self.unify_raw(derefd_ty_a, b) {
|
||||||
Ok(ok) => {
|
Ok(ok) => {
|
||||||
found = Some(ok);
|
found = Some(ok);
|
||||||
break;
|
break;
|
||||||
|
@ -579,13 +585,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
// We only have the latter, so we use an inference variable
|
// We only have the latter, so we use an inference variable
|
||||||
// for the former and let type inference do the rest.
|
// for the former and let type inference do the rest.
|
||||||
let coerce_target = self.next_ty_var(self.cause.span);
|
let coerce_target = self.next_ty_var(self.cause.span);
|
||||||
let mut coercion = self.unify_and(coerce_target, target, |target| {
|
|
||||||
let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
|
let mut coercion = self.unify_and(
|
||||||
match reborrow {
|
coerce_target,
|
||||||
None => vec![unsize],
|
target,
|
||||||
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
|
reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]),
|
||||||
}
|
Adjust::Pointer(PointerCoercion::Unsize),
|
||||||
})?;
|
)?;
|
||||||
|
|
||||||
let mut selcx = traits::SelectionContext::new(self);
|
let mut selcx = traits::SelectionContext::new(self);
|
||||||
|
|
||||||
|
@ -708,7 +714,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
|
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
|
||||||
&& a_data.principal_def_id() == b_data.principal_def_id()
|
&& a_data.principal_def_id() == b_data.principal_def_id()
|
||||||
{
|
{
|
||||||
return self.unify_and(a, b, |_| vec![]);
|
return self.unify(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the obligations of the cast -- for example, when casting
|
// Check the obligations of the cast -- for example, when casting
|
||||||
|
@ -808,23 +814,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
|
|
||||||
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
|
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
|
||||||
// add the adjustments.
|
// add the adjustments.
|
||||||
self.unify_and(a, b, |_inner_ty| {
|
self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
|
||||||
vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_from_safe_fn<F, G>(
|
fn coerce_from_safe_fn(
|
||||||
&self,
|
&self,
|
||||||
a: Ty<'tcx>,
|
|
||||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||||
b: Ty<'tcx>,
|
b: Ty<'tcx>,
|
||||||
to_unsafe: F,
|
adjustment: Option<Adjust>,
|
||||||
normal: G,
|
) -> CoerceResult<'tcx> {
|
||||||
) -> CoerceResult<'tcx>
|
|
||||||
where
|
|
||||||
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
|
||||||
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
|
||||||
{
|
|
||||||
self.commit_if_ok(|snapshot| {
|
self.commit_if_ok(|snapshot| {
|
||||||
let outer_universe = self.infcx.universe();
|
let outer_universe = self.infcx.universe();
|
||||||
|
|
||||||
|
@ -833,9 +831,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
&& hdr_b.safety.is_unsafe()
|
&& hdr_b.safety.is_unsafe()
|
||||||
{
|
{
|
||||||
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
|
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
|
||||||
self.unify_and(unsafe_a, b, to_unsafe)
|
self.unify_and(
|
||||||
|
unsafe_a,
|
||||||
|
b,
|
||||||
|
adjustment
|
||||||
|
.map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }),
|
||||||
|
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
self.unify_and(a, b, normal)
|
let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
|
||||||
|
match adjustment {
|
||||||
|
Some(adjust) => self.unify_and(a, b, [], adjust),
|
||||||
|
None => self.unify(a, b),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME(#73154): This is a hack. Currently LUB can generate
|
// FIXME(#73154): This is a hack. Currently LUB can generate
|
||||||
|
@ -852,7 +860,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
|
|
||||||
fn coerce_from_fn_pointer(
|
fn coerce_from_fn_pointer(
|
||||||
&self,
|
&self,
|
||||||
a: Ty<'tcx>,
|
|
||||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||||
b: Ty<'tcx>,
|
b: Ty<'tcx>,
|
||||||
) -> CoerceResult<'tcx> {
|
) -> CoerceResult<'tcx> {
|
||||||
|
@ -861,15 +868,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
//!
|
//!
|
||||||
|
|
||||||
let b = self.shallow_resolve(b);
|
let b = self.shallow_resolve(b);
|
||||||
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
|
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
|
||||||
|
|
||||||
self.coerce_from_safe_fn(
|
self.coerce_from_safe_fn(fn_ty_a, b, None)
|
||||||
a,
|
|
||||||
fn_ty_a,
|
|
||||||
b,
|
|
||||||
simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
|
|
||||||
identity,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||||
|
@ -916,30 +917,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
self.at(&self.cause, self.param_env).normalize(a_sig);
|
self.at(&self.cause, self.param_env).normalize(a_sig);
|
||||||
obligations.extend(o1);
|
obligations.extend(o1);
|
||||||
|
|
||||||
let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
|
|
||||||
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
|
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
|
||||||
a_fn_pointer,
|
|
||||||
a_sig,
|
a_sig,
|
||||||
b,
|
b,
|
||||||
|unsafe_ty| {
|
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
|
||||||
vec![
|
|
||||||
Adjustment {
|
|
||||||
kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer),
|
|
||||||
target: a_fn_pointer,
|
|
||||||
},
|
|
||||||
Adjustment {
|
|
||||||
kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
|
|
||||||
target: unsafe_ty,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
obligations.extend(o2);
|
obligations.extend(o2);
|
||||||
Ok(InferOk { value, obligations })
|
Ok(InferOk { value, obligations })
|
||||||
}
|
}
|
||||||
_ => self.unify_and(a, b, identity),
|
_ => self.unify(a, b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,10 +970,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
self.unify_and(
|
self.unify_and(
|
||||||
pointer_ty,
|
pointer_ty,
|
||||||
b,
|
b,
|
||||||
simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
|
[],
|
||||||
|
Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => self.unify_and(a, b, identity),
|
_ => self.unify(a, b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1001,7 +989,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
let (is_ref, mt_a) = match *a.kind() {
|
let (is_ref, mt_a) = match *a.kind() {
|
||||||
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
|
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
|
||||||
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
|
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
|
||||||
_ => return self.unify_and(a, b, identity),
|
_ => return self.unify(a, b),
|
||||||
};
|
};
|
||||||
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
||||||
|
|
||||||
|
@ -1011,16 +999,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
// representation, we still register an Adjust::DerefRef so that
|
// representation, we still register an Adjust::DerefRef so that
|
||||||
// regionck knows that the region for `a` must be valid here.
|
// regionck knows that the region for `a` must be valid here.
|
||||||
if is_ref {
|
if is_ref {
|
||||||
self.unify_and(a_raw, b, |target| {
|
self.unify_and(
|
||||||
vec![
|
a_raw,
|
||||||
Adjustment { kind: Adjust::Deref(None), target: mt_a.ty },
|
b,
|
||||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target },
|
[Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
|
||||||
]
|
Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
|
||||||
})
|
)
|
||||||
} else if mt_a.mutbl != mutbl_b {
|
} else if mt_a.mutbl != mutbl_b {
|
||||||
self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
|
self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer))
|
||||||
} else {
|
} else {
|
||||||
self.unify_and(a_raw, b, identity)
|
self.unify(a_raw, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1118,9 +1106,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||||
// We don't ever need two-phase here since we throw out the result of the coercion.
|
// We don't ever need two-phase here since we throw out the result of the coercion.
|
||||||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
||||||
coerce
|
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
|
||||||
.autoderef(DUMMY_SP, expr_ty)
|
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
|
||||||
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a type, this function will calculate and return the type given
|
/// Given a type, this function will calculate and return the type given
|
||||||
|
|
|
@ -257,6 +257,13 @@ impl Parse for Newtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::ops::AddAssign<usize> for #name {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, other: usize) {
|
||||||
|
*self = *self + other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl rustc_index::Idx for #name {
|
impl rustc_index::Idx for #name {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(value: usize) -> Self {
|
fn new(value: usize) -> Self {
|
||||||
|
|
|
@ -606,6 +606,11 @@ fn register_builtins(store: &mut LintStore) {
|
||||||
"converted into hard error, see issue #127323 \
|
"converted into hard error, see issue #127323 \
|
||||||
<https://github.com/rust-lang/rust/issues/127323> for more information",
|
<https://github.com/rust-lang/rust/issues/127323> for more information",
|
||||||
);
|
);
|
||||||
|
store.register_removed(
|
||||||
|
"undefined_naked_function_abi",
|
||||||
|
"converted into hard error, see PR #139001 \
|
||||||
|
<https://github.com/rust-lang/rust/issues/139001> for more information",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_internals(store: &mut LintStore) {
|
fn register_internals(store: &mut LintStore) {
|
||||||
|
|
|
@ -864,8 +864,8 @@ fn ty_is_known_nonnull<'tcx>(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// `UnsafeCell` has its niche hidden.
|
// `UnsafeCell` and `UnsafePinned` have their niche hidden.
|
||||||
if def.is_unsafe_cell() {
|
if def.is_unsafe_cell() || def.is_unsafe_pinned() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,6 @@ declare_lint_pass! {
|
||||||
UNCONDITIONAL_PANIC,
|
UNCONDITIONAL_PANIC,
|
||||||
UNCONDITIONAL_RECURSION,
|
UNCONDITIONAL_RECURSION,
|
||||||
UNCOVERED_PARAM_IN_PROJECTION,
|
UNCOVERED_PARAM_IN_PROJECTION,
|
||||||
UNDEFINED_NAKED_FUNCTION_ABI,
|
|
||||||
UNEXPECTED_CFGS,
|
UNEXPECTED_CFGS,
|
||||||
UNFULFILLED_LINT_EXPECTATIONS,
|
UNFULFILLED_LINT_EXPECTATIONS,
|
||||||
UNINHABITED_STATIC,
|
UNINHABITED_STATIC,
|
||||||
|
@ -2830,39 +2829,6 @@ declare_lint! {
|
||||||
"detects deprecation attributes with no effect",
|
"detects deprecation attributes with no effect",
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `undefined_naked_function_abi` lint detects naked function definitions that
|
|
||||||
/// either do not specify an ABI or specify the Rust ABI.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// #![feature(asm_experimental_arch, naked_functions)]
|
|
||||||
///
|
|
||||||
/// use std::arch::naked_asm;
|
|
||||||
///
|
|
||||||
/// #[naked]
|
|
||||||
/// pub fn default_abi() -> u32 {
|
|
||||||
/// unsafe { naked_asm!(""); }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// #[naked]
|
|
||||||
/// pub extern "Rust" fn rust_abi() -> u32 {
|
|
||||||
/// unsafe { naked_asm!(""); }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// {{produces}}
|
|
||||||
///
|
|
||||||
/// ### Explanation
|
|
||||||
///
|
|
||||||
/// The Rust ABI is currently undefined. Therefore, naked functions should
|
|
||||||
/// specify a non-Rust ABI.
|
|
||||||
pub UNDEFINED_NAKED_FUNCTION_ABI,
|
|
||||||
Warn,
|
|
||||||
"undefined naked function ABI"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
|
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
|
||||||
///
|
///
|
||||||
|
|
|
@ -53,6 +53,10 @@ bitflags::bitflags! {
|
||||||
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
|
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
|
||||||
/// Indicates whether the type is `UnsafeCell`.
|
/// Indicates whether the type is `UnsafeCell`.
|
||||||
const IS_UNSAFE_CELL = 1 << 9;
|
const IS_UNSAFE_CELL = 1 << 9;
|
||||||
|
/// Indicates whether the type is `UnsafePinned`.
|
||||||
|
const IS_UNSAFE_PINNED = 1 << 10;
|
||||||
|
/// Indicates whether the type is anonymous.
|
||||||
|
const IS_ANONYMOUS = 1 << 11;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
||||||
|
@ -302,6 +306,9 @@ impl AdtDefData {
|
||||||
if tcx.is_lang_item(did, LangItem::UnsafeCell) {
|
if tcx.is_lang_item(did, LangItem::UnsafeCell) {
|
||||||
flags |= AdtFlags::IS_UNSAFE_CELL;
|
flags |= AdtFlags::IS_UNSAFE_CELL;
|
||||||
}
|
}
|
||||||
|
if tcx.is_lang_item(did, LangItem::UnsafePinned) {
|
||||||
|
flags |= AdtFlags::IS_UNSAFE_PINNED;
|
||||||
|
}
|
||||||
|
|
||||||
AdtDefData { did, variants, flags, repr }
|
AdtDefData { did, variants, flags, repr }
|
||||||
}
|
}
|
||||||
|
@ -405,6 +412,12 @@ impl<'tcx> AdtDef<'tcx> {
|
||||||
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
|
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this is `UnsafePinned<T>`.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_unsafe_pinned(self) -> bool {
|
||||||
|
self.flags().contains(AdtFlags::IS_UNSAFE_PINNED)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if this is `ManuallyDrop<T>`.
|
/// Returns `true` if this is `ManuallyDrop<T>`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_manually_drop(self) -> bool {
|
pub fn is_manually_drop(self) -> bool {
|
||||||
|
|
|
@ -547,7 +547,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
|
|
||||||
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
|
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
|
||||||
|
|
||||||
for bb in START_BLOCK..body.basic_blocks.next_index() {
|
for bb in body.basic_blocks.indices() {
|
||||||
let bb_data = &body[bb];
|
let bb_data = &body[bb];
|
||||||
if bb_data.is_cleanup {
|
if bb_data.is_cleanup {
|
||||||
continue;
|
continue;
|
||||||
|
@ -556,11 +556,11 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
match &bb_data.terminator().kind {
|
match &bb_data.terminator().kind {
|
||||||
TerminatorKind::Call { func, .. } => {
|
TerminatorKind::Call { func, .. } => {
|
||||||
let func_ty = func.ty(body, tcx);
|
let func_ty = func.ty(body, tcx);
|
||||||
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
if let ty::FnDef(def_id, _) = *func_ty.kind()
|
||||||
if def_id == get_context_def_id {
|
&& def_id == get_context_def_id
|
||||||
let local = eliminate_get_context_call(&mut body[bb]);
|
{
|
||||||
replace_resume_ty_local(tcx, body, local, context_mut_ref);
|
let local = eliminate_get_context_call(&mut body[bb]);
|
||||||
}
|
replace_resume_ty_local(tcx, body, local, context_mut_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Yield { resume_arg, .. } => {
|
TerminatorKind::Yield { resume_arg, .. } => {
|
||||||
|
@ -1057,7 +1057,7 @@ fn insert_switch<'tcx>(
|
||||||
let blocks = body.basic_blocks_mut().iter_mut();
|
let blocks = body.basic_blocks_mut().iter_mut();
|
||||||
|
|
||||||
for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) {
|
for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) {
|
||||||
*target = BasicBlock::new(target.index() + 1);
|
*target += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,14 +1209,8 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's a return terminator the function may return.
|
// If there's a return terminator the function may return.
|
||||||
for block in body.basic_blocks.iter() {
|
body.basic_blocks.iter().any(|block| matches!(block.terminator().kind, TerminatorKind::Return))
|
||||||
if let TerminatorKind::Return = block.terminator().kind {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise the function can't return.
|
// Otherwise the function can't return.
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
||||||
|
@ -1293,12 +1287,12 @@ fn create_coroutine_resume_function<'tcx>(
|
||||||
kind: TerminatorKind::Goto { target: poison_block },
|
kind: TerminatorKind::Goto { target: poison_block },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if !block.is_cleanup {
|
} else if !block.is_cleanup
|
||||||
// Any terminators that *can* unwind but don't have an unwind target set are also
|
// Any terminators that *can* unwind but don't have an unwind target set are also
|
||||||
// pointed at our poisoning block (unless they're part of the cleanup path).
|
// pointed at our poisoning block (unless they're part of the cleanup path).
|
||||||
if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() {
|
&& let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut()
|
||||||
*unwind = UnwindAction::Cleanup(poison_block);
|
{
|
||||||
}
|
*unwind = UnwindAction::Cleanup(poison_block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1340,12 +1334,14 @@ fn create_coroutine_resume_function<'tcx>(
|
||||||
make_coroutine_state_argument_indirect(tcx, body);
|
make_coroutine_state_argument_indirect(tcx, body);
|
||||||
|
|
||||||
match transform.coroutine_kind {
|
match transform.coroutine_kind {
|
||||||
|
CoroutineKind::Coroutine(_)
|
||||||
|
| CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) =>
|
||||||
|
{
|
||||||
|
make_coroutine_state_argument_pinned(tcx, body);
|
||||||
|
}
|
||||||
// Iterator::next doesn't accept a pinned argument,
|
// Iterator::next doesn't accept a pinned argument,
|
||||||
// unlike for all other coroutine kinds.
|
// unlike for all other coroutine kinds.
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {}
|
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {}
|
||||||
_ => {
|
|
||||||
make_coroutine_state_argument_pinned(tcx, body);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we remove dead blocks to remove
|
// Make sure we remove dead blocks to remove
|
||||||
|
@ -1408,8 +1404,7 @@ fn create_cases<'tcx>(
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
|
||||||
// Create StorageLive instructions for locals with live storage
|
// Create StorageLive instructions for locals with live storage
|
||||||
for i in 0..(body.local_decls.len()) {
|
for l in body.local_decls.indices() {
|
||||||
let l = Local::new(i);
|
|
||||||
let needs_storage_live = point.storage_liveness.contains(l)
|
let needs_storage_live = point.storage_liveness.contains(l)
|
||||||
&& !transform.remap.contains(l)
|
&& !transform.remap.contains(l)
|
||||||
&& !transform.always_live_locals.contains(l);
|
&& !transform.always_live_locals.contains(l);
|
||||||
|
@ -1535,15 +1530,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
|
||||||
let coroutine_kind = body.coroutine_kind().unwrap();
|
let coroutine_kind = body.coroutine_kind().unwrap();
|
||||||
|
|
||||||
// Get the discriminant type and args which typeck computed
|
// Get the discriminant type and args which typeck computed
|
||||||
let (discr_ty, movable) = match *coroutine_ty.kind() {
|
let ty::Coroutine(_, args) = coroutine_ty.kind() else {
|
||||||
ty::Coroutine(_, args) => {
|
tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}"));
|
||||||
let args = args.as_coroutine();
|
|
||||||
(args.discr_ty(tcx), coroutine_kind.movability() == hir::Movability::Movable)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}"));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
let discr_ty = args.as_coroutine().discr_ty(tcx);
|
||||||
|
|
||||||
let new_ret_ty = match coroutine_kind {
|
let new_ret_ty = match coroutine_kind {
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
|
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
|
||||||
|
@ -1610,6 +1600,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
|
||||||
|
|
||||||
let always_live_locals = always_storage_live_locals(body);
|
let always_live_locals = always_storage_live_locals(body);
|
||||||
|
|
||||||
|
let movable = coroutine_kind.movability() == hir::Movability::Movable;
|
||||||
let liveness_info =
|
let liveness_info =
|
||||||
locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
|
locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
|
||||||
|
|
||||||
|
|
|
@ -103,9 +103,8 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
||||||
let mut should_cleanup = false;
|
let mut should_cleanup = false;
|
||||||
|
|
||||||
// Also consider newly generated bbs in the same pass
|
// Also consider newly generated bbs in the same pass
|
||||||
for i in 0..body.basic_blocks.len() {
|
for parent in body.basic_blocks.indices() {
|
||||||
let bbs = &*body.basic_blocks;
|
let bbs = &*body.basic_blocks;
|
||||||
let parent = BasicBlock::from_usize(i);
|
|
||||||
let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue };
|
let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue };
|
||||||
|
|
||||||
trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}");
|
trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}");
|
||||||
|
|
|
@ -266,19 +266,16 @@ where
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
|
assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
|
||||||
// The type error for normalization may have been in dropck: see
|
|
||||||
// `compute_drop_data` in rustc_borrowck, in which case we wouldn't have
|
|
||||||
// deleted the MIR body and could have an error here as well.
|
|
||||||
let field_ty = match tcx
|
let field_ty = match tcx
|
||||||
.try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args))
|
.try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args))
|
||||||
{
|
{
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(_) => Ty::new_error(
|
Err(_) => Ty::new_error(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
self.elaborator
|
self.tcx().dcx().span_delayed_bug(
|
||||||
.body()
|
self.elaborator.body().span,
|
||||||
.tainted_by_errors
|
"Error normalizing in drop elaboration.",
|
||||||
.expect("Error in drop elaboration not found by dropck."),
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout};
|
||||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||||
|
|
||||||
use crate::simplify::simplify_duplicate_switch_targets;
|
use crate::simplify::simplify_duplicate_switch_targets;
|
||||||
use crate::take_array;
|
|
||||||
|
|
||||||
pub(super) enum InstSimplify {
|
pub(super) enum InstSimplify {
|
||||||
BeforeInline,
|
BeforeInline,
|
||||||
|
@ -214,7 +213,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
||||||
terminator: &mut Terminator<'tcx>,
|
terminator: &mut Terminator<'tcx>,
|
||||||
statements: &mut Vec<Statement<'tcx>>,
|
statements: &mut Vec<Statement<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind
|
let TerminatorKind::Call {
|
||||||
|
func, args, destination, target: Some(destination_block), ..
|
||||||
|
} = &terminator.kind
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -222,15 +223,8 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
||||||
// It's definitely not a clone if there are multiple arguments
|
// It's definitely not a clone if there are multiple arguments
|
||||||
let [arg] = &args[..] else { return };
|
let [arg] = &args[..] else { return };
|
||||||
|
|
||||||
let Some(destination_block) = *target else { return };
|
|
||||||
|
|
||||||
// Only bother looking more if it's easy to know what we're calling
|
// Only bother looking more if it's easy to know what we're calling
|
||||||
let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return };
|
let Some((fn_def_id, ..)) = func.const_fn_def() else { return };
|
||||||
|
|
||||||
// Clone needs one arg, so we can cheaply rule out other stuff
|
|
||||||
if fn_args.len() != 1 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These types are easily available from locals, so check that before
|
// These types are easily available from locals, so check that before
|
||||||
// doing DefId lookups to figure out what we're actually calling.
|
// doing DefId lookups to figure out what we're actually calling.
|
||||||
|
@ -238,15 +232,12 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
||||||
|
|
||||||
let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
|
let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
|
||||||
|
|
||||||
if !inner_ty.is_trivially_pure_clone_copy() {
|
if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn)
|
||||||
|
|| !inner_ty.is_trivially_pure_clone_copy()
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Ok([arg]) = take_array(args) else { return };
|
|
||||||
let Some(arg_place) = arg.node.place() else { return };
|
let Some(arg_place) = arg.node.place() else { return };
|
||||||
|
|
||||||
statements.push(Statement {
|
statements.push(Statement {
|
||||||
|
@ -258,7 +249,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
||||||
)),
|
)),
|
||||||
))),
|
))),
|
||||||
});
|
});
|
||||||
terminator.kind = TerminatorKind::Goto { target: destination_block };
|
terminator.kind = TerminatorKind::Goto { target: *destination_block };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) {
|
fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) {
|
||||||
|
|
|
@ -20,13 +20,11 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let typing_env = body.typing_env(tcx);
|
let typing_env = body.typing_env(tcx);
|
||||||
let mut should_cleanup = false;
|
let mut should_cleanup = false;
|
||||||
for i in 0..body.basic_blocks.len() {
|
for bb_idx in body.basic_blocks.indices() {
|
||||||
let bbs = &*body.basic_blocks;
|
match &body.basic_blocks[bb_idx].terminator().kind {
|
||||||
let bb_idx = BasicBlock::from_usize(i);
|
|
||||||
match bbs[bb_idx].terminator().kind {
|
|
||||||
TerminatorKind::SwitchInt {
|
TerminatorKind::SwitchInt {
|
||||||
discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)),
|
discr: Operand::Copy(_) | Operand::Move(_),
|
||||||
ref targets,
|
targets,
|
||||||
..
|
..
|
||||||
// We require that the possible target blocks don't contain this block.
|
// We require that the possible target blocks don't contain this block.
|
||||||
} if !targets.all_targets().contains(&bb_idx) => {}
|
} if !targets.all_targets().contains(&bb_idx) => {}
|
||||||
|
@ -66,9 +64,10 @@ trait SimplifyMatch<'tcx> {
|
||||||
typing_env: ty::TypingEnv<'tcx>,
|
typing_env: ty::TypingEnv<'tcx>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let bbs = &body.basic_blocks;
|
let bbs = &body.basic_blocks;
|
||||||
let (discr, targets) = match bbs[switch_bb_idx].terminator().kind {
|
let TerminatorKind::SwitchInt { discr, targets, .. } =
|
||||||
TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets),
|
&bbs[switch_bb_idx].terminator().kind
|
||||||
_ => unreachable!(),
|
else {
|
||||||
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
let discr_ty = discr.ty(body.local_decls(), tcx);
|
let discr_ty = discr.ty(body.local_decls(), tcx);
|
||||||
|
|
|
@ -18,19 +18,17 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
|
||||||
// find basic blocks with no statement and a return terminator
|
// find basic blocks with no statement and a return terminator
|
||||||
let mut bbs_simple_returns = DenseBitSet::new_empty(body.basic_blocks.len());
|
let mut bbs_simple_returns = DenseBitSet::new_empty(body.basic_blocks.len());
|
||||||
let bbs = body.basic_blocks_mut();
|
let bbs = body.basic_blocks_mut();
|
||||||
for idx in bbs.indices() {
|
for (idx, bb) in bbs.iter_enumerated() {
|
||||||
if bbs[idx].statements.is_empty()
|
if bb.statements.is_empty() && bb.terminator().kind == TerminatorKind::Return {
|
||||||
&& bbs[idx].terminator().kind == TerminatorKind::Return
|
|
||||||
{
|
|
||||||
bbs_simple_returns.insert(idx);
|
bbs_simple_returns.insert(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for bb in bbs {
|
for bb in bbs {
|
||||||
if let TerminatorKind::Goto { target } = bb.terminator().kind {
|
if let TerminatorKind::Goto { target } = bb.terminator().kind
|
||||||
if bbs_simple_returns.contains(target) {
|
&& bbs_simple_returns.contains(target)
|
||||||
bb.terminator_mut().kind = TerminatorKind::Return;
|
{
|
||||||
}
|
bb.terminator_mut().kind = TerminatorKind::Return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,12 +221,11 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
||||||
|
|
||||||
// Check for cycles
|
// Check for cycles
|
||||||
let mut stack = FxHashSet::default();
|
let mut stack = FxHashSet::default();
|
||||||
for i in 0..parent.len() {
|
for (mut bb, parent) in parent.iter_enumerated_mut() {
|
||||||
let mut bb = BasicBlock::from_usize(i);
|
|
||||||
stack.clear();
|
stack.clear();
|
||||||
stack.insert(bb);
|
stack.insert(bb);
|
||||||
loop {
|
loop {
|
||||||
let Some(parent) = parent[bb].take() else { break };
|
let Some(parent) = parent.take() else { break };
|
||||||
let no_cycle = stack.insert(parent);
|
let no_cycle = stack.insert(parent);
|
||||||
if !no_cycle {
|
if !no_cycle {
|
||||||
self.fail(
|
self.fail(
|
||||||
|
|
|
@ -742,9 +742,6 @@ passes_trait_impl_const_stable =
|
||||||
passes_transparent_incompatible =
|
passes_transparent_incompatible =
|
||||||
transparent {$target} cannot have other repr hints
|
transparent {$target} cannot have other repr hints
|
||||||
|
|
||||||
passes_undefined_naked_function_abi =
|
|
||||||
Rust ABI is unsupported in naked functions
|
|
||||||
|
|
||||||
passes_unknown_external_lang_item =
|
passes_unknown_external_lang_item =
|
||||||
unknown external lang item: `{$lang_item}`
|
unknown external lang item: `{$lang_item}`
|
||||||
|
|
||||||
|
|
|
@ -624,6 +624,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
match target {
|
match target {
|
||||||
Target::Fn
|
Target::Fn
|
||||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
|
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
|
||||||
|
let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
|
||||||
|
let abi = fn_sig.header.abi;
|
||||||
|
if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() {
|
||||||
|
feature_err(
|
||||||
|
&self.tcx.sess,
|
||||||
|
sym::naked_functions_rustic_abi,
|
||||||
|
fn_sig.span,
|
||||||
|
format!(
|
||||||
|
"`#[naked]` is currently unstable on `extern \"{}\"` functions",
|
||||||
|
abi.as_str()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
for other_attr in attrs {
|
for other_attr in attrs {
|
||||||
// this covers "sugared doc comments" of the form `/// ...`
|
// this covers "sugared doc comments" of the form `/// ...`
|
||||||
// it does not cover `#[doc = "..."]`, which is handled below
|
// it does not cover `#[doc = "..."]`, which is handled below
|
||||||
|
|
|
@ -1197,10 +1197,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
|
||||||
pub cf_type: &'a str,
|
pub cf_type: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(passes_undefined_naked_function_abi)]
|
|
||||||
pub(crate) struct UndefinedNakedFunctionAbi;
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(passes_no_patterns)]
|
#[diag(passes_no_patterns)]
|
||||||
pub(crate) struct NoPatterns {
|
pub(crate) struct NoPatterns {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//! Checks validity of naked functions.
|
//! Checks validity of naked functions.
|
||||||
|
|
||||||
use rustc_abi::ExternAbi;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
|
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
|
||||||
|
@ -10,12 +9,11 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
|
|
||||||
use rustc_span::{Span, sym};
|
use rustc_span::{Span, sym};
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
|
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
|
||||||
ParamsNotAllowed, UndefinedNakedFunctionAbi,
|
ParamsNotAllowed,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
|
@ -29,26 +27,21 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) {
|
let body = match tcx.hir_node_by_def_id(def_id) {
|
||||||
hir::Node::Item(hir::Item {
|
hir::Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::Fn { sig, body: body_id, .. },
|
kind: hir::ItemKind::Fn { body: body_id, .. }, ..
|
||||||
..
|
|
||||||
})
|
})
|
||||||
| hir::Node::TraitItem(hir::TraitItem {
|
| hir::Node::TraitItem(hir::TraitItem {
|
||||||
kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
|
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
| hir::Node::ImplItem(hir::ImplItem {
|
| hir::Node::ImplItem(hir::ImplItem {
|
||||||
kind: hir::ImplItemKind::Fn(sig, body_id),
|
kind: hir::ImplItemKind::Fn(_, body_id), ..
|
||||||
..
|
}) => tcx.hir_body(*body_id),
|
||||||
}) => (sig.header, *body_id),
|
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = tcx.hir_body(body_id);
|
|
||||||
|
|
||||||
if tcx.has_attr(def_id, sym::naked) {
|
if tcx.has_attr(def_id, sym::naked) {
|
||||||
check_abi(tcx, def_id, fn_header.abi);
|
|
||||||
check_no_patterns(tcx, body.params);
|
check_no_patterns(tcx, body.params);
|
||||||
check_no_parameters_use(tcx, body);
|
check_no_parameters_use(tcx, body);
|
||||||
check_asm(tcx, def_id, body);
|
check_asm(tcx, def_id, body);
|
||||||
|
@ -60,20 +53,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that function uses non-Rust ABI.
|
|
||||||
fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: ExternAbi) {
|
|
||||||
if abi == ExternAbi::Rust {
|
|
||||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
|
||||||
let span = tcx.def_span(def_id);
|
|
||||||
tcx.emit_node_span_lint(
|
|
||||||
UNDEFINED_NAKED_FUNCTION_ABI,
|
|
||||||
hir_id,
|
|
||||||
span,
|
|
||||||
UndefinedNakedFunctionAbi,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
|
/// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
|
||||||
fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
|
fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
|
||||||
for param in params {
|
for param in params {
|
||||||
|
|
|
@ -244,6 +244,7 @@ where
|
||||||
/// ```ignore(needs-extern-crate)
|
/// ```ignore(needs-extern-crate)
|
||||||
/// # extern crate rustc_driver;
|
/// # extern crate rustc_driver;
|
||||||
/// # extern crate rustc_interface;
|
/// # extern crate rustc_interface;
|
||||||
|
/// # extern crate rustc_middle;
|
||||||
/// # #[macro_use]
|
/// # #[macro_use]
|
||||||
/// # extern crate rustc_smir;
|
/// # extern crate rustc_smir;
|
||||||
/// # extern crate stable_mir;
|
/// # extern crate stable_mir;
|
||||||
|
@ -264,6 +265,7 @@ where
|
||||||
/// ```ignore(needs-extern-crate)
|
/// ```ignore(needs-extern-crate)
|
||||||
/// # extern crate rustc_driver;
|
/// # extern crate rustc_driver;
|
||||||
/// # extern crate rustc_interface;
|
/// # extern crate rustc_interface;
|
||||||
|
/// # extern crate rustc_middle;
|
||||||
/// # #[macro_use]
|
/// # #[macro_use]
|
||||||
/// # extern crate rustc_smir;
|
/// # extern crate rustc_smir;
|
||||||
/// # extern crate stable_mir;
|
/// # extern crate stable_mir;
|
||||||
|
@ -328,6 +330,7 @@ macro_rules! run_driver {
|
||||||
use rustc_driver::{Callbacks, Compilation, run_compiler};
|
use rustc_driver::{Callbacks, Compilation, run_compiler};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_interface::interface;
|
use rustc_interface::interface;
|
||||||
|
use rustc_smir::rustc_internal;
|
||||||
use stable_mir::CompilerError;
|
use stable_mir::CompilerError;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
|
|
@ -633,6 +633,24 @@ impl SourceMap {
|
||||||
sp
|
sp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extends the given `Span` to just before the previous occurrence of `c`. Return the same span
|
||||||
|
/// if an error occurred while retrieving the code snippet.
|
||||||
|
pub fn span_extend_to_prev_char_before(
|
||||||
|
&self,
|
||||||
|
sp: Span,
|
||||||
|
c: char,
|
||||||
|
accept_newlines: bool,
|
||||||
|
) -> Span {
|
||||||
|
if let Ok(prev_source) = self.span_to_prev_source(sp) {
|
||||||
|
let prev_source = prev_source.rsplit(c).next().unwrap_or("");
|
||||||
|
if accept_newlines || !prev_source.contains('\n') {
|
||||||
|
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sp
|
||||||
|
}
|
||||||
|
|
||||||
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
|
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
|
||||||
/// whitespace. Returns None if the pattern could not be found or if an error occurred while
|
/// whitespace. Returns None if the pattern could not be found or if an error occurred while
|
||||||
/// retrieving the code snippet.
|
/// retrieving the code snippet.
|
||||||
|
|
|
@ -1400,6 +1400,7 @@ symbols! {
|
||||||
naked,
|
naked,
|
||||||
naked_asm,
|
naked_asm,
|
||||||
naked_functions,
|
naked_functions,
|
||||||
|
naked_functions_rustic_abi,
|
||||||
naked_functions_target_feature,
|
naked_functions_target_feature,
|
||||||
name,
|
name,
|
||||||
names,
|
names,
|
||||||
|
@ -2215,6 +2216,8 @@ symbols! {
|
||||||
unsafe_fields,
|
unsafe_fields,
|
||||||
unsafe_no_drop_flag,
|
unsafe_no_drop_flag,
|
||||||
unsafe_pin_internals,
|
unsafe_pin_internals,
|
||||||
|
unsafe_pinned,
|
||||||
|
unsafe_unpin,
|
||||||
unsize,
|
unsize,
|
||||||
unsized_const_param_ty,
|
unsized_const_param_ty,
|
||||||
unsized_const_params,
|
unsized_const_params,
|
||||||
|
|
|
@ -514,6 +514,9 @@ fn layout_of_uncached<'tcx>(
|
||||||
return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
|
return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnsafeCell and UnsafePinned both disable niche optimizations
|
||||||
|
let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
|
||||||
|
|
||||||
let get_discriminant_type =
|
let get_discriminant_type =
|
||||||
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
|
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
|
||||||
|
|
||||||
|
@ -542,7 +545,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
&def.repr(),
|
&def.repr(),
|
||||||
&variants,
|
&variants,
|
||||||
def.is_enum(),
|
def.is_enum(),
|
||||||
def.is_unsafe_cell(),
|
is_special_no_niche,
|
||||||
tcx.layout_scalar_valid_range(def.did()),
|
tcx.layout_scalar_valid_range(def.did()),
|
||||||
get_discriminant_type,
|
get_discriminant_type,
|
||||||
discriminants_iter(),
|
discriminants_iter(),
|
||||||
|
@ -568,7 +571,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
&def.repr(),
|
&def.repr(),
|
||||||
&variants,
|
&variants,
|
||||||
def.is_enum(),
|
def.is_enum(),
|
||||||
def.is_unsafe_cell(),
|
is_special_no_niche,
|
||||||
tcx.layout_scalar_valid_range(def.did()),
|
tcx.layout_scalar_valid_range(def.did()),
|
||||||
get_discriminant_type,
|
get_discriminant_type,
|
||||||
discriminants_iter(),
|
discriminants_iter(),
|
||||||
|
|
|
@ -127,6 +127,7 @@
|
||||||
#![feature(ub_checks)]
|
#![feature(ub_checks)]
|
||||||
#![feature(unchecked_neg)]
|
#![feature(unchecked_neg)]
|
||||||
#![feature(unchecked_shifts)]
|
#![feature(unchecked_shifts)]
|
||||||
|
#![feature(unsafe_pinned)]
|
||||||
#![feature(utf16_extra)]
|
#![feature(utf16_extra)]
|
||||||
#![feature(variant_count)]
|
#![feature(variant_count)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::cell::UnsafeCell;
|
||||||
use crate::cmp;
|
use crate::cmp;
|
||||||
use crate::fmt::Debug;
|
use crate::fmt::Debug;
|
||||||
use crate::hash::{Hash, Hasher};
|
use crate::hash::{Hash, Hasher};
|
||||||
|
use crate::pin::UnsafePinned;
|
||||||
|
|
||||||
/// Implements a given marker trait for multiple types at the same time.
|
/// Implements a given marker trait for multiple types at the same time.
|
||||||
///
|
///
|
||||||
|
@ -878,6 +879,23 @@ marker_impls! {
|
||||||
{T: ?Sized} &mut T,
|
{T: ?Sized} &mut T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally,
|
||||||
|
/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata
|
||||||
|
/// for `&mut T` or not.
|
||||||
|
///
|
||||||
|
/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is
|
||||||
|
/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735).
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")]
|
||||||
|
#[cfg_attr(bootstrap, allow(dead_code))]
|
||||||
|
pub(crate) unsafe auto trait UnsafeUnpin {}
|
||||||
|
|
||||||
|
impl<T: ?Sized> !UnsafeUnpin for UnsafePinned<T> {}
|
||||||
|
unsafe impl<T: ?Sized> UnsafeUnpin for PhantomData<T> {}
|
||||||
|
unsafe impl<T: ?Sized> UnsafeUnpin for *const T {}
|
||||||
|
unsafe impl<T: ?Sized> UnsafeUnpin for *mut T {}
|
||||||
|
unsafe impl<T: ?Sized> UnsafeUnpin for &T {}
|
||||||
|
unsafe impl<T: ?Sized> UnsafeUnpin for &mut T {}
|
||||||
|
|
||||||
/// Types that do not require any pinning guarantees.
|
/// Types that do not require any pinning guarantees.
|
||||||
///
|
///
|
||||||
/// For information on what "pinning" is, see the [`pin` module] documentation.
|
/// For information on what "pinning" is, see the [`pin` module] documentation.
|
||||||
|
@ -953,6 +971,11 @@ pub auto trait Unpin {}
|
||||||
/// A marker type which does not implement `Unpin`.
|
/// A marker type which does not implement `Unpin`.
|
||||||
///
|
///
|
||||||
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
|
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
|
||||||
|
//
|
||||||
|
// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet.
|
||||||
|
// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this
|
||||||
|
// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type
|
||||||
|
// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead.
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
#[stable(feature = "pin", since = "1.33.0")]
|
||||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct PhantomPinned;
|
pub struct PhantomPinned;
|
||||||
|
@ -960,6 +983,12 @@ pub struct PhantomPinned;
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
#[stable(feature = "pin", since = "1.33.0")]
|
||||||
impl !Unpin for PhantomPinned {}
|
impl !Unpin for PhantomPinned {}
|
||||||
|
|
||||||
|
// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to
|
||||||
|
// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same
|
||||||
|
// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking
|
||||||
|
// change.
|
||||||
|
impl !UnsafeUnpin for PhantomPinned {}
|
||||||
|
|
||||||
marker_impls! {
|
marker_impls! {
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
#[stable(feature = "pin", since = "1.33.0")]
|
||||||
Unpin for
|
Unpin for
|
||||||
|
|
|
@ -931,6 +931,11 @@ use crate::{
|
||||||
};
|
};
|
||||||
use crate::{cmp, fmt};
|
use crate::{cmp, fmt};
|
||||||
|
|
||||||
|
mod unsafe_pinned;
|
||||||
|
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub use self::unsafe_pinned::UnsafePinned;
|
||||||
|
|
||||||
/// A pointer which pins its pointee in place.
|
/// A pointer which pins its pointee in place.
|
||||||
///
|
///
|
||||||
/// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its
|
/// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its
|
||||||
|
|
197
library/core/src/pin/unsafe_pinned.rs
Normal file
197
library/core/src/pin/unsafe_pinned.rs
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
use crate::marker::{PointerLike, Unpin};
|
||||||
|
use crate::ops::{CoerceUnsized, DispatchFromDyn};
|
||||||
|
use crate::pin::Pin;
|
||||||
|
use crate::{fmt, ptr};
|
||||||
|
|
||||||
|
/// This type provides a way to opt-out of typical aliasing rules;
|
||||||
|
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
|
||||||
|
///
|
||||||
|
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
|
||||||
|
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
|
||||||
|
/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
|
||||||
|
/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
|
||||||
|
/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
|
||||||
|
/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness.
|
||||||
|
///
|
||||||
|
/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in
|
||||||
|
/// the public API of a library. It is an internal implementation detail of libraries that need to
|
||||||
|
/// support aliasing mutable references.
|
||||||
|
///
|
||||||
|
/// Further note that this does *not* lift the requirement that shared references must be read-only!
|
||||||
|
/// Use `UnsafeCell` for that.
|
||||||
|
///
|
||||||
|
/// This type blocks niches the same way `UnsafeCell` does.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")]
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub struct UnsafePinned<T: ?Sized> {
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the
|
||||||
|
/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt
|
||||||
|
/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned.
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: ?Sized> !Unpin for UnsafePinned<T> {}
|
||||||
|
|
||||||
|
/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no
|
||||||
|
/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean
|
||||||
|
/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that
|
||||||
|
/// leaves the user more choices (as they can always wrap this in a `!Copy` type).
|
||||||
|
// FIXME(unsafe_pinned): this may be unsound or a footgun?
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: Copy> Copy for UnsafePinned<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: Copy> Clone for UnsafePinned<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since
|
||||||
|
// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes
|
||||||
|
// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit
|
||||||
|
// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`.
|
||||||
|
|
||||||
|
impl<T> UnsafePinned<T> {
|
||||||
|
/// Constructs a new instance of `UnsafePinned` which will wrap the specified value.
|
||||||
|
///
|
||||||
|
/// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
|
||||||
|
/// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub const fn new(value: T) -> Self {
|
||||||
|
UnsafePinned { value }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unwraps the value, consuming this `UnsafePinned`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||||
|
pub const fn into_inner(self) -> T {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> UnsafePinned<T> {
|
||||||
|
/// Get read-write access to the contents of a pinned `UnsafePinned`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T {
|
||||||
|
// SAFETY: we're not using `get_unchecked_mut` to unpin anything
|
||||||
|
unsafe { self.get_unchecked_mut() }.get_mut_unchecked()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get read-write access to the contents of an `UnsafePinned`.
|
||||||
|
///
|
||||||
|
/// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this
|
||||||
|
/// memory is "pinned" due to there being aliases.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub const fn get_mut_unchecked(&mut self) -> *mut T {
|
||||||
|
ptr::from_mut(self) as *mut T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get read-only access to the contents of a shared `UnsafePinned`.
|
||||||
|
///
|
||||||
|
/// Note that `&UnsafePinned<T>` is read-only if `&T` is read-only. This means that if there is
|
||||||
|
/// mutation of the `T`, future reads from the `*const T` returned here are UB! Use
|
||||||
|
/// [`UnsafeCell`] if you also need interior mutability.
|
||||||
|
///
|
||||||
|
/// [`UnsafeCell`]: crate::cell::UnsafeCell
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// #![feature(unsafe_pinned)]
|
||||||
|
/// use std::pin::UnsafePinned;
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// let mut x = UnsafePinned::new(0);
|
||||||
|
/// let ptr = x.get(); // read-only pointer, assumes immutability
|
||||||
|
/// x.get_mut_unchecked().write(1);
|
||||||
|
/// ptr.read(); // UB!
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub const fn get(&self) -> *const T {
|
||||||
|
ptr::from_ref(self) as *const T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an immutable pointer to the wrapped value.
|
||||||
|
///
|
||||||
|
/// The difference from [`get`] is that this function accepts a raw pointer, which is useful to
|
||||||
|
/// avoid the creation of temporary references.
|
||||||
|
///
|
||||||
|
/// [`get`]: UnsafePinned::get
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub const fn raw_get(this: *const Self) -> *const T {
|
||||||
|
this as *const T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable pointer to the wrapped value.
|
||||||
|
///
|
||||||
|
/// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function
|
||||||
|
/// accepts a raw pointer, which is useful to avoid the creation of temporary references.
|
||||||
|
///
|
||||||
|
/// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned
|
||||||
|
/// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
pub const fn raw_get_mut(this: *mut Self) -> *mut T {
|
||||||
|
this as *mut T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: Default> Default for UnsafePinned<T> {
|
||||||
|
/// Creates an `UnsafePinned`, with the `Default` value for T.
|
||||||
|
fn default() -> Self {
|
||||||
|
UnsafePinned::new(T::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T> From<T> for UnsafePinned<T> {
|
||||||
|
/// Creates a new `UnsafePinned<T>` containing the given value.
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
UnsafePinned::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: ?Sized> fmt::Debug for UnsafePinned<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("UnsafePinned").finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
||||||
|
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T> {}
|
||||||
|
|
||||||
|
// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn`
|
||||||
|
// and become dyn-compatible method receivers.
|
||||||
|
// Note that currently `UnsafePinned` itself cannot be a method receiver
|
||||||
|
// because it does not implement Deref.
|
||||||
|
// In other words:
|
||||||
|
// `self: UnsafePinned<&Self>` won't work
|
||||||
|
// `self: UnsafePinned<Self>` becomes possible
|
||||||
|
// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound?
|
||||||
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
|
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}
|
||||||
|
|
||||||
|
#[unstable(feature = "pointer_like_trait", issue = "none")]
|
||||||
|
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
|
||||||
|
impl<T: PointerLike> PointerLike for UnsafePinned<T> {}
|
||||||
|
|
||||||
|
// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::abi::{
|
use stable_mir::abi::{
|
||||||
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
|
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
|
||||||
VariantsShape,
|
VariantsShape,
|
||||||
|
|
|
@ -19,7 +19,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::crate_def::CrateDef;
|
use stable_mir::crate_def::CrateDef;
|
||||||
use stable_mir::mir::alloc::GlobalAlloc;
|
use stable_mir::mir::alloc::GlobalAlloc;
|
||||||
use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef};
|
use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef};
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use stable_mir::CrateDef;
|
use stable_mir::CrateDef;
|
||||||
|
|
|
@ -15,7 +15,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::{CrateDef, CrateItems};
|
use stable_mir::{CrateDef, CrateItems};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
|
@ -15,7 +15,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::mir::mono::Instance;
|
use stable_mir::mir::mono::Instance;
|
||||||
use stable_mir::mir::visit::{Location, MirVisitor};
|
use stable_mir::mir::visit::{Location, MirVisitor};
|
||||||
use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind};
|
use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind};
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::CrateDef;
|
use stable_mir::CrateDef;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::ty::{Ty, ForeignItemKind};
|
use stable_mir::ty::{Ty, ForeignItemKind};
|
||||||
use stable_mir::*;
|
use stable_mir::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
|
@ -19,7 +19,6 @@ extern crate stable_mir;
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
use mir::{mono::Instance, TerminatorKind::*};
|
use mir::{mono::Instance, TerminatorKind::*};
|
||||||
use stable_mir::mir::mono::InstanceKind;
|
use stable_mir::mir::mono::InstanceKind;
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
|
use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
|
||||||
use stable_mir::*;
|
use stable_mir::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_interface;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::{
|
use stable_mir::{
|
||||||
ty::{Abi, ForeignItemKind},
|
ty::{Abi, ForeignItemKind},
|
||||||
*,
|
*,
|
||||||
|
|
|
@ -21,7 +21,6 @@ use std::ops::ControlFlow;
|
||||||
|
|
||||||
use mir::mono::Instance;
|
use mir::mono::Instance;
|
||||||
use mir::TerminatorKind::*;
|
use mir::TerminatorKind::*;
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::ty::{RigidTy, TyKind};
|
use stable_mir::ty::{RigidTy, TyKind};
|
||||||
use stable_mir::*;
|
use stable_mir::*;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::mir::mono::{Instance, InstanceKind};
|
use stable_mir::mir::mono::{Instance, InstanceKind};
|
||||||
use stable_mir::mir::visit::{Location, MirVisitor};
|
use stable_mir::mir::visit::{Location, MirVisitor};
|
||||||
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
|
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::*;
|
use stable_mir::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate stable_mir;
|
||||||
|
|
||||||
use mir::mono::Instance;
|
use mir::mono::Instance;
|
||||||
use ty::{Ty, TyKind, RigidTy};
|
use ty::{Ty, TyKind, RigidTy};
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::*;
|
use stable_mir::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::CrateDef;
|
use stable_mir::CrateDef;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::mir::alloc::GlobalAlloc;
|
use stable_mir::mir::alloc::GlobalAlloc;
|
||||||
use stable_mir::mir::mono::Instance;
|
use stable_mir::mir::mono::Instance;
|
||||||
use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind};
|
use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind};
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::mir::{
|
use stable_mir::mir::{
|
||||||
Body, FieldIdx, MirVisitor, Place, ProjectionElem,
|
Body, FieldIdx, MirVisitor, Place, ProjectionElem,
|
||||||
visit::{Location, PlaceContext},
|
visit::{Location, PlaceContext},
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
/// This test will generate and analyze a dummy crate using the stable mir.
|
/// This test will generate and analyze a dummy crate using the stable mir.
|
||||||
|
|
|
@ -18,7 +18,6 @@ extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::ItemKind;
|
use stable_mir::ItemKind;
|
||||||
use stable_mir::crate_def::CrateDef;
|
use stable_mir::crate_def::CrateDef;
|
||||||
use stable_mir::mir::mono::Instance;
|
use stable_mir::mir::mono::Instance;
|
||||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::ItemKind;
|
use stable_mir::ItemKind;
|
||||||
use stable_mir::crate_def::CrateDef;
|
use stable_mir::crate_def::CrateDef;
|
||||||
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
|
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
|
||||||
|
|
|
@ -19,7 +19,6 @@ extern crate serde_json;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
use stable_mir::mir::Body;
|
use stable_mir::mir::Body;
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
|
||||||
use stable_mir::mir::MirVisitor;
|
use stable_mir::mir::MirVisitor;
|
||||||
use stable_mir::mir::MutMirVisitor;
|
use stable_mir::mir::MutMirVisitor;
|
||||||
use stable_mir::*;
|
use stable_mir::*;
|
||||||
|
|
27
tests/ui/asm/naked-functions-rustic-abi.rs
Normal file
27
tests/ui/asm/naked-functions-rustic-abi.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//@ revisions: x86_64 aarch64
|
||||||
|
//
|
||||||
|
//@[aarch64] only-aarch64
|
||||||
|
//@[x86_64] only-x86_64
|
||||||
|
//
|
||||||
|
//@ build-pass
|
||||||
|
//@ needs-asm-support
|
||||||
|
|
||||||
|
#![feature(naked_functions, naked_functions_rustic_abi, rust_cold_cc)]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
use std::arch::{asm, naked_asm};
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
pub unsafe fn rust_implicit() {
|
||||||
|
naked_asm!("ret");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "Rust" fn rust_explicit() {
|
||||||
|
naked_asm!("ret");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "rust-cold" fn rust_cold() {
|
||||||
|
naked_asm!("ret");
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
//@ needs-asm-support
|
//@ needs-asm-support
|
||||||
//@ compile-flags: --test
|
//@ compile-flags: --test
|
||||||
|
|
||||||
#![allow(undefined_naked_function_abi)]
|
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
@ -11,7 +10,7 @@ use std::arch::naked_asm;
|
||||||
#[test]
|
#[test]
|
||||||
#[naked]
|
#[naked]
|
||||||
//~^ ERROR [E0736]
|
//~^ ERROR [E0736]
|
||||||
fn test_naked() {
|
extern "C" fn test_naked() {
|
||||||
unsafe { naked_asm!("") };
|
unsafe { naked_asm!("") };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ fn test_naked() {
|
||||||
#[test]
|
#[test]
|
||||||
#[naked]
|
#[naked]
|
||||||
//~^ ERROR [E0736]
|
//~^ ERROR [E0736]
|
||||||
fn test_naked_should_panic() {
|
extern "C" fn test_naked_should_panic() {
|
||||||
unsafe { naked_asm!("") };
|
unsafe { naked_asm!("") };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +26,13 @@ fn test_naked_should_panic() {
|
||||||
#[test]
|
#[test]
|
||||||
#[naked]
|
#[naked]
|
||||||
//~^ ERROR [E0736]
|
//~^ ERROR [E0736]
|
||||||
fn test_naked_ignore() {
|
extern "C" fn test_naked_ignore() {
|
||||||
unsafe { naked_asm!("") };
|
unsafe { naked_asm!("") };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
#[naked]
|
#[naked]
|
||||||
//~^ ERROR [E0736]
|
//~^ ERROR [E0736]
|
||||||
fn bench_naked() {
|
extern "C" fn bench_naked() {
|
||||||
unsafe { naked_asm!("") };
|
unsafe { naked_asm!("") };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0736]: cannot use `#[naked]` with testing attributes
|
error[E0736]: cannot use `#[naked]` with testing attributes
|
||||||
--> $DIR/naked-functions-testattrs.rs:12:1
|
--> $DIR/naked-functions-testattrs.rs:11:1
|
||||||
|
|
|
|
||||||
LL | #[test]
|
LL | #[test]
|
||||||
| ------- function marked with testing attribute here
|
| ------- function marked with testing attribute here
|
||||||
|
@ -7,7 +7,7 @@ LL | #[naked]
|
||||||
| ^^^^^^^^ `#[naked]` is incompatible with testing attributes
|
| ^^^^^^^^ `#[naked]` is incompatible with testing attributes
|
||||||
|
|
||||||
error[E0736]: cannot use `#[naked]` with testing attributes
|
error[E0736]: cannot use `#[naked]` with testing attributes
|
||||||
--> $DIR/naked-functions-testattrs.rs:20:1
|
--> $DIR/naked-functions-testattrs.rs:19:1
|
||||||
|
|
|
|
||||||
LL | #[test]
|
LL | #[test]
|
||||||
| ------- function marked with testing attribute here
|
| ------- function marked with testing attribute here
|
||||||
|
@ -15,7 +15,7 @@ LL | #[naked]
|
||||||
| ^^^^^^^^ `#[naked]` is incompatible with testing attributes
|
| ^^^^^^^^ `#[naked]` is incompatible with testing attributes
|
||||||
|
|
||||||
error[E0736]: cannot use `#[naked]` with testing attributes
|
error[E0736]: cannot use `#[naked]` with testing attributes
|
||||||
--> $DIR/naked-functions-testattrs.rs:28:1
|
--> $DIR/naked-functions-testattrs.rs:27:1
|
||||||
|
|
|
|
||||||
LL | #[test]
|
LL | #[test]
|
||||||
| ------- function marked with testing attribute here
|
| ------- function marked with testing attribute here
|
||||||
|
@ -23,7 +23,7 @@ LL | #[naked]
|
||||||
| ^^^^^^^^ `#[naked]` is incompatible with testing attributes
|
| ^^^^^^^^ `#[naked]` is incompatible with testing attributes
|
||||||
|
|
||||||
error[E0736]: cannot use `#[naked]` with testing attributes
|
error[E0736]: cannot use `#[naked]` with testing attributes
|
||||||
--> $DIR/naked-functions-testattrs.rs:35:1
|
--> $DIR/naked-functions-testattrs.rs:34:1
|
||||||
|
|
|
|
||||||
LL | #[bench]
|
LL | #[bench]
|
||||||
| -------- function marked with testing attribute here
|
| -------- function marked with testing attribute here
|
||||||
|
|
|
@ -122,18 +122,6 @@ unsafe extern "C" fn invalid_may_unwind() {
|
||||||
//~^ ERROR the `may_unwind` option cannot be used with `naked_asm!`
|
//~^ ERROR the `may_unwind` option cannot be used with `naked_asm!`
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
|
||||||
pub unsafe fn default_abi() {
|
|
||||||
//~^ WARN Rust ABI is unsupported in naked functions
|
|
||||||
naked_asm!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[naked]
|
|
||||||
pub unsafe fn rust_abi() {
|
|
||||||
//~^ WARN Rust ABI is unsupported in naked functions
|
|
||||||
naked_asm!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
pub extern "C" fn valid_a<T>() -> T {
|
pub extern "C" fn valid_a<T>() -> T {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -53,19 +53,19 @@ LL | naked_asm!("", options(may_unwind));
|
||||||
| ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
|
| ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
|
||||||
|
|
||||||
error: this is a user specified error
|
error: this is a user specified error
|
||||||
--> $DIR/naked-functions.rs:169:5
|
--> $DIR/naked-functions.rs:157:5
|
||||||
|
|
|
|
||||||
LL | compile_error!("this is a user specified error")
|
LL | compile_error!("this is a user specified error")
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: this is a user specified error
|
error: this is a user specified error
|
||||||
--> $DIR/naked-functions.rs:175:5
|
--> $DIR/naked-functions.rs:163:5
|
||||||
|
|
|
|
||||||
LL | compile_error!("this is a user specified error");
|
LL | compile_error!("this is a user specified error");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: asm template must be a string literal
|
error: asm template must be a string literal
|
||||||
--> $DIR/naked-functions.rs:182:16
|
--> $DIR/naked-functions.rs:170:16
|
||||||
|
|
|
|
||||||
LL | naked_asm!(invalid_syntax)
|
LL | naked_asm!(invalid_syntax)
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
@ -175,20 +175,6 @@ LL |
|
||||||
LL | *&y
|
LL | *&y
|
||||||
| --- not allowed in naked functions
|
| --- not allowed in naked functions
|
||||||
|
|
||||||
warning: Rust ABI is unsupported in naked functions
|
error: aborting due to 25 previous errors
|
||||||
--> $DIR/naked-functions.rs:126:1
|
|
||||||
|
|
|
||||||
LL | pub unsafe fn default_abi() {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: `#[warn(undefined_naked_function_abi)]` on by default
|
|
||||||
|
|
||||||
warning: Rust ABI is unsupported in naked functions
|
|
||||||
--> $DIR/naked-functions.rs:132:1
|
|
||||||
|
|
|
||||||
LL | pub unsafe fn rust_abi() {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 25 previous errors; 2 warnings emitted
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0787`.
|
For more information about this error, try `rustc --explain E0787`.
|
||||||
|
|
5
tests/ui/cast/cast-array-issue-138836.rs
Normal file
5
tests/ui/cast/cast-array-issue-138836.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
fn main() {
|
||||||
|
let a: [u8; 3] = [1,2,3];
|
||||||
|
let b = &a;
|
||||||
|
let c = b as *const [u32; 3]; //~ ERROR casting `&[u8; 3]` as `*const [u32; 3]` is invalid
|
||||||
|
}
|
9
tests/ui/cast/cast-array-issue-138836.stderr
Normal file
9
tests/ui/cast/cast-array-issue-138836.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0606]: casting `&[u8; 3]` as `*const [u32; 3]` is invalid
|
||||||
|
--> $DIR/cast-array-issue-138836.rs:4:13
|
||||||
|
|
|
||||||
|
LL | let c = b as *const [u32; 3];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0606`.
|
|
@ -1,5 +1,5 @@
|
||||||
const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
|
const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
|
||||||
const b: *const i8 = &a as *const i8; //~ ERROR mismatched types
|
const b: *const i8 = &a as *const i8; //~ ERROR casting `&[u8; 3]` as `*const i8` is invalid
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
error[E0308]: mismatched types
|
error[E0606]: casting `&[u8; 3]` as `*const i8` is invalid
|
||||||
--> $DIR/const-cast-wrong-type.rs:2:22
|
--> $DIR/const-cast-wrong-type.rs:2:22
|
||||||
|
|
|
|
||||||
LL | const b: *const i8 = &a as *const i8;
|
LL | const b: *const i8 = &a as *const i8;
|
||||||
| ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0606`.
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
//@ known-bug: #137287
|
// Regression test for #137287
|
||||||
|
|
||||||
mod defining_scope {
|
mod defining_scope {
|
||||||
use super::*;
|
use super::*;
|
||||||
pub type Alias<T> = impl Sized;
|
pub type Alias<T> = impl Sized;
|
||||||
|
//~^ ERROR unconstrained opaque type
|
||||||
|
//~| ERROR `impl Trait` in type aliases is unstable
|
||||||
|
|
||||||
pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
|
pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
|
||||||
x
|
x
|
||||||
|
//~^ ERROR mismatched types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +24,7 @@ impl<T> Trait<T> for T {
|
||||||
type Assoc = Box<u32>;
|
type Assoc = Box<u32>;
|
||||||
}
|
}
|
||||||
impl<T> Trait<T> for defining_scope::Alias<T> {
|
impl<T> Trait<T> for defining_scope::Alias<T> {
|
||||||
|
//~^ ERROR conflicting implementations of trait `Trait<_>`
|
||||||
type Assoc = usize;
|
type Assoc = usize;
|
||||||
}
|
}
|
||||||
|
|
47
tests/ui/drop/drop_elaboration_with_errors2.stderr
Normal file
47
tests/ui/drop/drop_elaboration_with_errors2.stderr
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
error[E0658]: `impl Trait` in type aliases is unstable
|
||||||
|
--> $DIR/drop_elaboration_with_errors2.rs:5:25
|
||||||
|
|
|
||||||
|
LL | pub type Alias<T> = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
|
||||||
|
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0119]: conflicting implementations of trait `Trait<_>`
|
||||||
|
--> $DIR/drop_elaboration_with_errors2.rs:26:1
|
||||||
|
|
|
||||||
|
LL | impl<T> Trait<T> for T {
|
||||||
|
| ---------------------- first implementation here
|
||||||
|
...
|
||||||
|
LL | impl<T> Trait<T> for defining_scope::Alias<T> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
|
||||||
|
|
||||||
|
error: unconstrained opaque type
|
||||||
|
--> $DIR/drop_elaboration_with_errors2.rs:5:25
|
||||||
|
|
|
||||||
|
LL | pub type Alias<T> = impl Sized;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `Alias` must be used in combination with a concrete type within the same crate
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/drop_elaboration_with_errors2.rs:10:9
|
||||||
|
|
|
||||||
|
LL | pub type Alias<T> = impl Sized;
|
||||||
|
| ---------- the found opaque type
|
||||||
|
...
|
||||||
|
LL | pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
|
||||||
|
| - expected this type parameter --------------- expected `Container<T, T>` because of return type
|
||||||
|
LL | x
|
||||||
|
| ^ expected `Container<T, T>`, found `Container<Alias<T>, T>`
|
||||||
|
|
|
||||||
|
= note: expected struct `Container<T, _>`
|
||||||
|
found struct `Container<Alias<T>, _>`
|
||||||
|
= help: type parameters must be constrained to match other types
|
||||||
|
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0119, E0308, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0119`.
|
|
@ -1,5 +1,6 @@
|
||||||
//@ known-bug: #135668
|
// Regression test for #135668
|
||||||
//@ edition: 2021
|
//@ edition: 2021
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
pub async fn foo() {
|
pub async fn foo() {
|
||||||
|
@ -11,7 +12,8 @@ async fn create_task() -> impl Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn documentation() {
|
async fn documentation() {
|
||||||
include_str!("nonexistent");
|
compile_error!("bonjour");
|
||||||
|
//~^ ERROR bonjour
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind<F>(_filter: F) -> impl Sized
|
fn bind<F>(_filter: F) -> impl Sized
|
||||||
|
@ -36,3 +38,5 @@ where
|
||||||
{
|
{
|
||||||
type Assoc = F;
|
type Assoc = F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
8
tests/ui/drop/drop_elaboration_with_errors3.stderr
Normal file
8
tests/ui/drop/drop_elaboration_with_errors3.stderr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
error: bonjour
|
||||||
|
--> $DIR/drop_elaboration_with_errors3.rs:15:5
|
||||||
|
|
|
||||||
|
LL | compile_error!("bonjour");
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
//@ needs-asm-support
|
||||||
|
//@ only-x86_64
|
||||||
|
|
||||||
|
#![feature(naked_functions, rust_cold_cc)]
|
||||||
|
|
||||||
|
use std::arch::naked_asm;
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
pub unsafe fn rust_implicit() {
|
||||||
|
//~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions
|
||||||
|
naked_asm!("ret");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "Rust" fn rust_explicit() {
|
||||||
|
//~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions
|
||||||
|
naked_asm!("ret");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "rust-cold" fn rust_cold() {
|
||||||
|
//~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions
|
||||||
|
naked_asm!("ret");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,33 @@
|
||||||
|
error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions
|
||||||
|
--> $DIR/feature-gate-naked_functions_rustic_abi.rs:9:1
|
||||||
|
|
|
||||||
|
LL | pub unsafe fn rust_implicit() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #138997 <https://github.com/rust-lang/rust/issues/138997> for more information
|
||||||
|
= help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions
|
||||||
|
--> $DIR/feature-gate-naked_functions_rustic_abi.rs:15:1
|
||||||
|
|
|
||||||
|
LL | pub unsafe extern "Rust" fn rust_explicit() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #138997 <https://github.com/rust-lang/rust/issues/138997> for more information
|
||||||
|
= help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: `#[naked]` is currently unstable on `extern "rust-cold"` functions
|
||||||
|
--> $DIR/feature-gate-naked_functions_rustic_abi.rs:21:1
|
||||||
|
|
|
||||||
|
LL | pub unsafe extern "rust-cold" fn rust_cold() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #138997 <https://github.com/rust-lang/rust/issues/138997> for more information
|
||||||
|
= help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -1,19 +1,29 @@
|
||||||
// Test that dead code warnings are issued for superfluous assignments of
|
//! Test that dead code warnings are issued for superfluous assignments of fields or variables to
|
||||||
// fields or variables to themselves (issue #75356).
|
//! themselves (issue #75356).
|
||||||
|
//!
|
||||||
//@ ignore-test FIXME(81658, 83171)
|
//! # History of this test (to aid relanding of a fixed version of #81473)
|
||||||
|
//!
|
||||||
|
//! - Original lint request was about self-assignments not triggering sth like `dead_code`.
|
||||||
|
//! - `dead_code` lint expansion for self-assignments was implemented in #87129.
|
||||||
|
//! - Unfortunately implementation components of #87129 had to be disabled as part of reverts
|
||||||
|
//! #86212, #83171 (to revert #81473) to address regressions #81626 and #81658.
|
||||||
|
//! - Consequently, none of the following warnings are emitted.
|
||||||
|
|
||||||
//@ check-pass
|
//@ check-pass
|
||||||
|
|
||||||
|
// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts.
|
||||||
|
//@ known-bug: #75356
|
||||||
|
|
||||||
#![allow(unused_assignments)]
|
#![allow(unused_assignments)]
|
||||||
#![warn(dead_code)]
|
#![warn(dead_code)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
x = x;
|
x = x;
|
||||||
//~^ WARNING: useless assignment of variable of type `i32` to itself
|
// FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
|
||||||
|
|
||||||
x = (x);
|
x = (x);
|
||||||
//~^ WARNING: useless assignment of variable of type `i32` to itself
|
// FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
|
||||||
|
|
||||||
x = {x};
|
x = {x};
|
||||||
// block expressions don't count as self-assignments
|
// block expressions don't count as self-assignments
|
||||||
|
@ -22,10 +32,10 @@ fn main() {
|
||||||
struct S<'a> { f: &'a str }
|
struct S<'a> { f: &'a str }
|
||||||
let mut s = S { f: "abc" };
|
let mut s = S { f: "abc" };
|
||||||
s = s;
|
s = s;
|
||||||
//~^ WARNING: useless assignment of variable of type `S` to itself
|
// FIXME ~^ WARNING: useless assignment of variable of type `S` to itself
|
||||||
|
|
||||||
s.f = s.f;
|
s.f = s.f;
|
||||||
//~^ WARNING: useless assignment of field of type `&str` to itself
|
// FIXME ~^ WARNING: useless assignment of field of type `&str` to itself
|
||||||
|
|
||||||
|
|
||||||
struct N0 { x: Box<i32> }
|
struct N0 { x: Box<i32> }
|
||||||
|
@ -34,11 +44,11 @@ fn main() {
|
||||||
struct N3 { n: N2 };
|
struct N3 { n: N2 };
|
||||||
let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) };
|
let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) };
|
||||||
n3.n.0.n.x = n3.n.0.n.x;
|
n3.n.0.n.x = n3.n.0.n.x;
|
||||||
//~^ WARNING: useless assignment of field of type `Box<i32>` to itself
|
// FIXME ~^ WARNING: useless assignment of field of type `Box<i32>` to itself
|
||||||
|
|
||||||
let mut t = (1, ((2, 3, (4, 5)),));
|
let mut t = (1, ((2, 3, (4, 5)),));
|
||||||
t.1.0.2.1 = t.1.0.2.1;
|
t.1.0.2.1 = t.1.0.2.1;
|
||||||
//~^ WARNING: useless assignment of field of type `i32` to itself
|
// FIXME ~^ WARNING: useless assignment of field of type `i32` to itself
|
||||||
|
|
||||||
|
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
warning: useless assignment of variable of type `i32` to itself
|
|
||||||
--> $DIR/self-assign.rs:10:5
|
|
||||||
|
|
|
||||||
LL | x = x;
|
|
||||||
| ^^^^^
|
|
||||||
|
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/self-assign.rs:6:9
|
|
||||||
|
|
|
||||||
LL | #![warn(dead_code)]
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
||||||
warning: useless assignment of variable of type `i32` to itself
|
|
||||||
--> $DIR/self-assign.rs:13:5
|
|
||||||
|
|
|
||||||
LL | x = (x);
|
|
||||||
| ^^^^^^^
|
|
||||||
|
|
||||||
warning: useless assignment of variable of type `S` to itself
|
|
||||||
--> $DIR/self-assign.rs:22:5
|
|
||||||
|
|
|
||||||
LL | s = s;
|
|
||||||
| ^^^^^
|
|
||||||
|
|
||||||
warning: useless assignment of field of type `&str` to itself
|
|
||||||
--> $DIR/self-assign.rs:25:5
|
|
||||||
|
|
|
||||||
LL | s.f = s.f;
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
||||||
warning: useless assignment of field of type `Box<i32>` to itself
|
|
||||||
--> $DIR/self-assign.rs:34:5
|
|
||||||
|
|
|
||||||
LL | n3.n.0.n.x = n3.n.0.n.x;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
warning: useless assignment of field of type `i32` to itself
|
|
||||||
--> $DIR/self-assign.rs:38:5
|
|
||||||
|
|
|
||||||
LL | t.1.0.2.1 = t.1.0.2.1;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
warning: 6 warnings emitted
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![deny(undefined_naked_function_abi)]
|
||||||
|
//~^ WARN lint `undefined_naked_function_abi` has been removed
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
warning: lint `undefined_naked_function_abi` has been removed: converted into hard error, see PR #139001 <https://github.com/rust-lang/rust/issues/139001> for more information
|
||||||
|
--> $DIR/undefined_naked_function_abi.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(undefined_naked_function_abi)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(renamed_and_removed_lints)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
28
tests/ui/macros/remove-repetition-issue-139480.rs
Normal file
28
tests/ui/macros/remove-repetition-issue-139480.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
macro_rules! ciallo {
|
||||||
|
($($v: vis)? $name: ident) => {
|
||||||
|
//~^ error: repetition matches empty token tree
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! meow {
|
||||||
|
($name: ident $($v: vis)?) => {
|
||||||
|
//~^ error: repetition matches empty token tree
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! gbc {
|
||||||
|
($name: ident $/*
|
||||||
|
this comment gets removed by the suggestion
|
||||||
|
*/
|
||||||
|
($v: vis)?) => {
|
||||||
|
//~^ error: repetition matches empty token tree
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ciallo!(hello);
|
||||||
|
|
||||||
|
meow!(miaow, pub);
|
||||||
|
|
||||||
|
gbc!(mygo,);
|
||||||
|
|
||||||
|
fn main() {}
|
44
tests/ui/macros/remove-repetition-issue-139480.stderr
Normal file
44
tests/ui/macros/remove-repetition-issue-139480.stderr
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/remove-repetition-issue-139480.rs:2:7
|
||||||
|
|
|
||||||
|
LL | ($($v: vis)? $name: ident) => {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a `vis` fragment can already be empty
|
||||||
|
help: remove the `$(` and `)?`
|
||||||
|
|
|
||||||
|
LL - ($($v: vis)? $name: ident) => {
|
||||||
|
LL + ($v: vis $name: ident) => {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/remove-repetition-issue-139480.rs:8:20
|
||||||
|
|
|
||||||
|
LL | ($name: ident $($v: vis)?) => {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a `vis` fragment can already be empty
|
||||||
|
help: remove the `$(` and `)?`
|
||||||
|
|
|
||||||
|
LL - ($name: ident $($v: vis)?) => {
|
||||||
|
LL + ($name: ident $v: vis) => {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: repetition matches empty token tree
|
||||||
|
--> $DIR/remove-repetition-issue-139480.rs:17:9
|
||||||
|
|
|
||||||
|
LL | ($v: vis)?) => {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a `vis` fragment can already be empty
|
||||||
|
help: remove the `$(` and `)?`
|
||||||
|
|
|
||||||
|
LL - ($name: ident $/*
|
||||||
|
LL - this comment gets removed by the suggestion
|
||||||
|
LL - */
|
||||||
|
LL - ($v: vis)?) => {
|
||||||
|
LL + ($name: ident $v: vis) => {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
//@ check-pass
|
||||||
|
// this test ensures that UnsafePinned hides the niche of its inner type, just like UnsafeCell does
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(unsafe_pinned)]
|
||||||
|
|
||||||
|
use std::num::NonZero;
|
||||||
|
use std::pin::UnsafePinned;
|
||||||
|
|
||||||
|
macro_rules! assert_size_is {
|
||||||
|
($ty:ty = $size:expr) => {
|
||||||
|
const _: () = assert!(size_of::<$ty>() == $size);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_size_is!(UnsafePinned<()> = 0);
|
||||||
|
assert_size_is!(UnsafePinned<u8> = 1);
|
||||||
|
|
||||||
|
assert_size_is!( UnsafePinned< u32> = 4);
|
||||||
|
assert_size_is!( UnsafePinned< NonZero<u32>> = 4);
|
||||||
|
assert_size_is!( UnsafePinned<Option<NonZero<u32>>> = 4);
|
||||||
|
assert_size_is!(Option<UnsafePinned< u32>> = 8);
|
||||||
|
assert_size_is!(Option<UnsafePinned< NonZero<u32>>> = 8);
|
||||||
|
assert_size_is!(Option<UnsafePinned<Option<NonZero<u32>>>> = 8);
|
||||||
|
|
||||||
|
assert_size_is!( UnsafePinned< &()> = size_of::<usize>());
|
||||||
|
assert_size_is!( UnsafePinned<Option<&()>> = size_of::<usize>());
|
||||||
|
assert_size_is!(Option<UnsafePinned< &()>> = size_of::<usize>() * 2);
|
||||||
|
assert_size_is!(Option<UnsafePinned<Option<&()>>> = size_of::<usize>() * 2);
|
Loading…
Add table
Add a link
Reference in a new issue