Auto merge of #139101 - matthiaskrgr:rollup-zhu7hf6, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #138692 (Reject `{true,false}` as revision names) - #138757 (wasm: increase default thread stack size to 1 MB) - #138988 (Change the syntax of the internal `weak!` macro) - #139056 (use `try_fold` instead of `fold`) - #139057 (use `slice::contains` where applicable) - #139086 (Various cleanup in ExprUseVisitor) - #139097 (Add more tests for pin!().) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5cc60728e7
28 changed files with 337 additions and 209 deletions
|
@ -74,12 +74,12 @@ pub(crate) fn use_panic_2021(mut span: Span) -> bool {
|
|||
// (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
|
||||
loop {
|
||||
let expn = span.ctxt().outer_expn_data();
|
||||
if let Some(features) = expn.allow_internal_unstable {
|
||||
if features.iter().any(|&f| f == sym::edition_panic) {
|
||||
if let Some(features) = expn.allow_internal_unstable
|
||||
&& features.contains(&sym::edition_panic)
|
||||
{
|
||||
span = expn.call_site;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break expn.edition >= Edition::Edition2021;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2186,7 +2186,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
|
|||
// indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve
|
||||
// these, but it currently does not do so.
|
||||
let can_have_static_objects =
|
||||
tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib);
|
||||
tcx.sess.lto() == Lto::Thin || tcx.crate_types().contains(&CrateType::Rlib);
|
||||
|
||||
tcx.sess.target.is_like_windows &&
|
||||
can_have_static_objects &&
|
||||
|
|
|
@ -604,7 +604,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
if let Some((name, _)) = lang_items::extract(attrs)
|
||||
&& let Some(lang_item) = LangItem::from_name(name)
|
||||
{
|
||||
if WEAK_LANG_ITEMS.iter().any(|&l| l == lang_item) {
|
||||
if WEAK_LANG_ITEMS.contains(&lang_item) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||
}
|
||||
if let Some(link_name) = lang_item.link_name() {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
//! A different sort of visitor for walking fn bodies. Unlike the
|
||||
//! normal visitor, which just walks the entire body in one shot, the
|
||||
//! `ExprUseVisitor` determines how expressions are being used.
|
||||
//!
|
||||
//! In the compiler, this is only used for upvar inference, but there
|
||||
//! are many uses within clippy.
|
||||
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::ops::Deref;
|
||||
|
@ -25,7 +28,7 @@ use rustc_middle::ty::{
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use tracing::{debug, trace};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::fn_ctxt::FnCtxt;
|
||||
|
||||
|
@ -35,11 +38,8 @@ pub trait Delegate<'tcx> {
|
|||
/// The value found at `place` is moved, depending
|
||||
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
|
||||
///
|
||||
/// Use of a `Copy` type in a ByValue context is considered a use
|
||||
/// by `ImmBorrow` and `borrow` is called instead. This is because
|
||||
/// a shared borrow is the "minimum access" that would be needed
|
||||
/// to perform a copy.
|
||||
///
|
||||
/// If the value is `Copy`, [`copy`][Self::copy] is called instead, which
|
||||
/// by default falls back to [`borrow`][Self::borrow].
|
||||
///
|
||||
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
|
||||
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
|
||||
|
@ -73,6 +73,10 @@ pub trait Delegate<'tcx> {
|
|||
|
||||
/// The value found at `place` is being copied.
|
||||
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
///
|
||||
/// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead
|
||||
/// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared
|
||||
/// borrow is the "minimum access" that would be needed to perform a copy.
|
||||
fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||
// In most cases, copying data from `x` is equivalent to doing `*&x`, so by default
|
||||
// we treat a copy of `x` as a borrow of `x`.
|
||||
|
@ -141,6 +145,8 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
|
|||
}
|
||||
}
|
||||
|
||||
/// This trait makes `ExprUseVisitor` usable with both [`FnCtxt`]
|
||||
/// and [`LateContext`], depending on where in the compiler it is used.
|
||||
pub trait TypeInformationCtxt<'tcx> {
|
||||
type TypeckResults<'a>: Deref<Target = ty::TypeckResults<'tcx>>
|
||||
where
|
||||
|
@ -154,7 +160,7 @@ pub trait TypeInformationCtxt<'tcx> {
|
|||
|
||||
fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
|
||||
|
||||
fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error;
|
||||
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error;
|
||||
|
||||
fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>;
|
||||
|
||||
|
@ -189,7 +195,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
|
|||
(**self).try_structurally_resolve_type(sp, ty)
|
||||
}
|
||||
|
||||
fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error {
|
||||
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error {
|
||||
self.dcx().span_delayed_bug(span, msg.to_string())
|
||||
}
|
||||
|
||||
|
@ -239,7 +245,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
|
|||
t
|
||||
}
|
||||
|
||||
fn report_error(&self, span: Span, msg: impl ToString) -> ! {
|
||||
fn report_bug(&self, span: Span, msg: impl ToString) -> ! {
|
||||
span_bug!(span, "{}", msg.to_string())
|
||||
}
|
||||
|
||||
|
@ -268,9 +274,9 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
|
|||
}
|
||||
}
|
||||
|
||||
/// The ExprUseVisitor type
|
||||
/// A visitor that reports how each expression is being used.
|
||||
///
|
||||
/// This is the code that actually walks the tree.
|
||||
/// See [module-level docs][self] and [`Delegate`] for details.
|
||||
pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
|
||||
cx: Cx,
|
||||
/// We use a `RefCell` here so that delegates can mutate themselves, but we can
|
||||
|
@ -314,9 +320,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||
debug!("delegate_consume(place_with_id={:?})", place_with_id);
|
||||
|
||||
if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
|
||||
self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
|
||||
} else {
|
||||
|
@ -324,9 +329,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||
debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id);
|
||||
|
||||
// `x.use` will do one of the following
|
||||
// * if it implements `Copy`, it will be a copy
|
||||
// * if it implements `UseCloned`, it will be a call to `clone`
|
||||
|
@ -351,18 +355,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
|
||||
// FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||
debug!("consume_expr(expr={:?})", expr);
|
||||
|
||||
let place_with_id = self.cat_expr(expr)?;
|
||||
self.consume_or_copy(&place_with_id, place_with_id.hir_id);
|
||||
self.walk_expr(expr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||
debug!("consume_or_clone_expr(expr={:?})", expr);
|
||||
|
||||
let place_with_id = self.cat_expr(expr)?;
|
||||
self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
|
||||
self.walk_expr(expr)?;
|
||||
|
@ -376,17 +378,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> {
|
||||
debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
|
||||
|
||||
let place_with_id = self.cat_expr(expr)?;
|
||||
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
|
||||
self.walk_expr(expr)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||
debug!("walk_expr(expr={:?})", expr);
|
||||
|
||||
self.walk_adjustment(expr)?;
|
||||
|
||||
match expr.kind {
|
||||
|
@ -733,9 +733,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
|
||||
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
|
||||
/// depending on its type.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> {
|
||||
debug!("walk_block(blk.hir_id={})", blk.hir_id);
|
||||
|
||||
for stmt in blk.stmts {
|
||||
self.walk_stmt(stmt)?;
|
||||
}
|
||||
|
@ -861,7 +860,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
|
||||
/// Walks the autoref `autoref` applied to the autoderef'd
|
||||
/// `expr`. `base_place` is the mem-categorized form of `expr`
|
||||
/// `expr`. `base_place` is `expr` represented as a place,
|
||||
/// after all relevant autoderefs have occurred.
|
||||
fn walk_autoref(
|
||||
&self,
|
||||
|
@ -942,14 +941,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
|
||||
/// The core driver for walking a pattern
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn walk_pat(
|
||||
&self,
|
||||
discr_place: &PlaceWithHirId<'tcx>,
|
||||
pat: &hir::Pat<'_>,
|
||||
has_guard: bool,
|
||||
) -> Result<(), Cx::Error> {
|
||||
debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
|
||||
|
||||
let tcx = self.cx.tcx();
|
||||
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
|
||||
match pat.kind {
|
||||
|
@ -1042,6 +1040,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
///
|
||||
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
|
||||
/// closure as the DefId.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> {
|
||||
fn upvar_is_local_variable(
|
||||
upvars: Option<&FxIndexMap<HirId, hir::Upvar>>,
|
||||
|
@ -1051,8 +1050,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
|
||||
}
|
||||
|
||||
debug!("walk_captures({:?})", closure_expr);
|
||||
|
||||
let tcx = self.cx.tcx();
|
||||
let closure_def_id = closure_expr.def_id;
|
||||
// For purposes of this function, coroutine and closures are equivalent.
|
||||
|
@ -1164,55 +1161,17 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
/// The job of the categorization methods is to analyze an expression to
|
||||
/// determine what kind of memory is used in evaluating it (for example,
|
||||
/// where dereferences occur and what kind of pointer is dereferenced;
|
||||
/// whether the memory is mutable, etc.).
|
||||
/// The job of the methods whose name starts with `cat_` is to analyze
|
||||
/// expressions and construct the corresponding [`Place`]s. The `cat`
|
||||
/// stands for "categorize", this is a leftover from long ago when
|
||||
/// places were called "categorizations".
|
||||
///
|
||||
/// Categorization effectively transforms all of our expressions into
|
||||
/// expressions of the following forms (the actual enum has many more
|
||||
/// possibilities, naturally, but they are all variants of these base
|
||||
/// forms):
|
||||
/// ```ignore (not-rust)
|
||||
/// E = rvalue // some computed rvalue
|
||||
/// | x // address of a local variable or argument
|
||||
/// | *E // deref of a ptr
|
||||
/// | E.comp // access to an interior component
|
||||
/// ```
|
||||
/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
|
||||
/// address where the result is to be found. If Expr is a place, then this
|
||||
/// is the address of the place. If `Expr` is an rvalue, this is the address of
|
||||
/// some temporary spot in memory where the result is stored.
|
||||
///
|
||||
/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
|
||||
/// as follows:
|
||||
///
|
||||
/// - `cat`: what kind of expression was this? This is a subset of the
|
||||
/// full expression forms which only includes those that we care about
|
||||
/// for the purpose of the analysis.
|
||||
/// - `mutbl`: mutability of the address `A`.
|
||||
/// - `ty`: the type of data found at the address `A`.
|
||||
///
|
||||
/// The resulting categorization tree differs somewhat from the expressions
|
||||
/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
|
||||
/// decomposed into two operations: a dereference to reach the array data and
|
||||
/// then an index to jump forward to the relevant item.
|
||||
///
|
||||
/// ## By-reference upvars
|
||||
///
|
||||
/// One part of the codegen which may be non-obvious is that we translate
|
||||
/// closure upvars into the dereference of a borrowed pointer; this more closely
|
||||
/// resembles the runtime codegen. So, for example, if we had:
|
||||
///
|
||||
/// let mut x = 3;
|
||||
/// let y = 5;
|
||||
/// let inc = || x += y;
|
||||
///
|
||||
/// Then when we categorize `x` (*within* the closure) we would yield a
|
||||
/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
|
||||
/// tied to `x`. The type of `x'` will be a borrowed pointer.
|
||||
/// Note that a [`Place`] differs somewhat from the expression itself. For
|
||||
/// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into
|
||||
/// two operations: a dereference to reach the array data and then an index to
|
||||
/// jump forward to the relevant item.
|
||||
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
|
||||
fn resolve_type_vars_or_error(
|
||||
fn resolve_type_vars_or_bug(
|
||||
&self,
|
||||
id: HirId,
|
||||
ty: Option<Ty<'tcx>>,
|
||||
|
@ -1222,10 +1181,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
let ty = self.cx.resolve_vars_if_possible(ty);
|
||||
self.cx.error_reported_in_ty(ty)?;
|
||||
if ty.is_ty_var() {
|
||||
debug!("resolve_type_vars_or_error: infer var from {:?}", ty);
|
||||
debug!("resolve_type_vars_or_bug: infer var from {:?}", ty);
|
||||
Err(self
|
||||
.cx
|
||||
.report_error(self.cx.tcx().hir().span(id), "encountered type variable"))
|
||||
.report_bug(self.cx.tcx().hir().span(id), "encountered type variable"))
|
||||
} else {
|
||||
Ok(ty)
|
||||
}
|
||||
|
@ -1233,24 +1192,21 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
None => {
|
||||
// FIXME: We shouldn't be relying on the infcx being tainted.
|
||||
self.cx.tainted_by_errors()?;
|
||||
bug!(
|
||||
"no type for node {} in mem_categorization",
|
||||
self.cx.tcx().hir_id_to_string(id)
|
||||
);
|
||||
bug!("no type for node {} in ExprUseVisitor", self.cx.tcx().hir_id_to_string(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
|
||||
self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
|
||||
self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
|
||||
}
|
||||
|
||||
fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
|
||||
self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
|
||||
self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
|
||||
self.resolve_type_vars_or_error(
|
||||
self.resolve_type_vars_or_bug(
|
||||
expr.hir_id,
|
||||
self.cx.typeck_results().expr_ty_adjusted_opt(expr),
|
||||
)
|
||||
|
@ -1285,7 +1241,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.pat_ty_unadjusted(pat)
|
||||
}
|
||||
|
||||
/// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns.
|
||||
/// Like [`Self::pat_ty_adjusted`], but ignores implicit `&` patterns.
|
||||
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
|
||||
let base_ty = self.node_ty(pat.hir_id)?;
|
||||
trace!(?base_ty);
|
||||
|
@ -1315,7 +1271,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
debug!("By-ref binding of non-derefable type");
|
||||
Err(self
|
||||
.cx
|
||||
.report_error(pat.span, "by-ref binding of non-derefable type"))
|
||||
.report_bug(pat.span, "by-ref binding of non-derefable type"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1511,7 +1467,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def),
|
||||
def => span_bug!(span, "unexpected definition in ExprUseVisitor: {:?}", def),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1604,7 +1560,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
Some(ty) => ty,
|
||||
None => {
|
||||
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
|
||||
return Err(self.cx.report_error(
|
||||
return Err(self.cx.report_bug(
|
||||
self.cx.tcx().hir().span(node),
|
||||
"explicit deref of non-derefable type",
|
||||
));
|
||||
|
@ -1629,7 +1585,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
|
||||
return Err(self
|
||||
.cx
|
||||
.report_error(span, "struct or tuple struct pattern not applied to an ADT"));
|
||||
.report_bug(span, "struct or tuple struct pattern not applied to an ADT"));
|
||||
};
|
||||
|
||||
match res {
|
||||
|
@ -1675,7 +1631,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
let ty = self.cx.typeck_results().node_type(pat_hir_id);
|
||||
match self.cx.try_structurally_resolve_type(span, ty).kind() {
|
||||
ty::Tuple(args) => Ok(args.len()),
|
||||
_ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")),
|
||||
_ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1854,7 +1810,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
debug!("explicit index of non-indexable type {:?}", place_with_id);
|
||||
return Err(self
|
||||
.cx
|
||||
.report_error(pat.span, "explicit index of non-indexable type"));
|
||||
.report_bug(pat.span, "explicit index of non-indexable type"));
|
||||
};
|
||||
let elt_place = self.cat_projection(
|
||||
pat.hir_id,
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
//! from there).
|
||||
//!
|
||||
//! The fact that we are inferring borrow kinds as we go results in a
|
||||
//! semi-hacky interaction with mem-categorization. In particular,
|
||||
//! mem-categorization will query the current borrow kind as it
|
||||
//! categorizes, and we'll return the *current* value, but this may get
|
||||
//! semi-hacky interaction with the way `ExprUseVisitor` is computing
|
||||
//! `Place`s. In particular, it will query the current borrow kind as it
|
||||
//! goes, and we'll return the *current* value, but this may get
|
||||
//! adjusted later. Therefore, in this module, we generally ignore the
|
||||
//! borrow kind (and derived mutabilities) that are returned from
|
||||
//! mem-categorization, since they may be inaccurate. (Another option
|
||||
//! borrow kind (and derived mutabilities) that `ExprUseVisitor` returns
|
||||
//! within `Place`s, since they may be inaccurate. (Another option
|
||||
//! would be to use a unification scheme, where instead of returning a
|
||||
//! concrete borrow kind like `ty::ImmBorrow`, we return a
|
||||
//! `ty::InferBorrow(upvar_id)` or something like that, but this would
|
||||
|
|
|
@ -53,7 +53,10 @@ pub struct Projection<'tcx> {
|
|||
pub kind: ProjectionKind,
|
||||
}
|
||||
|
||||
/// A `Place` represents how a value is located in memory.
|
||||
/// A `Place` represents how a value is located in memory. This does not
|
||||
/// always correspond to a syntactic place expression. For example, when
|
||||
/// processing a pattern, a `Place` can be used to refer to the sub-value
|
||||
/// currently being inspected.
|
||||
///
|
||||
/// This is an HIR version of [`rustc_middle::mir::Place`].
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
|
||||
|
@ -67,7 +70,10 @@ pub struct Place<'tcx> {
|
|||
pub projections: Vec<Projection<'tcx>>,
|
||||
}
|
||||
|
||||
/// A `PlaceWithHirId` represents how a value is located in memory.
|
||||
/// A `PlaceWithHirId` represents how a value is located in memory. This does not
|
||||
/// always correspond to a syntactic place expression. For example, when
|
||||
/// processing a pattern, a `Place` can be used to refer to the sub-value
|
||||
/// currently being inspected.
|
||||
///
|
||||
/// This is an HIR version of [`rustc_middle::mir::Place`].
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
|
||||
|
|
|
@ -1496,7 +1496,7 @@ fn build_scope_drops<'tcx>(
|
|||
// path, then don't generate the drop. (We only take this into
|
||||
// account for non-unwind paths so as not to disturb the
|
||||
// caching mechanism.)
|
||||
if scope.moved_locals.iter().any(|&o| o == local) {
|
||||
if scope.moved_locals.contains(&local) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ struct EntryContext<'tcx> {
|
|||
}
|
||||
|
||||
fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
||||
let any_exe = tcx.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
||||
let any_exe = tcx.crate_types().contains(&CrateType::Executable);
|
||||
if !any_exe {
|
||||
// No need to find a main function.
|
||||
return None;
|
||||
|
|
|
@ -149,14 +149,15 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
|
|||
arg[a.len()..].to_string()
|
||||
};
|
||||
let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
|
||||
if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) {
|
||||
if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&option) {
|
||||
excluded_cargo_defaults = true;
|
||||
} else {
|
||||
result.push(a.to_string());
|
||||
match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
|
||||
Some(s) => result.push(format!("{s}=[REDACTED]")),
|
||||
None => result.push(content),
|
||||
}
|
||||
result.push(if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&option) {
|
||||
format!("{option}=[REDACTED]")
|
||||
} else {
|
||||
content
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -876,7 +876,7 @@ impl Span {
|
|||
self.ctxt()
|
||||
.outer_expn_data()
|
||||
.allow_internal_unstable
|
||||
.is_some_and(|features| features.iter().any(|&f| f == feature))
|
||||
.is_some_and(|features| features.contains(&feature))
|
||||
}
|
||||
|
||||
/// Checks if this span arises from a compiler desugaring of kind `kind`.
|
||||
|
|
|
@ -1057,8 +1057,7 @@ impl Place {
|
|||
/// In order to retrieve the correct type, the `locals` argument must match the list of all
|
||||
/// locals from the function body where this place originates from.
|
||||
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
|
||||
let start_ty = locals[self.local].ty;
|
||||
self.projection.iter().fold(Ok(start_ty), |place_ty, elem| elem.ty(place_ty?))
|
||||
self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -563,7 +563,7 @@ pub struct PlaceRef<'a> {
|
|||
impl PlaceRef<'_> {
|
||||
/// Get the type of this place.
|
||||
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
|
||||
self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?))
|
||||
self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,3 +47,14 @@ fn temp_lifetime() {
|
|||
}
|
||||
async fn foo(_: &mut usize) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transitive_extension() {
|
||||
async fn temporary() {}
|
||||
|
||||
// `pin!` witnessed in the wild being used like this, even if it yields
|
||||
// a `Pin<&mut &mut impl Unpin>`; it does work because `pin!`
|
||||
// happens to transitively extend the lifespan of `temporary()`.
|
||||
let p = pin!(&mut temporary());
|
||||
let _use = p;
|
||||
}
|
||||
|
|
|
@ -155,15 +155,15 @@ cfg_has_statx! {{
|
|||
enum STATX_STATE{ Unknown = 0, Present, Unavailable }
|
||||
static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8);
|
||||
|
||||
syscall! {
|
||||
syscall!(
|
||||
fn statx(
|
||||
fd: c_int,
|
||||
pathname: *const c_char,
|
||||
flags: c_int,
|
||||
mask: libc::c_uint,
|
||||
statxbuf: *mut libc::statx
|
||||
) -> c_int
|
||||
}
|
||||
statxbuf: *mut libc::statx,
|
||||
) -> c_int;
|
||||
);
|
||||
|
||||
let statx_availability = STATX_SAVED_STATE.load(Ordering::Relaxed);
|
||||
if statx_availability == STATX_STATE::Unavailable as u8 {
|
||||
|
@ -1540,7 +1540,9 @@ impl File {
|
|||
let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
|
||||
// futimens requires Android API level 19
|
||||
cvt(unsafe {
|
||||
weak!(fn futimens(c_int, *const libc::timespec) -> c_int);
|
||||
weak!(
|
||||
fn futimens(fd: c_int, times: *const libc::timespec) -> c_int;
|
||||
);
|
||||
match futimens.get() {
|
||||
Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()),
|
||||
None => return Err(io::const_error!(
|
||||
|
@ -1556,7 +1558,9 @@ impl File {
|
|||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(fn __futimens64(libc::c_int, *const __timespec64) -> libc::c_int);
|
||||
weak!(
|
||||
fn __futimens64(fd: c_int, times: *const __timespec64) -> c_int;
|
||||
);
|
||||
|
||||
if let Some(futimens64) = __futimens64.get() {
|
||||
let to_timespec = |time: Option<SystemTime>| time.map(|time| time.t.to_timespec64())
|
||||
|
|
|
@ -232,14 +232,14 @@ impl FileDesc {
|
|||
// implementation if `preadv` is not available.
|
||||
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
|
||||
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
|
||||
super::weak::syscall! {
|
||||
super::weak::syscall!(
|
||||
fn preadv(
|
||||
fd: libc::c_int,
|
||||
iovec: *const libc::iovec,
|
||||
n_iovec: libc::c_int,
|
||||
offset: off64_t
|
||||
) -> isize
|
||||
}
|
||||
offset: off64_t,
|
||||
) -> isize;
|
||||
);
|
||||
|
||||
let ret = cvt(unsafe {
|
||||
preadv(
|
||||
|
@ -257,7 +257,14 @@ impl FileDesc {
|
|||
// and its metadata from LLVM IR.
|
||||
#[no_sanitize(cfi)]
|
||||
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
|
||||
super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
|
||||
super::weak::weak!(
|
||||
fn preadv64(
|
||||
fd: libc::c_int,
|
||||
iovec: *const libc::iovec,
|
||||
n_iovec: libc::c_int,
|
||||
offset: off64_t,
|
||||
) -> isize;
|
||||
);
|
||||
|
||||
match preadv64.get() {
|
||||
Some(preadv) => {
|
||||
|
@ -286,7 +293,14 @@ impl FileDesc {
|
|||
// use "weak" linking.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
|
||||
super::weak::weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
|
||||
super::weak::weak!(
|
||||
fn preadv(
|
||||
fd: libc::c_int,
|
||||
iovec: *const libc::iovec,
|
||||
n_iovec: libc::c_int,
|
||||
offset: off64_t,
|
||||
) -> isize;
|
||||
);
|
||||
|
||||
match preadv.get() {
|
||||
Some(preadv) => {
|
||||
|
@ -428,14 +442,14 @@ impl FileDesc {
|
|||
// implementation if `pwritev` is not available.
|
||||
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
|
||||
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
|
||||
super::weak::syscall! {
|
||||
super::weak::syscall!(
|
||||
fn pwritev(
|
||||
fd: libc::c_int,
|
||||
iovec: *const libc::iovec,
|
||||
n_iovec: libc::c_int,
|
||||
offset: off64_t
|
||||
) -> isize
|
||||
}
|
||||
offset: off64_t,
|
||||
) -> isize;
|
||||
);
|
||||
|
||||
let ret = cvt(unsafe {
|
||||
pwritev(
|
||||
|
@ -450,7 +464,14 @@ impl FileDesc {
|
|||
|
||||
#[cfg(all(target_os = "android", target_pointer_width = "32"))]
|
||||
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
|
||||
super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
|
||||
super::weak::weak!(
|
||||
fn pwritev64(
|
||||
fd: libc::c_int,
|
||||
iovec: *const libc::iovec,
|
||||
n_iovec: libc::c_int,
|
||||
offset: off64_t,
|
||||
) -> isize;
|
||||
);
|
||||
|
||||
match pwritev64.get() {
|
||||
Some(pwritev) => {
|
||||
|
@ -479,7 +500,14 @@ impl FileDesc {
|
|||
// use "weak" linking.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
|
||||
super::weak::weak!(fn pwritev(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
|
||||
super::weak::weak!(
|
||||
fn pwritev(
|
||||
fd: libc::c_int,
|
||||
iovec: *const libc::iovec,
|
||||
n_iovec: libc::c_int,
|
||||
offset: off64_t,
|
||||
) -> isize;
|
||||
);
|
||||
|
||||
match pwritev.get() {
|
||||
Some(pwritev) => {
|
||||
|
|
|
@ -604,16 +604,16 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
|
|||
_ => true,
|
||||
};
|
||||
|
||||
syscall! {
|
||||
syscall!(
|
||||
fn copy_file_range(
|
||||
fd_in: libc::c_int,
|
||||
off_in: *mut libc::loff_t,
|
||||
fd_out: libc::c_int,
|
||||
off_out: *mut libc::loff_t,
|
||||
len: libc::size_t,
|
||||
flags: libc::c_uint
|
||||
) -> libc::ssize_t
|
||||
}
|
||||
flags: libc::c_uint,
|
||||
) -> libc::ssize_t;
|
||||
);
|
||||
|
||||
fn probe_copy_file_range_support() -> u8 {
|
||||
// In some cases, we cannot determine availability from the first
|
||||
|
@ -727,16 +727,16 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
|
|||
// Android builds use feature level 14, but the libc wrapper for splice is
|
||||
// gated on feature level 21+, so we have to invoke the syscall directly.
|
||||
#[cfg(target_os = "android")]
|
||||
syscall! {
|
||||
syscall!(
|
||||
fn splice(
|
||||
srcfd: libc::c_int,
|
||||
src_offset: *const i64,
|
||||
dstfd: libc::c_int,
|
||||
dst_offset: *const i64,
|
||||
len: libc::size_t,
|
||||
flags: libc::c_int
|
||||
) -> libc::ssize_t
|
||||
}
|
||||
flags: libc::c_int,
|
||||
) -> libc::ssize_t;
|
||||
);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use libc::splice;
|
||||
|
|
|
@ -424,18 +424,32 @@ mod imp {
|
|||
|
||||
let pages = PAGES.get_or_init(|| {
|
||||
use crate::sys::weak::dlsym;
|
||||
dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
|
||||
dlsym!(
|
||||
fn sysctlbyname(
|
||||
name: *const libc::c_char,
|
||||
oldp: *mut libc::c_void,
|
||||
oldlenp: *mut libc::size_t,
|
||||
newp: *const libc::c_void,
|
||||
newlen: libc::size_t,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
let mut guard: usize = 0;
|
||||
let mut size = size_of_val(&guard);
|
||||
let oid = c"security.bsd.stack_guard_page";
|
||||
match sysctlbyname.get() {
|
||||
Some(fcn) if unsafe {
|
||||
fcn(oid.as_ptr(),
|
||||
Some(fcn)
|
||||
if unsafe {
|
||||
fcn(
|
||||
oid.as_ptr(),
|
||||
(&raw mut guard).cast(),
|
||||
&raw mut size,
|
||||
ptr::null_mut(),
|
||||
0) == 0
|
||||
} => guard,
|
||||
0,
|
||||
) == 0
|
||||
} =>
|
||||
{
|
||||
guard
|
||||
}
|
||||
_ => 1,
|
||||
}
|
||||
});
|
||||
|
|
|
@ -193,11 +193,12 @@ impl Thread {
|
|||
// and its metadata from LLVM IR.
|
||||
#[no_sanitize(cfi)]
|
||||
pub fn set_name(name: &CStr) {
|
||||
weak! {
|
||||
weak!(
|
||||
fn pthread_setname_np(
|
||||
libc::pthread_t, *const libc::c_char
|
||||
) -> libc::c_int
|
||||
}
|
||||
thread: libc::pthread_t,
|
||||
name: *const libc::c_char,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
|
||||
if let Some(f) = pthread_setname_np.get() {
|
||||
#[cfg(target_os = "nto")]
|
||||
|
@ -762,7 +763,9 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
|
|||
// We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628)
|
||||
// We shouldn't really be using such an internal symbol, but there's currently
|
||||
// no other way to account for the TLS size.
|
||||
dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
|
||||
dlsym!(
|
||||
fn __pthread_get_minstack(attr: *const libc::pthread_attr_t) -> libc::size_t;
|
||||
);
|
||||
|
||||
match __pthread_get_minstack.get() {
|
||||
None => libc::PTHREAD_STACK_MIN,
|
||||
|
|
|
@ -123,7 +123,12 @@ impl Timespec {
|
|||
|
||||
// __clock_gettime64 was added to 32-bit arches in glibc 2.34,
|
||||
// and it handles both vDSO calls and ENOSYS fallbacks itself.
|
||||
weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
|
||||
weak!(
|
||||
fn __clock_gettime64(
|
||||
clockid: libc::clockid_t,
|
||||
tp: *mut __timespec64,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
|
||||
if let Some(clock_gettime64) = __clock_gettime64.get() {
|
||||
let mut t = MaybeUninit::uninit();
|
||||
|
|
|
@ -29,7 +29,7 @@ use crate::{mem, ptr};
|
|||
// We can use true weak linkage on ELF targets.
|
||||
#[cfg(all(unix, not(target_vendor = "apple")))]
|
||||
pub(crate) macro weak {
|
||||
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
|
||||
(fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
|
||||
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
|
||||
unsafe extern "C" {
|
||||
#[linkage = "extern_weak"]
|
||||
|
@ -62,10 +62,16 @@ impl<F: Copy> ExternWeak<F> {
|
|||
}
|
||||
|
||||
pub(crate) macro dlsym {
|
||||
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
|
||||
dlsym!(fn $name($($t),*) -> $ret, stringify!($name));
|
||||
(fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
|
||||
dlsym!(
|
||||
#[link_name = stringify!($name)]
|
||||
fn $name($($param : $t),*) -> $ret;
|
||||
);
|
||||
),
|
||||
(fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => (
|
||||
(
|
||||
#[link_name = $sym:expr]
|
||||
fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
|
||||
) => (
|
||||
static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
|
||||
DlsymWeak::new(concat!($sym, '\0'));
|
||||
let $name = &DLSYM;
|
||||
|
@ -143,15 +149,15 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void {
|
|||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub(crate) macro syscall {
|
||||
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
|
||||
(fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
|
||||
// FIXME(#115199): Rust currently omits weak function definitions
|
||||
// and its metadata from LLVM IR.
|
||||
#[no_sanitize(cfi)]
|
||||
unsafe fn $name($($arg_name: $t),*) -> $ret {
|
||||
weak! { fn $name($($t),*) -> $ret }
|
||||
unsafe fn $name($($param: $t),*) -> $ret {
|
||||
weak!(fn $name($($param: $t),*) -> $ret;);
|
||||
|
||||
if let Some(fun) = $name.get() {
|
||||
fun($($arg_name),*)
|
||||
fun($($param),*)
|
||||
} else {
|
||||
super::os::set_errno(libc::ENOSYS);
|
||||
-1
|
||||
|
@ -162,16 +168,18 @@ pub(crate) macro syscall {
|
|||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub(crate) macro syscall {
|
||||
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
|
||||
unsafe fn $name($($arg_name:$t),*) -> $ret {
|
||||
weak! { fn $name($($t),*) -> $ret }
|
||||
(
|
||||
fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
|
||||
) => (
|
||||
unsafe fn $name($($param: $t),*) -> $ret {
|
||||
weak!(fn $name($($param: $t),*) -> $ret;);
|
||||
|
||||
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
|
||||
// interposition, but if it's not found just use a raw syscall.
|
||||
if let Some(fun) = $name.get() {
|
||||
fun($($arg_name),*)
|
||||
fun($($param),*)
|
||||
} else {
|
||||
libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret
|
||||
libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -179,9 +187,9 @@ pub(crate) macro syscall {
|
|||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub(crate) macro raw_syscall {
|
||||
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
|
||||
unsafe fn $name($($arg_name:$t),*) -> $ret {
|
||||
libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret
|
||||
(fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
|
||||
unsafe fn $name($($param: $t),*) -> $ret {
|
||||
libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ cfg_if::cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::time::Duration;
|
|||
|
||||
pub struct Thread(!);
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
|
|
|
@ -461,18 +461,20 @@ impl Command {
|
|||
if #[cfg(target_os = "linux")] {
|
||||
use crate::sys::weak::weak;
|
||||
|
||||
weak! {
|
||||
weak!(
|
||||
fn pidfd_spawnp(
|
||||
*mut libc::c_int,
|
||||
*const libc::c_char,
|
||||
*const libc::posix_spawn_file_actions_t,
|
||||
*const libc::posix_spawnattr_t,
|
||||
*const *mut libc::c_char,
|
||||
*const *mut libc::c_char
|
||||
) -> libc::c_int
|
||||
}
|
||||
pidfd: *mut libc::c_int,
|
||||
path: *const libc::c_char,
|
||||
file_actions: *const libc::posix_spawn_file_actions_t,
|
||||
attrp: *const libc::posix_spawnattr_t,
|
||||
argv: *const *mut libc::c_char,
|
||||
envp: *const *mut libc::c_char,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
|
||||
weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int }
|
||||
weak!(
|
||||
fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int;
|
||||
);
|
||||
|
||||
static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
|
||||
const UNKNOWN: u8 = 0;
|
||||
|
@ -593,19 +595,19 @@ impl Command {
|
|||
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html.
|
||||
// The _np version is more widely available, though, so try that first.
|
||||
|
||||
weak! {
|
||||
weak!(
|
||||
fn posix_spawn_file_actions_addchdir_np(
|
||||
*mut libc::posix_spawn_file_actions_t,
|
||||
*const libc::c_char
|
||||
) -> libc::c_int
|
||||
}
|
||||
file_actions: *mut libc::posix_spawn_file_actions_t,
|
||||
path: *const libc::c_char,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
|
||||
weak! {
|
||||
weak!(
|
||||
fn posix_spawn_file_actions_addchdir(
|
||||
*mut libc::posix_spawn_file_actions_t,
|
||||
*const libc::c_char
|
||||
) -> libc::c_int
|
||||
}
|
||||
file_actions: *mut libc::posix_spawn_file_actions_t,
|
||||
path: *const libc::c_char,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
|
||||
posix_spawn_file_actions_addchdir_np
|
||||
.get()
|
||||
|
|
|
@ -73,13 +73,13 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) {
|
|||
// A weak symbol allows interposition, e.g. for perf measurements that want to
|
||||
// disable randomness for consistency. Otherwise, we'll try a raw syscall.
|
||||
// (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
|
||||
syscall! {
|
||||
syscall!(
|
||||
fn getrandom(
|
||||
buffer: *mut libc::c_void,
|
||||
length: libc::size_t,
|
||||
flags: libc::c_uint
|
||||
) -> libc::ssize_t
|
||||
}
|
||||
flags: libc::c_uint,
|
||||
) -> libc::ssize_t;
|
||||
);
|
||||
|
||||
static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true);
|
||||
static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true);
|
||||
|
|
|
@ -924,7 +924,14 @@ fn iter_header(
|
|||
|
||||
impl Config {
|
||||
fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec<String>) {
|
||||
const FORBIDDEN_REVISION_NAMES: [&str; 9] =
|
||||
const FORBIDDEN_REVISION_NAMES: [&str; 2] = [
|
||||
// `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very
|
||||
// weird for the test, since if the test writer wants a cfg of the same revision name
|
||||
// they'd have to use `cfg(r#true)` and `cfg(r#false)`.
|
||||
"true", "false",
|
||||
];
|
||||
|
||||
const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] =
|
||||
["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
|
||||
|
||||
if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
|
||||
|
@ -933,25 +940,38 @@ impl Config {
|
|||
}
|
||||
|
||||
let mut duplicates: HashSet<_> = existing.iter().cloned().collect();
|
||||
for revision in raw.split_whitespace().map(|r| r.to_string()) {
|
||||
if !duplicates.insert(revision.clone()) {
|
||||
for revision in raw.split_whitespace() {
|
||||
if !duplicates.insert(revision.to_string()) {
|
||||
panic!(
|
||||
"duplicate revision: `{}` in line `{}`: {}",
|
||||
revision,
|
||||
raw,
|
||||
testfile.display()
|
||||
);
|
||||
} else if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt)
|
||||
&& FORBIDDEN_REVISION_NAMES.contains(&revision.as_str())
|
||||
{
|
||||
}
|
||||
|
||||
if FORBIDDEN_REVISION_NAMES.contains(&revision) {
|
||||
panic!(
|
||||
"revision name `{revision}` is not permitted in a test suite that uses `FileCheck` annotations\n\
|
||||
as it is confusing when used as custom `FileCheck` prefix: `{revision}` in line `{}`: {}",
|
||||
"revision name `{revision}` is not permitted: `{}` in line `{}`: {}",
|
||||
revision,
|
||||
raw,
|
||||
testfile.display()
|
||||
);
|
||||
}
|
||||
existing.push(revision);
|
||||
|
||||
if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt)
|
||||
&& FILECHECK_FORBIDDEN_REVISION_NAMES.contains(&revision)
|
||||
{
|
||||
panic!(
|
||||
"revision name `{revision}` is not permitted in a test suite that uses \
|
||||
`FileCheck` annotations as it is confusing when used as custom `FileCheck` \
|
||||
prefix: `{revision}` in line `{}`: {}",
|
||||
raw,
|
||||
testfile.display()
|
||||
);
|
||||
}
|
||||
|
||||
existing.push(revision.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -567,6 +567,13 @@ fn test_assembly_mode_forbidden_revisions() {
|
|||
parse_rs(&config, "//@ revisions: CHECK");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "revision name `true` is not permitted")]
|
||||
fn test_forbidden_revisions() {
|
||||
let config = cfg().mode("ui").build();
|
||||
parse_rs(&config, "//@ revisions: true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "revision name `CHECK` is not permitted in a test suite that uses `FileCheck` annotations"
|
||||
|
|
26
tests/ui/pin-macro/pin_move.rs
Normal file
26
tests/ui/pin-macro/pin_move.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
//@ edition:2024
|
||||
|
||||
use core::marker::PhantomPinned;
|
||||
use core::pin::pin;
|
||||
|
||||
fn a() {
|
||||
struct NotCopy<T>(T);
|
||||
#[allow(unused_mut)]
|
||||
let mut pointee = NotCopy(PhantomPinned);
|
||||
pin!(pointee);
|
||||
let _moved = pointee;
|
||||
//~^ ERROR use of moved value
|
||||
}
|
||||
|
||||
fn b() {
|
||||
struct NotCopy<T>(T);
|
||||
let mut pointee = NotCopy(PhantomPinned);
|
||||
pin!(*&mut pointee);
|
||||
//~^ ERROR cannot move
|
||||
let _moved = pointee;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a();
|
||||
b();
|
||||
}
|
38
tests/ui/pin-macro/pin_move.stderr
Normal file
38
tests/ui/pin-macro/pin_move.stderr
Normal file
|
@ -0,0 +1,38 @@
|
|||
error[E0382]: use of moved value: `pointee`
|
||||
--> $DIR/pin_move.rs:11:18
|
||||
|
|
||||
LL | let mut pointee = NotCopy(PhantomPinned);
|
||||
| ----------- move occurs because `pointee` has type `a::NotCopy<PhantomPinned>`, which does not implement the `Copy` trait
|
||||
LL | pin!(pointee);
|
||||
| ------- value moved here
|
||||
LL | let _moved = pointee;
|
||||
| ^^^^^^^ value used here after move
|
||||
|
|
||||
note: if `a::NotCopy<PhantomPinned>` implemented `Clone`, you could clone the value
|
||||
--> $DIR/pin_move.rs:7:5
|
||||
|
|
||||
LL | struct NotCopy<T>(T);
|
||||
| ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
|
||||
...
|
||||
LL | pin!(pointee);
|
||||
| ------- you could clone this value
|
||||
|
||||
error[E0507]: cannot move out of a mutable reference
|
||||
--> $DIR/pin_move.rs:18:10
|
||||
|
|
||||
LL | pin!(*&mut pointee);
|
||||
| ^^^^^^^^^^^^^ move occurs because value has type `b::NotCopy<PhantomPinned>`, which does not implement the `Copy` trait
|
||||
|
|
||||
note: if `b::NotCopy<PhantomPinned>` implemented `Clone`, you could clone the value
|
||||
--> $DIR/pin_move.rs:16:5
|
||||
|
|
||||
LL | struct NotCopy<T>(T);
|
||||
| ^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
|
||||
LL | let mut pointee = NotCopy(PhantomPinned);
|
||||
LL | pin!(*&mut pointee);
|
||||
| ------------- you could clone this value
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0382, E0507.
|
||||
For more information about an error, try `rustc --explain E0382`.
|
Loading…
Add table
Add a link
Reference in a new issue