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,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
is_special_no_niche: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||
|
@ -348,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr,
|
||||
variants,
|
||||
is_enum,
|
||||
is_unsafe_cell,
|
||||
is_special_no_niche,
|
||||
scalar_valid_range,
|
||||
always_sized,
|
||||
present_first,
|
||||
|
@ -505,7 +505,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
is_special_no_niche: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
always_sized: bool,
|
||||
present_first: VariantIdx,
|
||||
|
@ -524,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let mut st = self.univariant(&variants[v], repr, kind)?;
|
||||
st.variants = Variants::Single { index: v };
|
||||
|
||||
if is_unsafe_cell {
|
||||
if is_special_no_niche {
|
||||
let hide_niches = |scalar: &mut _| match scalar {
|
||||
Scalar::Initialized { value, valid_range } => {
|
||||
*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_attr_parsing::{AttributeKind, find_attr};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed};
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
|
@ -27,19 +27,18 @@ use rustc_span::hygiene::Transparency;
|
|||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
|
||||
use tracing::{debug, instrument, trace, trace_span};
|
||||
|
||||
use super::diagnostics;
|
||||
use super::macro_parser::{NamedMatches, NamedParseResult};
|
||||
use super::{SequenceRepetition, diagnostics};
|
||||
use crate::base::{
|
||||
DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
|
||||
SyntaxExtensionKind, TTMacroExpander,
|
||||
};
|
||||
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::macro_check;
|
||||
use crate::mbe::macro_parser::NamedMatch::*;
|
||||
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
|
||||
use crate::mbe::transcribe::transcribe;
|
||||
use crate::mbe::{self, KleeneOp, macro_check};
|
||||
|
||||
pub(crate) struct ParserAnyMacro<'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
|
||||
/// tree, because then the matcher would hang indefinitely.
|
||||
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) => {
|
||||
if is_empty_token_tree(sess, seq) {
|
||||
let sp = span.entire();
|
||||
let guar = sess.dcx().span_err(sp, "repetition matches empty token tree");
|
||||
return Err(guar);
|
||||
let mut err =
|
||||
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)?
|
||||
}
|
||||
|
|
|
@ -565,6 +565,8 @@ declare_features! (
|
|||
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(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.
|
||||
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
|
||||
/// Allows specifying the as-needed link modifier
|
||||
|
|
|
@ -182,6 +182,7 @@ language_item_table! {
|
|||
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
|
|
@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
m_cast: ty::TypeAndMut<'tcx>,
|
||||
) -> Result<CastKind, CastError<'tcx>> {
|
||||
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
|
||||
if m_expr.mutbl >= m_cast.mutbl {
|
||||
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// To allow raw pointers to work correctly, we
|
||||
// need to special-case obtaining a raw pointer
|
||||
// from a region pointer to a vector.
|
||||
if m_expr.mutbl >= m_cast.mutbl
|
||||
&& let ty::Array(ety, _) = m_expr.ty.kind()
|
||||
&& fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
|
||||
{
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// 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.
|
||||
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)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
// 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);
|
||||
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
||||
self.expr_ty,
|
||||
array_ptr_type,
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
// this will report a type mismatch if needed
|
||||
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
|
||||
return Ok(CastKind::ArrayPtrCast);
|
||||
}
|
||||
// this will report a type mismatch if needed
|
||||
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
|
||||
return Ok(CastKind::ArrayPtrCast);
|
||||
}
|
||||
|
||||
Err(CastError::IllegalCast)
|
||||
|
|
|
@ -103,15 +103,6 @@ fn coerce_mutbls<'tcx>(
|
|||
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(...)`.
|
||||
fn success<'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 }
|
||||
}
|
||||
|
||||
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);
|
||||
self.commit_if_ok(|_| {
|
||||
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.
|
||||
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
|
||||
where
|
||||
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
{
|
||||
self.unify(a, b)
|
||||
.and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
|
||||
fn unify_and(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
adjustments: impl IntoIterator<Item = Adjustment<'tcx>>,
|
||||
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))]
|
||||
|
@ -180,10 +188,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// Coercing from `!` to any type is allowed:
|
||||
if a.is_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 {
|
||||
// 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
|
||||
// ultimately fall back to some form of subtyping.
|
||||
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
|
||||
|
@ -247,7 +259,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
ty::FnPtr(a_sig_tys, a_hdr) => {
|
||||
// We permit coercion of fn pointers to drop the
|
||||
// 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) => {
|
||||
// Non-capturing closures are coercible to
|
||||
|
@ -257,7 +269,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
}
|
||||
_ => {
|
||||
// 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
|
||||
/// about the source type, so we can't really do a true coercion and we always
|
||||
/// fall back to subtyping (`unify_and`).
|
||||
fn coerce_from_inference_variable(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
) -> CoerceResult<'tcx> {
|
||||
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
|
||||
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
|
||||
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={:?}",
|
||||
target_ty, obligations
|
||||
);
|
||||
let adjustments = make_adjustments(target_ty);
|
||||
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
|
||||
success(vec![], target_ty, obligations)
|
||||
} else {
|
||||
// One unresolved type variable: just apply subtyping, we may be able
|
||||
// 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)?;
|
||||
(r_a, mt_a)
|
||||
}
|
||||
_ => return self.unify_and(a, b, identity),
|
||||
_ => return self.unify(a, b),
|
||||
};
|
||||
|
||||
let span = self.cause.span;
|
||||
|
@ -437,7 +443,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
referent_ty,
|
||||
mutbl_b, // [1] above
|
||||
);
|
||||
match self.unify(derefd_ty_a, b) {
|
||||
match self.unify_raw(derefd_ty_a, b) {
|
||||
Ok(ok) => {
|
||||
found = Some(ok);
|
||||
break;
|
||||
|
@ -579,13 +585,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// We only have the latter, so we use an inference variable
|
||||
// for the former and let type inference do the rest.
|
||||
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 };
|
||||
match reborrow {
|
||||
None => vec![unsize],
|
||||
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
|
||||
}
|
||||
})?;
|
||||
|
||||
let mut coercion = self.unify_and(
|
||||
coerce_target,
|
||||
target,
|
||||
reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]),
|
||||
Adjust::Pointer(PointerCoercion::Unsize),
|
||||
)?;
|
||||
|
||||
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()
|
||||
&& 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
|
||||
|
@ -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
|
||||
// add the adjustments.
|
||||
self.unify_and(a, b, |_inner_ty| {
|
||||
vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }]
|
||||
})
|
||||
self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
|
||||
}
|
||||
|
||||
fn coerce_from_safe_fn<F, G>(
|
||||
fn coerce_from_safe_fn(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
to_unsafe: F,
|
||||
normal: G,
|
||||
) -> CoerceResult<'tcx>
|
||||
where
|
||||
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
{
|
||||
adjustment: Option<Adjust>,
|
||||
) -> CoerceResult<'tcx> {
|
||||
self.commit_if_ok(|snapshot| {
|
||||
let outer_universe = self.infcx.universe();
|
||||
|
||||
|
@ -833,9 +831,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
&& hdr_b.safety.is_unsafe()
|
||||
{
|
||||
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 {
|
||||
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
|
||||
|
@ -852,7 +860,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
fn coerce_from_fn_pointer(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
) -> CoerceResult<'tcx> {
|
||||
|
@ -861,15 +868,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
//!
|
||||
|
||||
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(
|
||||
a,
|
||||
fn_ty_a,
|
||||
b,
|
||||
simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
|
||||
identity,
|
||||
)
|
||||
self.coerce_from_safe_fn(fn_ty_a, b, None)
|
||||
}
|
||||
|
||||
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);
|
||||
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(
|
||||
a_fn_pointer,
|
||||
a_sig,
|
||||
b,
|
||||
|unsafe_ty| {
|
||||
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)),
|
||||
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
|
||||
)?;
|
||||
|
||||
obligations.extend(o2);
|
||||
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(
|
||||
pointer_ty,
|
||||
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() {
|
||||
ty::Ref(_, ty, mutbl) => (true, 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)?;
|
||||
|
||||
|
@ -1011,16 +999,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// representation, we still register an Adjust::DerefRef so that
|
||||
// regionck knows that the region for `a` must be valid here.
|
||||
if is_ref {
|
||||
self.unify_and(a_raw, b, |target| {
|
||||
vec![
|
||||
Adjustment { kind: Adjust::Deref(None), target: mt_a.ty },
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target },
|
||||
]
|
||||
})
|
||||
self.unify_and(
|
||||
a_raw,
|
||||
b,
|
||||
[Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(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 {
|
||||
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);
|
||||
// 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);
|
||||
coerce
|
||||
.autoderef(DUMMY_SP, expr_ty)
|
||||
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
|
||||
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
|
||||
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
#[inline]
|
||||
fn new(value: usize) -> Self {
|
||||
|
|
|
@ -606,6 +606,11 @@ fn register_builtins(store: &mut LintStore) {
|
|||
"converted into hard error, see issue #127323 \
|
||||
<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) {
|
||||
|
|
|
@ -864,8 +864,8 @@ fn ty_is_known_nonnull<'tcx>(
|
|||
return true;
|
||||
}
|
||||
|
||||
// `UnsafeCell` has its niche hidden.
|
||||
if def.is_unsafe_cell() {
|
||||
// `UnsafeCell` and `UnsafePinned` have their niche hidden.
|
||||
if def.is_unsafe_cell() || def.is_unsafe_pinned() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,6 @@ declare_lint_pass! {
|
|||
UNCONDITIONAL_PANIC,
|
||||
UNCONDITIONAL_RECURSION,
|
||||
UNCOVERED_PARAM_IN_PROJECTION,
|
||||
UNDEFINED_NAKED_FUNCTION_ABI,
|
||||
UNEXPECTED_CFGS,
|
||||
UNFULFILLED_LINT_EXPECTATIONS,
|
||||
UNINHABITED_STATIC,
|
||||
|
@ -2830,39 +2829,6 @@ declare_lint! {
|
|||
"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! {
|
||||
/// 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;
|
||||
/// Indicates whether the type is `UnsafeCell`.
|
||||
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 }
|
||||
|
@ -302,6 +306,9 @@ impl AdtDefData {
|
|||
if tcx.is_lang_item(did, LangItem::UnsafeCell) {
|
||||
flags |= AdtFlags::IS_UNSAFE_CELL;
|
||||
}
|
||||
if tcx.is_lang_item(did, LangItem::UnsafePinned) {
|
||||
flags |= AdtFlags::IS_UNSAFE_PINNED;
|
||||
}
|
||||
|
||||
AdtDefData { did, variants, flags, repr }
|
||||
}
|
||||
|
@ -405,6 +412,12 @@ impl<'tcx> AdtDef<'tcx> {
|
|||
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>`.
|
||||
#[inline]
|
||||
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);
|
||||
|
||||
for bb in START_BLOCK..body.basic_blocks.next_index() {
|
||||
for bb in body.basic_blocks.indices() {
|
||||
let bb_data = &body[bb];
|
||||
if bb_data.is_cleanup {
|
||||
continue;
|
||||
|
@ -556,11 +556,11 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
match &bb_data.terminator().kind {
|
||||
TerminatorKind::Call { func, .. } => {
|
||||
let func_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
||||
if 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);
|
||||
}
|
||||
if let ty::FnDef(def_id, _) = *func_ty.kind()
|
||||
&& 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);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Yield { resume_arg, .. } => {
|
||||
|
@ -1057,7 +1057,7 @@ fn insert_switch<'tcx>(
|
|||
let blocks = body.basic_blocks_mut().iter_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.
|
||||
for block in body.basic_blocks.iter() {
|
||||
if let TerminatorKind::Return = block.terminator().kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
body.basic_blocks.iter().any(|block| matches!(block.terminator().kind, TerminatorKind::Return))
|
||||
// Otherwise the function can't return.
|
||||
false
|
||||
}
|
||||
|
||||
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 },
|
||||
};
|
||||
}
|
||||
} 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
|
||||
// pointed at our poisoning block (unless they're part of the cleanup path).
|
||||
if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() {
|
||||
*unwind = UnwindAction::Cleanup(poison_block);
|
||||
}
|
||||
&& let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut()
|
||||
{
|
||||
*unwind = UnwindAction::Cleanup(poison_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1340,12 +1334,14 @@ fn create_coroutine_resume_function<'tcx>(
|
|||
make_coroutine_state_argument_indirect(tcx, body);
|
||||
|
||||
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,
|
||||
// unlike for all other coroutine kinds.
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {}
|
||||
_ => {
|
||||
make_coroutine_state_argument_pinned(tcx, body);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we remove dead blocks to remove
|
||||
|
@ -1408,8 +1404,7 @@ fn create_cases<'tcx>(
|
|||
let mut statements = Vec::new();
|
||||
|
||||
// Create StorageLive instructions for locals with live storage
|
||||
for i in 0..(body.local_decls.len()) {
|
||||
let l = Local::new(i);
|
||||
for l in body.local_decls.indices() {
|
||||
let needs_storage_live = point.storage_liveness.contains(l)
|
||||
&& !transform.remap.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();
|
||||
|
||||
// Get the discriminant type and args which typeck computed
|
||||
let (discr_ty, movable) = match *coroutine_ty.kind() {
|
||||
ty::Coroutine(_, args) => {
|
||||
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 ty::Coroutine(_, args) = coroutine_ty.kind() else {
|
||||
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 {
|
||||
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 movable = coroutine_kind.movability() == hir::Movability::Movable;
|
||||
let liveness_info =
|
||||
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;
|
||||
|
||||
// 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 parent = BasicBlock::from_usize(i);
|
||||
let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue };
|
||||
|
||||
trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}");
|
||||
|
|
|
@ -266,19 +266,16 @@ where
|
|||
let tcx = self.tcx();
|
||||
|
||||
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
|
||||
.try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args))
|
||||
{
|
||||
Ok(t) => t,
|
||||
Err(_) => Ty::new_error(
|
||||
self.tcx(),
|
||||
self.elaborator
|
||||
.body()
|
||||
.tainted_by_errors
|
||||
.expect("Error in drop elaboration not found by dropck."),
|
||||
self.tcx().dcx().span_delayed_bug(
|
||||
self.elaborator.body().span,
|
||||
"Error normalizing in drop elaboration.",
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout};
|
|||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
|
||||
use crate::simplify::simplify_duplicate_switch_targets;
|
||||
use crate::take_array;
|
||||
|
||||
pub(super) enum InstSimplify {
|
||||
BeforeInline,
|
||||
|
@ -214,7 +213,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
|||
terminator: &mut Terminator<'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 {
|
||||
return;
|
||||
};
|
||||
|
@ -222,15 +223,8 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
|||
// It's definitely not a clone if there are multiple arguments
|
||||
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
|
||||
let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return };
|
||||
|
||||
// Clone needs one arg, so we can cheaply rule out other stuff
|
||||
if fn_args.len() != 1 {
|
||||
return;
|
||||
}
|
||||
let Some((fn_def_id, ..)) = func.const_fn_def() else { return };
|
||||
|
||||
// These types are easily available from locals, so check that before
|
||||
// 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 };
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
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>) {
|
||||
|
|
|
@ -20,13 +20,11 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let typing_env = body.typing_env(tcx);
|
||||
let mut should_cleanup = false;
|
||||
for i in 0..body.basic_blocks.len() {
|
||||
let bbs = &*body.basic_blocks;
|
||||
let bb_idx = BasicBlock::from_usize(i);
|
||||
match bbs[bb_idx].terminator().kind {
|
||||
for bb_idx in body.basic_blocks.indices() {
|
||||
match &body.basic_blocks[bb_idx].terminator().kind {
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)),
|
||||
ref targets,
|
||||
discr: Operand::Copy(_) | Operand::Move(_),
|
||||
targets,
|
||||
..
|
||||
// We require that the possible target blocks don't contain this block.
|
||||
} if !targets.all_targets().contains(&bb_idx) => {}
|
||||
|
@ -66,9 +64,10 @@ trait SimplifyMatch<'tcx> {
|
|||
typing_env: ty::TypingEnv<'tcx>,
|
||||
) -> Option<()> {
|
||||
let bbs = &body.basic_blocks;
|
||||
let (discr, targets) = match bbs[switch_bb_idx].terminator().kind {
|
||||
TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets),
|
||||
_ => unreachable!(),
|
||||
let TerminatorKind::SwitchInt { discr, targets, .. } =
|
||||
&bbs[switch_bb_idx].terminator().kind
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
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
|
||||
let mut bbs_simple_returns = DenseBitSet::new_empty(body.basic_blocks.len());
|
||||
let bbs = body.basic_blocks_mut();
|
||||
for idx in bbs.indices() {
|
||||
if bbs[idx].statements.is_empty()
|
||||
&& bbs[idx].terminator().kind == TerminatorKind::Return
|
||||
{
|
||||
for (idx, bb) in bbs.iter_enumerated() {
|
||||
if bb.statements.is_empty() && bb.terminator().kind == TerminatorKind::Return {
|
||||
bbs_simple_returns.insert(idx);
|
||||
}
|
||||
}
|
||||
|
||||
for bb in bbs {
|
||||
if let TerminatorKind::Goto { target } = bb.terminator().kind {
|
||||
if bbs_simple_returns.contains(target) {
|
||||
bb.terminator_mut().kind = TerminatorKind::Return;
|
||||
}
|
||||
if let TerminatorKind::Goto { target } = bb.terminator().kind
|
||||
&& bbs_simple_returns.contains(target)
|
||||
{
|
||||
bb.terminator_mut().kind = TerminatorKind::Return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -221,12 +221,11 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
|||
|
||||
// Check for cycles
|
||||
let mut stack = FxHashSet::default();
|
||||
for i in 0..parent.len() {
|
||||
let mut bb = BasicBlock::from_usize(i);
|
||||
for (mut bb, parent) in parent.iter_enumerated_mut() {
|
||||
stack.clear();
|
||||
stack.insert(bb);
|
||||
loop {
|
||||
let Some(parent) = parent[bb].take() else { break };
|
||||
let Some(parent) = parent.take() else { break };
|
||||
let no_cycle = stack.insert(parent);
|
||||
if !no_cycle {
|
||||
self.fail(
|
||||
|
|
|
@ -742,9 +742,6 @@ passes_trait_impl_const_stable =
|
|||
passes_transparent_incompatible =
|
||||
transparent {$target} cannot have other repr hints
|
||||
|
||||
passes_undefined_naked_function_abi =
|
||||
Rust ABI is unsupported in naked functions
|
||||
|
||||
passes_unknown_external_lang_item =
|
||||
unknown external lang item: `{$lang_item}`
|
||||
|
||||
|
|
|
@ -624,6 +624,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
match target {
|
||||
Target::Fn
|
||||
| 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 {
|
||||
// this covers "sugared doc comments" of the form `/// ...`
|
||||
// it does not cover `#[doc = "..."]`, which is handled below
|
||||
|
|
|
@ -1197,10 +1197,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
|
|||
pub cf_type: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_undefined_naked_function_abi)]
|
||||
pub(crate) struct UndefinedNakedFunctionAbi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_no_patterns)]
|
||||
pub(crate) struct NoPatterns {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! Checks validity of naked functions.
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
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::span_bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use crate::errors::{
|
||||
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
|
||||
ParamsNotAllowed, UndefinedNakedFunctionAbi,
|
||||
ParamsNotAllowed,
|
||||
};
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
@ -29,26 +27,21 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
|||
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 {
|
||||
kind: hir::ItemKind::Fn { sig, body: body_id, .. },
|
||||
..
|
||||
kind: hir::ItemKind::Fn { body: body_id, .. }, ..
|
||||
})
|
||||
| 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 {
|
||||
kind: hir::ImplItemKind::Fn(sig, body_id),
|
||||
..
|
||||
}) => (sig.header, *body_id),
|
||||
kind: hir::ImplItemKind::Fn(_, body_id), ..
|
||||
}) => tcx.hir_body(*body_id),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let body = tcx.hir_body(body_id);
|
||||
|
||||
if tcx.has_attr(def_id, sym::naked) {
|
||||
check_abi(tcx, def_id, fn_header.abi);
|
||||
check_no_patterns(tcx, body.params);
|
||||
check_no_parameters_use(tcx, 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.
|
||||
fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
|
||||
for param in params {
|
||||
|
|
|
@ -244,6 +244,7 @@ where
|
|||
/// ```ignore(needs-extern-crate)
|
||||
/// # extern crate rustc_driver;
|
||||
/// # extern crate rustc_interface;
|
||||
/// # extern crate rustc_middle;
|
||||
/// # #[macro_use]
|
||||
/// # extern crate rustc_smir;
|
||||
/// # extern crate stable_mir;
|
||||
|
@ -264,6 +265,7 @@ where
|
|||
/// ```ignore(needs-extern-crate)
|
||||
/// # extern crate rustc_driver;
|
||||
/// # extern crate rustc_interface;
|
||||
/// # extern crate rustc_middle;
|
||||
/// # #[macro_use]
|
||||
/// # extern crate rustc_smir;
|
||||
/// # extern crate stable_mir;
|
||||
|
@ -328,6 +330,7 @@ macro_rules! run_driver {
|
|||
use rustc_driver::{Callbacks, Compilation, run_compiler};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_interface::interface;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::CompilerError;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
|
|
|
@ -633,6 +633,24 @@ impl SourceMap {
|
|||
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
|
||||
/// whitespace. Returns None if the pattern could not be found or if an error occurred while
|
||||
/// retrieving the code snippet.
|
||||
|
|
|
@ -1400,6 +1400,7 @@ symbols! {
|
|||
naked,
|
||||
naked_asm,
|
||||
naked_functions,
|
||||
naked_functions_rustic_abi,
|
||||
naked_functions_target_feature,
|
||||
name,
|
||||
names,
|
||||
|
@ -2215,6 +2216,8 @@ symbols! {
|
|||
unsafe_fields,
|
||||
unsafe_no_drop_flag,
|
||||
unsafe_pin_internals,
|
||||
unsafe_pinned,
|
||||
unsafe_unpin,
|
||||
unsize,
|
||||
unsized_const_param_ty,
|
||||
unsized_const_params,
|
||||
|
|
|
@ -514,6 +514,9 @@ fn layout_of_uncached<'tcx>(
|
|||
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 =
|
||||
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
|
||||
|
||||
|
@ -542,7 +545,7 @@ fn layout_of_uncached<'tcx>(
|
|||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
def.is_unsafe_cell(),
|
||||
is_special_no_niche,
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
|
@ -568,7 +571,7 @@ fn layout_of_uncached<'tcx>(
|
|||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
def.is_unsafe_cell(),
|
||||
is_special_no_niche,
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
|
|
|
@ -127,6 +127,7 @@
|
|||
#![feature(ub_checks)]
|
||||
#![feature(unchecked_neg)]
|
||||
#![feature(unchecked_shifts)]
|
||||
#![feature(unsafe_pinned)]
|
||||
#![feature(utf16_extra)]
|
||||
#![feature(variant_count)]
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::cell::UnsafeCell;
|
|||
use crate::cmp;
|
||||
use crate::fmt::Debug;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::pin::UnsafePinned;
|
||||
|
||||
/// Implements a given marker trait for multiple types at the same time.
|
||||
///
|
||||
|
@ -878,6 +879,23 @@ marker_impls! {
|
|||
{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.
|
||||
///
|
||||
/// 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`.
|
||||
///
|
||||
/// 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")]
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct PhantomPinned;
|
||||
|
@ -960,6 +983,12 @@ pub struct PhantomPinned;
|
|||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
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! {
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
Unpin for
|
||||
|
|
|
@ -931,6 +931,11 @@ use crate::{
|
|||
};
|
||||
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.
|
||||
///
|
||||
/// [`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 stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::abi::{
|
||||
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
|
||||
VariantsShape,
|
||||
|
|
|
@ -19,7 +19,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::crate_def::CrateDef;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef};
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use std::io::Write;
|
||||
use std::collections::HashSet;
|
||||
use stable_mir::CrateDef;
|
||||
|
|
|
@ -15,7 +15,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::{CrateDef, CrateItems};
|
||||
use std::io::Write;
|
||||
use std::ops::ControlFlow;
|
||||
|
|
|
@ -15,7 +15,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::mir::mono::Instance;
|
||||
use stable_mir::mir::visit::{Location, MirVisitor};
|
||||
use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind};
|
||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::CrateDef;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Write;
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ty::{Ty, ForeignItemKind};
|
||||
use stable_mir::*;
|
||||
use std::io::Write;
|
||||
|
|
|
@ -19,7 +19,6 @@ extern crate stable_mir;
|
|||
use std::assert_matches::assert_matches;
|
||||
use mir::{mono::Instance, TerminatorKind::*};
|
||||
use stable_mir::mir::mono::InstanceKind;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
|
||||
use stable_mir::*;
|
||||
use std::io::Write;
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_interface;
|
|||
extern crate rustc_span;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::{
|
||||
ty::{Abi, ForeignItemKind},
|
||||
*,
|
||||
|
|
|
@ -21,7 +21,6 @@ use std::ops::ControlFlow;
|
|||
|
||||
use mir::mono::Instance;
|
||||
use mir::TerminatorKind::*;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ty::{RigidTy, TyKind};
|
||||
use stable_mir::*;
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::mir::mono::{Instance, InstanceKind};
|
||||
use stable_mir::mir::visit::{Location, MirVisitor};
|
||||
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
|
||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::*;
|
||||
use std::io::Write;
|
||||
use std::ops::ControlFlow;
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate stable_mir;
|
|||
|
||||
use mir::mono::Instance;
|
||||
use ty::{Ty, TyKind, RigidTy};
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::*;
|
||||
use std::io::Write;
|
||||
use std::ops::ControlFlow;
|
||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::CrateDef;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Write;
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
use stable_mir::mir::mono::Instance;
|
||||
use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind};
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::mir::{
|
||||
Body, FieldIdx, MirVisitor, Place, ProjectionElem,
|
||||
visit::{Location, PlaceContext},
|
||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use std::io::Write;
|
||||
|
||||
/// 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;
|
||||
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ItemKind;
|
||||
use stable_mir::crate_def::CrateDef;
|
||||
use stable_mir::mir::mono::Instance;
|
||||
|
|
|
@ -17,7 +17,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ItemKind;
|
||||
use stable_mir::crate_def::CrateDef;
|
||||
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
|
||||
|
|
|
@ -19,7 +19,6 @@ extern crate serde_json;
|
|||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use serde_json::to_string;
|
||||
use stable_mir::mir::Body;
|
||||
use std::io::{BufWriter, Write};
|
||||
|
|
|
@ -16,7 +16,6 @@ extern crate rustc_driver;
|
|||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::mir::MirVisitor;
|
||||
use stable_mir::mir::MutMirVisitor;
|
||||
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
|
||||
//@ compile-flags: --test
|
||||
|
||||
#![allow(undefined_naked_function_abi)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(test)]
|
||||
#![crate_type = "lib"]
|
||||
|
@ -11,7 +10,7 @@ use std::arch::naked_asm;
|
|||
#[test]
|
||||
#[naked]
|
||||
//~^ ERROR [E0736]
|
||||
fn test_naked() {
|
||||
extern "C" fn test_naked() {
|
||||
unsafe { naked_asm!("") };
|
||||
}
|
||||
|
||||
|
@ -19,7 +18,7 @@ fn test_naked() {
|
|||
#[test]
|
||||
#[naked]
|
||||
//~^ ERROR [E0736]
|
||||
fn test_naked_should_panic() {
|
||||
extern "C" fn test_naked_should_panic() {
|
||||
unsafe { naked_asm!("") };
|
||||
}
|
||||
|
||||
|
@ -27,13 +26,13 @@ fn test_naked_should_panic() {
|
|||
#[test]
|
||||
#[naked]
|
||||
//~^ ERROR [E0736]
|
||||
fn test_naked_ignore() {
|
||||
extern "C" fn test_naked_ignore() {
|
||||
unsafe { naked_asm!("") };
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[naked]
|
||||
//~^ ERROR [E0736]
|
||||
fn bench_naked() {
|
||||
extern "C" fn bench_naked() {
|
||||
unsafe { naked_asm!("") };
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0736]: cannot use `#[naked]` with testing attributes
|
||||
--> $DIR/naked-functions-testattrs.rs:12:1
|
||||
--> $DIR/naked-functions-testattrs.rs:11:1
|
||||
|
|
||||
LL | #[test]
|
||||
| ------- function marked with testing attribute here
|
||||
|
@ -7,7 +7,7 @@ LL | #[naked]
|
|||
| ^^^^^^^^ `#[naked]` is incompatible 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]
|
||||
| ------- function marked with testing attribute here
|
||||
|
@ -15,7 +15,7 @@ LL | #[naked]
|
|||
| ^^^^^^^^ `#[naked]` is incompatible 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]
|
||||
| ------- function marked with testing attribute here
|
||||
|
@ -23,7 +23,7 @@ LL | #[naked]
|
|||
| ^^^^^^^^ `#[naked]` is incompatible 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]
|
||||
| -------- 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!`
|
||||
}
|
||||
|
||||
#[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]
|
||||
pub extern "C" fn valid_a<T>() -> T {
|
||||
unsafe {
|
||||
|
|
|
@ -53,19 +53,19 @@ LL | naked_asm!("", options(may_unwind));
|
|||
| ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
|
||||
|
||||
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")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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)
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -175,20 +175,6 @@ LL |
|
|||
LL | *&y
|
||||
| --- not allowed in naked functions
|
||||
|
||||
warning: Rust ABI is unsupported in naked functions
|
||||
--> $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
|
||||
error: aborting due to 25 previous errors
|
||||
|
||||
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 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() {
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
LL | const b: *const i8 = &a as *const i8;
|
||||
| ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
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 {
|
||||
use super::*;
|
||||
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> {
|
||||
x
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +24,7 @@ impl<T> Trait<T> for T {
|
|||
type Assoc = Box<u32>;
|
||||
}
|
||||
impl<T> Trait<T> for defining_scope::Alias<T> {
|
||||
//~^ ERROR conflicting implementations of trait `Trait<_>`
|
||||
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
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
pub async fn foo() {
|
||||
|
@ -11,7 +12,8 @@ async fn create_task() -> impl Sized {
|
|||
}
|
||||
|
||||
async fn documentation() {
|
||||
include_str!("nonexistent");
|
||||
compile_error!("bonjour");
|
||||
//~^ ERROR bonjour
|
||||
}
|
||||
|
||||
fn bind<F>(_filter: F) -> impl Sized
|
||||
|
@ -36,3 +38,5 @@ where
|
|||
{
|
||||
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
|
||||
// fields or variables to themselves (issue #75356).
|
||||
|
||||
//@ ignore-test FIXME(81658, 83171)
|
||||
//! Test that dead code warnings are issued for superfluous assignments of fields or variables to
|
||||
//! themselves (issue #75356).
|
||||
//!
|
||||
//! # 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
|
||||
|
||||
// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts.
|
||||
//@ known-bug: #75356
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
#![warn(dead_code)]
|
||||
|
||||
fn main() {
|
||||
let mut x = 0;
|
||||
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);
|
||||
//~^ WARNING: useless assignment of variable of type `i32` to itself
|
||||
// FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
|
||||
|
||||
x = {x};
|
||||
// block expressions don't count as self-assignments
|
||||
|
@ -22,10 +32,10 @@ fn main() {
|
|||
struct S<'a> { f: &'a str }
|
||||
let mut s = S { f: "abc" };
|
||||
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;
|
||||
//~^ 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> }
|
||||
|
@ -34,11 +44,11 @@ fn main() {
|
|||
struct N3 { n: N2 };
|
||||
let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) };
|
||||
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)),));
|
||||
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;
|
||||
|
|
|
@ -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