Auto merge of #145599 - jieyouxu:rollup-523cxhm, r=jieyouxu

Rollup of 15 pull requests

Successful merges:

 - rust-lang/rust#139345 (Extend `QueryStability` to handle `IntoIterator` implementations)
 - rust-lang/rust#140740 (Add `-Zindirect-branch-cs-prefix`)
 - rust-lang/rust#142079 (nll-relate: improve hr opaque types support)
 - rust-lang/rust#142938 (implement std::fs::set_permissions_nofollow on unix)
 - rust-lang/rust#143730 (fmt of non-decimal radix untangled)
 - rust-lang/rust#144767 (Correct some grammar in integer documentation)
 - rust-lang/rust#144906 (Require approval from t-infra instead of t-release on tier bumps)
 - rust-lang/rust#144983 (Rehome 37 `tests/ui/issues/` tests to other subdirectories under `tests/ui/`)
 - rust-lang/rust#145025 (run spellcheck as a tidy extra check in ci)
 - rust-lang/rust#145099 (rustc_target: Add the `32s` target feature for LoongArch)
 - rust-lang/rust#145166 (suggest using `pub(crate)` for E0364)
 - rust-lang/rust#145255 (dec2flt: Provide more valid inputs examples)
 - rust-lang/rust#145306 (Add tracing to various miscellaneous functions)
 - rust-lang/rust#145336 (Hide docs for `core::unicode`)
 - rust-lang/rust#145585 (Miri: fix handling of in-place argument and return place handling)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2025-08-19 14:43:48 +00:00
163 changed files with 1128 additions and 557 deletions

View File

@@ -124,8 +124,13 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
// by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
// the opaque.
let mut enable_subtyping = |ty, opaque_is_expected| {
let ty_vid = infcx.next_ty_var_id_in_universe(self.span(), ty::UniverseIndex::ROOT);
// We create the fresh inference variable in the highest universe.
// In theory we could limit it to the highest universe in the args of
// the opaque but that isn't really worth the effort.
//
// We'll make sure that the opaque type can actually name everything
// in its hidden type later on.
let ty_vid = infcx.next_ty_vid(self.span());
let variance = if opaque_is_expected {
self.ambient_variance
} else {

View File

@@ -471,6 +471,15 @@ pub(crate) unsafe fn create_module<'ll>(
}
}
if sess.opts.unstable_opts.indirect_branch_cs_prefix {
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"indirect_branch_cs_prefix",
1,
);
}
match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support())
{
// Set up the small-data optimization limit for architectures that use

View File

@@ -277,6 +277,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
{
None
}
("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None,
// Filter out features that are not supported by the current LLVM version
("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None,
(

View File

@@ -180,6 +180,7 @@ fn parse_rust_feature_flag<'a>(
while let Some(new_feature) = new_features.pop() {
if features.insert(new_feature) {
if let Some(implied_features) = inverse_implied_features.get(&new_feature) {
#[allow(rustc::potential_query_instability)]
new_features.extend(implied_features)
}
}

View File

@@ -27,8 +27,9 @@ use crate::{enter_trace_span, fluent_generated as fluent};
pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
/// Pass a copy of the given operand.
Copy(OpTy<'tcx, Prov>),
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
/// make the place inaccessible for the duration of the function call.
/// Allow for the argument to be passed in-place: destroy the value originally stored at that
/// place and make the place inaccessible for the duration of the function call. This *must* be
/// an in-memory place so that we can do the proper alias checks.
InPlace(MPlaceTy<'tcx, Prov>),
}
@@ -379,6 +380,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}
// *Before* pushing the new frame, determine whether the return destination is in memory.
// Need to use `place_to_op` to be *sure* we get the mplace if there is one.
let destination_mplace = self.place_to_op(destination)?.as_mplace_or_imm().left();
// Push the "raw" frame -- this leaves locals uninitialized.
self.push_stack_frame_raw(instance, body, destination, cont)?;
// If an error is raised here, pop the frame again to get an accurate backtrace.
@@ -496,7 +502,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Protect return place for in-place return value passing.
// We only need to protect anything if this is actually an in-memory place.
if let Left(mplace) = destination.as_mplace_or_local() {
if let Some(mplace) = destination_mplace {
M::protect_in_place_function_argument(self, &mplace)?;
}

View File

@@ -325,8 +325,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let _trace = enter_trace_span!(
M,
"instantiate_from_frame_and_normalize_erasing_regions",
"{}",
frame.instance
%frame.instance
);
frame
.instance
@@ -583,6 +582,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
span: Span,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let _trace = enter_trace_span!(M, const_eval::eval_mir_constant, ?val);
let const_val = val.eval(*self.tcx, self.typing_env, span).map_err(|err| {
if M::ALL_CONSTS_ARE_PRECHECKED {
match err {

View File

@@ -234,6 +234,12 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> {
}
/// A place is either an mplace or some local.
///
/// Note that the return value can be different even for logically identical places!
/// Specifically, if a local is stored in-memory, this may return `Local` or `MPlaceTy`
/// depending on how the place was constructed. In other words, seeing `Local` here does *not*
/// imply that this place does not point to memory. Every caller must therefore always handle
/// both cases.
#[inline(always)]
pub fn as_mplace_or_local(
&self,

View File

@@ -20,7 +20,7 @@ use super::{
MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar, from_known_layout,
interp_ok, throw_ub, throw_unsup,
};
use crate::errors;
use crate::{enter_trace_span, errors};
// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
// boundary and dropped in the other thread, it would exit the span in the other thread.
@@ -386,6 +386,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
for &const_ in body.required_consts() {
// We can't use `eval_mir_constant` here as that assumes that all required consts have
// already been checked, so we need a separate tracing call.
let _trace = enter_trace_span!(M, const_eval::required_consts, ?const_.const_);
let c =
self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| {

View File

@@ -4,6 +4,7 @@
use either::Either;
use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_data_structures::fx::FxHashSet;
use rustc_index::IndexSlice;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, mir, span_bug};
@@ -389,8 +390,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Evaluate the arguments of a function call
fn eval_fn_call_argument(
&self,
&mut self,
op: &mir::Operand<'tcx>,
move_definitely_disjoint: bool,
) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
interp_ok(match op {
mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
@@ -399,24 +401,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
FnArg::Copy(op)
}
mir::Operand::Move(place) => {
// If this place lives in memory, preserve its location.
// We call `place_to_op` which will be an `MPlaceTy` whenever there exists
// an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
// which can return a local even if that has an mplace.)
let place = self.eval_place(*place)?;
let op = self.place_to_op(&place)?;
match op.as_mplace_or_imm() {
Either::Left(mplace) => FnArg::InPlace(mplace),
Either::Right(_imm) => {
// This argument doesn't live in memory, so there's no place
// to make inaccessible during the call.
// We rely on there not being any stray `PlaceTy` that would let the
// caller directly access this local!
// This is also crucial for tail calls, where we want the `FnArg` to
// stay valid when the old stack frame gets popped.
FnArg::Copy(op)
if move_definitely_disjoint {
// We still have to ensure that no *other* pointers are used to access this place,
// so *if* it is in memory then we have to treat it as `InPlace`.
// Use `place_to_op` to guarantee that we notice it being in memory.
let op = self.place_to_op(&place)?;
match op.as_mplace_or_imm() {
Either::Left(mplace) => FnArg::InPlace(mplace),
Either::Right(_imm) => FnArg::Copy(op),
}
} else {
// We have to force this into memory to detect aliasing among `Move` arguments.
FnArg::InPlace(self.force_allocation(&place)?)
}
}
})
@@ -425,18 +422,46 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
/// necessary information about callee and arguments to make a call.
fn eval_callee_and_args(
&self,
&mut self,
terminator: &mir::Terminator<'tcx>,
func: &mir::Operand<'tcx>,
args: &[Spanned<mir::Operand<'tcx>>],
) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
let func = self.eval_operand(func, None)?;
// Evaluating function call arguments. The tricky part here is dealing with `Move`
// arguments: we have to ensure no two such arguments alias. This would be most easily done
// by just forcing them all into memory and then doing the usual in-place argument
// protection, but then we'd force *a lot* of arguments into memory. So we do some syntactic
// pre-processing here where if all `move` arguments are syntactically distinct local
// variables (and none is indirect), we can skip the in-memory forcing.
let move_definitely_disjoint = 'move_definitely_disjoint: {
let mut previous_locals = FxHashSet::<mir::Local>::default();
for arg in args {
let mir::Operand::Move(place) = arg.node else {
continue; // we can skip non-`Move` arguments.
};
if place.is_indirect_first_projection() {
// An indirect `Move` argument could alias with anything else...
break 'move_definitely_disjoint false;
}
if !previous_locals.insert(place.local) {
// This local is the base for two arguments! They might overlap.
break 'move_definitely_disjoint false;
}
}
// We found no violation so they are all definitely disjoint.
true
};
let args = args
.iter()
.map(|arg| self.eval_fn_call_argument(&arg.node))
.map(|arg| self.eval_fn_call_argument(&arg.node, move_definitely_disjoint))
.collect::<InterpResult<'tcx, Vec<_>>>()?;
let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
let fn_sig_binder = {
let _trace = enter_trace_span!(M, "fn_sig", ty = ?func.layout.ty.kind());
func.layout.ty.fn_sig(*self.tcx)
};
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, fn_sig_binder);
let extra_args = &args[fn_sig.inputs().len()..];
let extra_args =

View File

@@ -1418,7 +1418,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let _trace = enter_trace_span!(
M,
"validate_operand",
"recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}"
recursive,
reset_provenance_and_padding,
?val,
);
// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's

View File

@@ -17,7 +17,7 @@ use std::path::Path;
use std::sync::Arc;
use derive_setters::Setters;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
use rustc_error_messages::{FluentArgs, SpanLabel};
use rustc_lexer;
@@ -1853,7 +1853,7 @@ impl HumanEmitter {
&& line_idx + 1 == annotated_file.lines.len(),
);
let mut to_add = FxHashMap::default();
let mut to_add = FxIndexMap::default();
for (depth, style) in depths {
// FIXME(#120456) - is `swap_remove` correct?

View File

@@ -596,6 +596,7 @@ pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>(
match result {
Success(body_named_matches) => {
psess.gated_spans.merge(gated_spans_snapshot);
#[allow(rustc::potential_query_instability)]
named_matches.extend(body_named_matches);
return Ok((i, rule, named_matches));
}

View File

@@ -782,22 +782,30 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().num_vars()
}
pub fn next_ty_vid(&self, span: Span) -> TyVid {
self.next_ty_vid_with_origin(TypeVariableOrigin { span, param_def_id: None })
}
pub fn next_ty_vid_with_origin(&self, origin: TypeVariableOrigin) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
}
pub fn next_ty_vid_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
let origin = TypeVariableOrigin { span, param_def_id: None };
self.inner.borrow_mut().type_variables().new_var(universe, origin)
}
pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
}
pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
let vid = self.next_ty_vid_with_origin(origin);
Ty::new_var(self.tcx, vid)
}
pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
let origin = TypeVariableOrigin { span, param_def_id: None };
self.inner.borrow_mut().type_variables().new_var(universe, origin)
}
pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> {
let vid = self.next_ty_var_id_in_universe(span, universe);
let vid = self.next_ty_vid_in_universe(span, universe);
Ty::new_var(self.tcx, vid)
}

View File

@@ -285,7 +285,9 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
.expecteds
.entry(name.name)
.and_modify(|v| match v {
ExpectedValues::Some(v) if !values_any_specified => {
ExpectedValues::Some(v) if !values_any_specified =>
{
#[allow(rustc::potential_query_instability)]
v.extend(values.clone())
}
ExpectedValues::Some(_) => *v = ExpectedValues::Any,

View File

@@ -807,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(hint_mostly_unused, true);
tracked!(human_readable_cgu_names, true);
tracked!(incremental_ignore_spans, true);
tracked!(indirect_branch_cs_prefix, true);
tracked!(inline_mir, Some(true));
tracked!(inline_mir_hint_threshold, Some(123));
tracked!(inline_mir_threshold, Some(123));

View File

@@ -1,10 +1,10 @@
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
//! Clippy.
use rustc_hir::HirId;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
use rustc_hir::{Expr, ExprKind, HirId};
use rustc_middle::ty::{self, ClauseKind, GenericArgsRef, PredicatePolarity, TraitPredicate, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::{Span, sym};
@@ -56,25 +56,6 @@ impl LateLintPass<'_> for DefaultHashTypes {
}
}
/// Helper function for lints that check for expressions with calls and use typeck results to
/// get the `DefId` and `GenericArgsRef` of the function.
fn typeck_results_of_method_fn<'tcx>(
cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>,
) -> Option<(Span, DefId, ty::GenericArgsRef<'tcx>)> {
match expr.kind {
hir::ExprKind::MethodCall(segment, ..)
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
{
Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id)))
}
_ => match cx.typeck_results().node_type(expr.hir_id).kind() {
&ty::FnDef(def_id, args) => Some((expr.span, def_id, args)),
_ => None,
},
}
}
declare_tool_lint! {
/// The `potential_query_instability` lint detects use of methods which can lead to
/// potential query instability, such as iterating over a `HashMap`.
@@ -101,10 +82,12 @@ declare_tool_lint! {
declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]);
impl LateLintPass<'_> for QueryStability {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args)
impl<'tcx> LateLintPass<'tcx> for QueryStability {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let Some((callee_def_id, span, generic_args, _recv, _args)) =
get_callee_span_generic_args_and_args(cx, expr)
&& let Ok(Some(instance)) =
ty::Instance::try_resolve(cx.tcx, cx.typing_env(), callee_def_id, generic_args)
{
let def_id = instance.def_id();
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
@@ -113,7 +96,15 @@ impl LateLintPass<'_> for QueryStability {
span,
QueryInstability { query: cx.tcx.item_name(def_id) },
);
} else if has_unstable_into_iter_predicate(cx, callee_def_id, generic_args) {
let call_span = span.with_hi(expr.span.hi());
cx.emit_span_lint(
POTENTIAL_QUERY_INSTABILITY,
call_span,
QueryInstability { query: sym::into_iter },
);
}
if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) {
cx.emit_span_lint(
UNTRACKED_QUERY_INFORMATION,
@@ -125,6 +116,64 @@ impl LateLintPass<'_> for QueryStability {
}
}
fn has_unstable_into_iter_predicate<'tcx>(
cx: &LateContext<'tcx>,
callee_def_id: DefId,
generic_args: GenericArgsRef<'tcx>,
) -> bool {
let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else {
return false;
};
let Some(into_iter_fn_def_id) = cx.tcx.lang_items().into_iter_fn() else {
return false;
};
let predicates = cx.tcx.predicates_of(callee_def_id).instantiate(cx.tcx, generic_args);
for (predicate, _) in predicates {
let ClauseKind::Trait(TraitPredicate { trait_ref, polarity: PredicatePolarity::Positive }) =
predicate.kind().skip_binder()
else {
continue;
};
// Does the function or method require any of its arguments to implement `IntoIterator`?
if trait_ref.def_id != into_iterator_def_id {
continue;
}
let Ok(Some(instance)) =
ty::Instance::try_resolve(cx.tcx, cx.typing_env(), into_iter_fn_def_id, trait_ref.args)
else {
continue;
};
// Does the input type's `IntoIterator` implementation have the
// `rustc_lint_query_instability` attribute on its `into_iter` method?
if cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_query_instability) {
return true;
}
}
false
}
/// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
/// `Span`, `GenericArgs`, and arguments. This is a slight augmentation of a similarly named Clippy
/// function, `get_callee_generic_args_and_args`.
fn get_callee_span_generic_args_and_args<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
) -> Option<(DefId, Span, GenericArgsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
if let ExprKind::Call(callee, args) = expr.kind
&& let callee_ty = cx.typeck_results().expr_ty(callee)
&& let ty::FnDef(callee_def_id, generic_args) = callee_ty.kind()
{
return Some((*callee_def_id, callee.span, generic_args, None, args));
}
if let ExprKind::MethodCall(segment, recv, args, _) = expr.kind
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
{
let generic_args = cx.typeck_results().node_args(expr.hir_id);
return Some((method_def_id, segment.ident.span, generic_args, Some(recv), args));
}
None
}
declare_tool_lint! {
/// The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::<kind>`,
/// where `ty::<kind>` would suffice.
@@ -461,33 +510,22 @@ declare_tool_lint! {
declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);
impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| {
let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra));
result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span)));
result
};
// Only check function calls and method calls.
let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind {
hir::ExprKind::Call(callee, args) => {
match cx.typeck_results().node_type(callee.hir_id).kind() {
&ty::FnDef(def_id, fn_gen_args) => {
(callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false))
}
_ => return, // occurs for fns passed as args
}
}
hir::ExprKind::MethodCall(_segment, _recv, args, _span) => {
let Some((span, def_id, fn_gen_args)) = typeck_results_of_method_fn(cx, expr)
else {
return;
};
let mut args = collect_args_tys_and_spans(args, true);
args.insert(0, (cx.tcx.types.self_param, _recv.span)); // dummy inserted for `self`
(span, def_id, fn_gen_args, args)
}
_ => return,
let Some((def_id, span, fn_gen_args, recv, args)) =
get_callee_span_generic_args_and_args(cx, expr)
else {
return;
};
let mut arg_tys_and_spans = collect_args_tys_and_spans(args, recv.is_some());
if let Some(recv) = recv {
arg_tys_and_spans.insert(0, (cx.tcx.types.self_param, recv.span)); // dummy inserted for `self`
}
Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args);
Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans);
@@ -496,7 +534,7 @@ impl LateLintPass<'_> for Diagnostics {
impl Diagnostics {
// Is the type `{D,Subd}iagMessage`?
fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: MiddleTy<'cx>) -> bool {
fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: Ty<'cx>) -> bool {
if let Some(adt_def) = ty.ty_adt_def()
&& let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
&& matches!(name, sym::DiagMessage | sym::SubdiagMessage)
@@ -510,7 +548,7 @@ impl Diagnostics {
fn untranslatable_diagnostic<'cx>(
cx: &LateContext<'cx>,
def_id: DefId,
arg_tys_and_spans: &[(MiddleTy<'cx>, Span)],
arg_tys_and_spans: &[(Ty<'cx>, Span)],
) {
let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;

View File

@@ -27,7 +27,7 @@ enum CanonicalizeInputKind {
ParamEnv,
/// When canonicalizing predicates, we don't keep `'static`. If we're
/// currently outside of the trait solver and canonicalize the root goal
/// during HIR typeck, we replace each occurance of a region with a
/// during HIR typeck, we replace each occurrence of a region with a
/// unique region variable. See the comment on `InferCtxt::in_hir_typeck`
/// for more details.
Predicate { is_hir_typeck_root_goal: bool },

View File

@@ -93,6 +93,9 @@ resolve_consider_adding_a_derive =
resolve_consider_adding_macro_export =
consider adding a `#[macro_export]` to the macro in the imported module
resolve_consider_marking_as_pub_crate =
in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)`
resolve_consider_declaring_with_pub =
consider declaring type or module `{$ident}` with `pub`

View File

@@ -485,6 +485,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
root_span,
root_id,
vis,
vis_span: item.vis.span,
});
self.r.indeterminate_imports.push(import);
@@ -977,6 +978,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
span: item.span,
module_path: Vec::new(),
vis,
vis_span: item.vis.span,
});
if used {
self.r.import_use_map.insert(import, Used::Other);
@@ -1111,6 +1113,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
span,
module_path: Vec::new(),
vis: Visibility::Restricted(CRATE_DEF_ID),
vis_span: item.vis.span,
})
};
@@ -1281,6 +1284,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
span,
module_path: Vec::new(),
vis,
vis_span: item.vis.span,
});
self.r.import_use_map.insert(import, Used::Other);
let import_binding = self.r.import(binding, import);

View File

@@ -775,6 +775,17 @@ pub(crate) struct ConsiderAddingMacroExport {
pub(crate) span: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(
resolve_consider_marking_as_pub_crate,
code = "pub(crate)",
applicability = "maybe-incorrect"
)]
pub(crate) struct ConsiderMarkingAsPubCrate {
#[primary_span]
pub(crate) vis_span: Span,
}
#[derive(Subdiagnostic)]
#[note(resolve_consider_marking_as_pub)]
pub(crate) struct ConsiderMarkingAsPub {

View File

@@ -30,7 +30,7 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates};
use crate::errors::{
CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
ConsiderAddingMacroExport, ConsiderMarkingAsPub,
ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate,
};
use crate::{
AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion,
@@ -184,6 +184,9 @@ pub(crate) struct ImportData<'ra> {
/// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
pub vis: Visibility,
/// Span of the visibility.
pub vis_span: Span,
}
/// All imports are unique and allocated on a same arena,
@@ -866,7 +869,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
ImportKind::Glob { .. } => {
// FIXME: Use mutable resolver directly as a hack, this should be an output of
// specualtive resolution.
// speculative resolution.
self.get_mut_unchecked().resolve_glob_import(import);
return 0;
}
@@ -903,7 +906,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// We need the `target`, `source` can be extracted.
let imported_binding = this.import(binding, import);
// FIXME: Use mutable resolver directly as a hack, this should be an output of
// specualtive resolution.
// speculative resolution.
this.get_mut_unchecked().define_binding_local(
parent,
target,
@@ -917,7 +920,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if target.name != kw::Underscore {
let key = BindingKey::new(target, ns);
// FIXME: Use mutable resolver directly as a hack, this should be an output of
// specualtive resolution.
// speculative resolution.
this.get_mut_unchecked().update_local_resolution(
parent,
key,
@@ -1368,6 +1371,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
err.subdiagnostic( ConsiderAddingMacroExport {
span: binding.span,
});
err.subdiagnostic( ConsiderMarkingAsPubCrate {
vis_span: import.vis_span,
});
}
_ => {
err.subdiagnostic( ConsiderMarkingAsPub {

View File

@@ -4270,7 +4270,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
if path.len() == 2
&& let [segment] = prefix_path
{
// Delay to check whether methond name is an associated function or not
// Delay to check whether method name is an associated function or not
// ```
// let foo = Foo {};
// foo::bar(); // possibly suggest to foo.bar();

View File

@@ -49,6 +49,8 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n
session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target
.note = compatible flavors are: {$compatible_list}
session_indirect_branch_cs_prefix_requires_x86_or_x86_64 = `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64
session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
session_int_literal_too_large = integer literal is too large

View File

@@ -471,6 +471,10 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664;
#[diag(session_function_return_thunk_extern_requires_non_large_code_model)]
pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel;
#[derive(Diagnostic)]
#[diag(session_indirect_branch_cs_prefix_requires_x86_or_x86_64)]
pub(crate) struct IndirectBranchCsPrefixRequiresX86OrX8664;
#[derive(Diagnostic)]
#[diag(session_unsupported_regparm)]
pub(crate) struct UnsupportedRegparm {

View File

@@ -2295,6 +2295,8 @@ options! {
- hashes of green query instances
- hash collisions of query keys
- hash collisions when creating dep-nodes"),
indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
"add `cs` prefix to `call` and `jmp` to indirect thunks (default: no)"),
inline_llvm: bool = (true, parse_bool, [TRACKED],
"enable LLVM inlining (default: yes)"),
inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],

View File

@@ -1368,6 +1368,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}
if sess.opts.unstable_opts.indirect_branch_cs_prefix {
if sess.target.arch != "x86" && sess.target.arch != "x86_64" {
sess.dcx().emit_err(errors::IndirectBranchCsPrefixRequiresX86OrX8664);
}
}
if let Some(regparm) = sess.opts.unstable_opts.regparm {
if regparm > 3 {
sess.dcx().emit_err(errors::UnsupportedRegparm { regparm });

View File

@@ -767,6 +767,7 @@ static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
("32s", Unstable(sym::loongarch_target_feature), &[]),
("d", Stable, &["f"]),
("div32", Unstable(sym::loongarch_target_feature), &[]),
("f", Stable, &[]),

View File

@@ -3,164 +3,78 @@
use crate::fmt::NumBuffer;
use crate::mem::MaybeUninit;
use crate::num::fmt as numfmt;
use crate::ops::{Div, Rem, Sub};
use crate::{fmt, ptr, slice, str};
#[doc(hidden)]
trait DisplayInt:
PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
{
fn zero() -> Self;
fn from_u8(u: u8) -> Self;
fn to_u8(&self) -> u8;
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
fn to_u32(&self) -> u32;
fn to_u64(&self) -> u64;
fn to_u128(&self) -> u128;
}
macro_rules! impl_int {
($($t:ident)*) => (
$(impl DisplayInt for $t {
fn zero() -> Self { 0 }
fn from_u8(u: u8) -> Self { u as Self }
fn to_u8(&self) -> u8 { *self as u8 }
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
fn to_u32(&self) -> u32 { *self as u32 }
fn to_u64(&self) -> u64 { *self as u64 }
fn to_u128(&self) -> u128 { *self as u128 }
})*
)
}
impl_int! {
i8 i16 i32 i64 i128 isize
u8 u16 u32 u64 u128 usize
}
/// A type that represents a specific radix
///
/// # Safety
///
/// `digit` must return an ASCII character.
#[doc(hidden)]
unsafe trait GenericRadix: Sized {
/// The number of digits.
const BASE: u8;
/// A radix-specific prefix string.
const PREFIX: &'static str;
/// Converts an integer to corresponding radix digit.
fn digit(x: u8) -> u8;
/// Format an integer using the radix using a formatter.
fn fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// The radix can be as low as 2, so we need a buffer of at least 128
// characters for a base 2 number.
let zero = T::zero();
let is_nonnegative = x >= zero;
let mut buf = [MaybeUninit::<u8>::uninit(); 128];
let mut offset = buf.len();
let base = T::from_u8(Self::BASE);
if is_nonnegative {
// Accumulate each digit of the number from the least significant
// to the most significant figure.
loop {
let n = x % base; // Get the current place value.
x = x / base; // Deaccumulate the number.
offset -= 1;
buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer.
if x == zero {
// No more digits left to accumulate.
break;
};
}
} else {
// Do the same as above, but accounting for two's complement.
loop {
let n = zero - (x % base); // Get the current place value.
x = x / base; // Deaccumulate the number.
offset -= 1;
buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer.
if x == zero {
// No more digits left to accumulate.
break;
};
}
}
// SAFETY: Starting from `offset`, all elements of the slice have been set.
let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
f.pad_integral(is_nonnegative, Self::PREFIX, buf_slice)
}
}
/// A binary (base 2) radix
#[derive(Clone, PartialEq)]
struct Binary;
/// An octal (base 8) radix
#[derive(Clone, PartialEq)]
struct Octal;
/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[derive(Clone, PartialEq)]
struct LowerHex;
/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[derive(Clone, PartialEq)]
struct UpperHex;
macro_rules! radix {
($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
unsafe impl GenericRadix for $T {
const BASE: u8 = $base;
const PREFIX: &'static str = $prefix;
fn digit(x: u8) -> u8 {
match x {
$($x => $conv,)+
x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x),
}
}
}
}
}
radix! { Binary, 2, "0b", x @ 0 ..= 1 => b'0' + x }
radix! { Octal, 8, "0o", x @ 0 ..= 7 => b'0' + x }
radix! { LowerHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'a' + (x - 10) }
radix! { UpperHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'A' + (x - 10) }
macro_rules! int_base {
(fmt::$Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
/// Formatting of integers with a non-decimal radix.
macro_rules! radix_integer {
(fmt::$Trait:ident for $Signed:ident and $Unsigned:ident, $prefix:literal, $dig_tab:literal) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::$Trait for $T {
impl fmt::$Trait for $Unsigned {
/// Format unsigned integers in the radix.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
$Radix.fmt_int(*self as $U, f)
// Check macro arguments at compile time.
const {
assert!($Unsigned::MIN == 0, "need unsigned");
assert!($dig_tab.is_ascii(), "need single-byte entries");
}
// ASCII digits in ascending order are used as a lookup table.
const DIG_TAB: &[u8] = $dig_tab;
const BASE: $Unsigned = DIG_TAB.len() as $Unsigned;
const MAX_DIG_N: usize = $Unsigned::MAX.ilog(BASE) as usize + 1;
// Buffer digits of self with right alignment.
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DIG_N];
// Count the number of bytes in buf that are not initialized.
let mut offset = buf.len();
// Accumulate each digit of the number from the least
// significant to the most significant figure.
let mut remain = *self;
loop {
let digit = remain % BASE;
remain /= BASE;
offset -= 1;
// SAFETY: `remain` will reach 0 and we will break before `offset` wraps
unsafe { core::hint::assert_unchecked(offset < buf.len()) }
buf[offset].write(DIG_TAB[digit as usize]);
if remain == 0 {
break;
}
}
// SAFETY: Starting from `offset`, all elements of the slice have been set.
let digits = unsafe { slice_buffer_to_str(&buf, offset) };
f.pad_integral(true, $prefix, digits)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::$Trait for $Signed {
/// Format signed integers in the twos-complement form.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::$Trait::fmt(&self.cast_unsigned(), f)
}
}
};
}
macro_rules! integer {
($Int:ident, $Uint:ident) => {
int_base! { fmt::Binary for $Int as $Uint -> Binary }
int_base! { fmt::Octal for $Int as $Uint -> Octal }
int_base! { fmt::LowerHex for $Int as $Uint -> LowerHex }
int_base! { fmt::UpperHex for $Int as $Uint -> UpperHex }
int_base! { fmt::Binary for $Uint as $Uint -> Binary }
int_base! { fmt::Octal for $Uint as $Uint -> Octal }
int_base! { fmt::LowerHex for $Uint as $Uint -> LowerHex }
int_base! { fmt::UpperHex for $Uint as $Uint -> UpperHex }
/// Formatting of integers with a non-decimal radix.
macro_rules! radix_integers {
($Signed:ident, $Unsigned:ident) => {
radix_integer! { fmt::Binary for $Signed and $Unsigned, "0b", b"01" }
radix_integer! { fmt::Octal for $Signed and $Unsigned, "0o", b"01234567" }
radix_integer! { fmt::LowerHex for $Signed and $Unsigned, "0x", b"0123456789abcdef" }
radix_integer! { fmt::UpperHex for $Signed and $Unsigned, "0x", b"0123456789ABCDEF" }
};
}
integer! { isize, usize }
integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
integer! { i64, u64 }
integer! { i128, u128 }
radix_integers! { isize, usize }
radix_integers! { i8, u8 }
radix_integers! { i16, u16 }
radix_integers! { i32, u32 }
radix_integers! { i64, u64 }
radix_integers! { i128, u128 }
macro_rules! impl_Debug {
($($T:ident)*) => {
@@ -205,16 +119,21 @@ unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
}
macro_rules! impl_Display {
($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
$(
const _: () = {
assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
};
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for $unsigned {
impl fmt::Display for $Unsigned {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(not(feature = "optimize_for_size"))]
{
const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
// Buffer decimals for $unsigned with right alignment.
const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
// Buffer decimals for self with right alignment.
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
// SAFETY: `buf` is always big enough to contain all the digits.
@@ -222,18 +141,20 @@ macro_rules! impl_Display {
}
#[cfg(feature = "optimize_for_size")]
{
$gen_name(self.$conv_fn(), true, f)
// Lossless conversion (with as) is asserted at the top of
// this macro.
${concat($fmt_fn, _small)}(*self as $T, true, f)
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for $signed {
impl fmt::Display for $Signed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(not(feature = "optimize_for_size"))]
{
const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
// Buffer decimals for $unsigned with right alignment.
const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
// Buffer decimals for self with right alignment.
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
// SAFETY: `buf` is always big enough to contain all the digits.
@@ -241,13 +162,15 @@ macro_rules! impl_Display {
}
#[cfg(feature = "optimize_for_size")]
{
return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f);
// Lossless conversion (with as) is asserted at the top of
// this macro.
return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
}
}
}
#[cfg(not(feature = "optimize_for_size"))]
impl $unsigned {
impl $Unsigned {
#[doc(hidden)]
#[unstable(
feature = "fmt_internals",
@@ -268,7 +191,7 @@ macro_rules! impl_Display {
let mut remain = self;
// Format per four digits from the lookup table.
// Four digits need a 16-bit $unsigned or wider.
// Four digits need a 16-bit $Unsigned or wider.
while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N
// and the while condition ensures at least 4 more decimals.
@@ -327,7 +250,7 @@ macro_rules! impl_Display {
}
}
impl $signed {
impl $Signed {
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
///
@@ -337,15 +260,15 @@ macro_rules! impl_Display {
/// #![feature(int_format_into)]
/// use core::fmt::NumBuffer;
///
#[doc = concat!("let n = 0", stringify!($signed), ";")]
#[doc = concat!("let n = 0", stringify!($Signed), ";")]
/// let mut buf = NumBuffer::new();
/// assert_eq!(n.format_into(&mut buf), "0");
///
#[doc = concat!("let n1 = 32", stringify!($signed), ";")]
#[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
/// assert_eq!(n1.format_into(&mut buf), "32");
///
#[doc = concat!("let n2 = ", stringify!($signed::MAX), ";")]
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($signed::MAX), ".to_string());")]
#[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
/// ```
#[unstable(feature = "int_format_into", issue = "138215")]
pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
@@ -358,7 +281,9 @@ macro_rules! impl_Display {
}
#[cfg(feature = "optimize_for_size")]
{
offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf);
// Lossless conversion (with as) is asserted at the top of
// this macro.
offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
}
// Only difference between signed and unsigned are these 4 lines.
if self < 0 {
@@ -370,7 +295,7 @@ macro_rules! impl_Display {
}
}
impl $unsigned {
impl $Unsigned {
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
///
@@ -380,15 +305,15 @@ macro_rules! impl_Display {
/// #![feature(int_format_into)]
/// use core::fmt::NumBuffer;
///
#[doc = concat!("let n = 0", stringify!($unsigned), ";")]
#[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
/// let mut buf = NumBuffer::new();
/// assert_eq!(n.format_into(&mut buf), "0");
///
#[doc = concat!("let n1 = 32", stringify!($unsigned), ";")]
#[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
/// assert_eq!(n1.format_into(&mut buf), "32");
///
#[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")]
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($unsigned::MAX), ".to_string());")]
#[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
/// ```
#[unstable(feature = "int_format_into", issue = "138215")]
pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
@@ -401,7 +326,9 @@ macro_rules! impl_Display {
}
#[cfg(feature = "optimize_for_size")]
{
offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf);
// Lossless conversion (with as) is asserted at the top of
// this macro.
offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
}
// SAFETY: Starting from `offset`, all elements of the slice have been set.
unsafe { slice_buffer_to_str(&buf.buf, offset) }
@@ -412,7 +339,7 @@ macro_rules! impl_Display {
)*
#[cfg(feature = "optimize_for_size")]
fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize {
fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
let mut curr = buf.len();
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
@@ -433,11 +360,11 @@ macro_rules! impl_Display {
}
#[cfg(feature = "optimize_for_size")]
fn $gen_name(n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1;
fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf);
let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
// SAFETY: Starting from `offset`, all elements of the slice have been set.
let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
f.pad_integral(is_nonnegative, "", buf_slice)
@@ -446,9 +373,9 @@ macro_rules! impl_Display {
}
macro_rules! impl_Exp {
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
fn $name(
mut n: $u,
($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
fn $fmt_fn(
mut n: $T,
is_nonnegative: bool,
upper: bool,
f: &mut fmt::Formatter<'_>
@@ -582,32 +509,41 @@ macro_rules! impl_Exp {
$(
#[stable(feature = "integer_exp_format", since = "1.42.0")]
impl fmt::LowerExp for $t {
#[allow(unused_comparisons)]
impl fmt::LowerExp for $Signed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_nonnegative = *self >= 0;
let n = if is_nonnegative {
self.$conv_fn()
*self as $T
} else {
// convert the negative num to positive by summing 1 to its 2s complement
(!self.$conv_fn()).wrapping_add(1)
self.unsigned_abs() as $T
};
$name(n, is_nonnegative, false, f)
$fmt_fn(n, is_nonnegative, false, f)
}
}
#[stable(feature = "integer_exp_format", since = "1.42.0")]
impl fmt::LowerExp for $Unsigned {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
$fmt_fn(*self as $T, true, false, f)
}
})*
$(
#[stable(feature = "integer_exp_format", since = "1.42.0")]
impl fmt::UpperExp for $t {
#[allow(unused_comparisons)]
impl fmt::UpperExp for $Signed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_nonnegative = *self >= 0;
let n = if is_nonnegative {
self.$conv_fn()
*self as $T
} else {
// convert the negative num to positive by summing 1 to its 2s complement
(!self.$conv_fn()).wrapping_add(1)
self.unsigned_abs() as $T
};
$name(n, is_nonnegative, true, f)
$fmt_fn(n, is_nonnegative, true, f)
}
}
#[stable(feature = "integer_exp_format", since = "1.42.0")]
impl fmt::UpperExp for $Unsigned {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
$fmt_fn(*self as $T, true, true, f)
}
})*
};
@@ -623,37 +559,20 @@ impl_Debug! {
#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
mod imp {
use super::*;
impl_Display!(
i8, u8,
i16, u16,
i32, u32,
i64, u64,
isize, usize,
; as u64 via to_u64 named fmt_u64
);
impl_Exp!(
i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
as u64 via to_u64 named exp_u64
);
impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
}
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
mod imp {
use super::*;
impl_Display!(
i8, u8,
i16, u16,
i32, u32,
isize, usize,
; as u32 via to_u32 named fmt_u32);
impl_Display!(
i64, u64,
; as u64 via to_u64 named fmt_u64);
impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
impl_Display!(i64, u64; as u64 into display_u64);
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
impl_Exp!(i64, u64; as u64 into exp_u64);
}
impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
impl_Exp!(i128, u128; as u128 into exp_u128);
const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;

View File

@@ -124,6 +124,8 @@ macro_rules! from_str_float_impl {
/// * '2.5E-10'
/// * '5.'
/// * '.5', or, equivalently, '0.5'
/// * '7'
/// * '007'
/// * 'inf', '-inf', '+infinity', 'NaN'
///
/// Note that alphabetical characters are not case-sensitive.

View File

@@ -2494,8 +2494,7 @@ macro_rules! int_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `i32` is used here.
/// Please note that this example is shared among integer types, which is why `i32` is used.
///
/// ```
/// #![feature(bigint_helper_methods)]
@@ -2525,8 +2524,7 @@ macro_rules! int_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `i32` is used here.
/// Please note that this example is shared among integer types, which is why `i32` is used.
///
/// ```
/// #![feature(bigint_helper_methods)]
@@ -2563,8 +2561,7 @@ macro_rules! int_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `i32` is used here.
/// Please note that this example is shared among integer types, which is why `i32` is used.
///
/// ```
/// #![feature(bigint_helper_methods)]

View File

@@ -729,8 +729,8 @@ macro_rules! saturating_int_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `i16` is used here.
/// Please note that this example is shared among integer types, which is why `i16`
/// is used.
///
/// ```
/// use std::num::Saturating;

View File

@@ -2115,8 +2115,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `u8` is used here.
/// Please note that this example is shared among integer types, which is why `u8` is used.
///
/// ```
/// assert_eq!(10u8.wrapping_mul(12), 120);
@@ -2606,8 +2605,8 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `u32` is used here.
/// Please note that this example is shared among integer types, which is why why `u32`
/// is used.
///
/// ```
/// assert_eq!(5u32.overflowing_mul(2), (10, false));
@@ -2633,8 +2632,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `u32` is used here.
/// Please note that this example is shared among integer types, which is why `u32` is used.
///
/// ```
/// #![feature(bigint_helper_methods)]
@@ -2664,8 +2662,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `u32` is used here.
/// Please note that this example is shared among integer types, which is why `u32` is used.
///
/// ```
/// #![feature(bigint_helper_methods)]

View File

@@ -765,8 +765,8 @@ macro_rules! wrapping_int_impl {
///
/// # Examples
///
/// Please note that this example is shared between integer types.
/// Which explains why `i16` is used here.
/// Please note that this example is shared among integer types, which is why `i16`
/// is used.
///
/// Basic usage:
///

View File

@@ -1,5 +1,6 @@
//! Unicode internals used in liballoc and libstd. Not public API.
#![unstable(feature = "unicode_internals", issue = "none")]
#![allow(missing_docs)]
#![doc(hidden)]
// for use in alloc, not re-exported in std.
#[rustfmt::skip]
@@ -31,5 +32,4 @@ mod unicode_data;
///
/// The version numbering scheme is explained in
/// [Unicode 11.0 or later, Section 3.1 Versions of the Unicode Standard](https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf#page=4).
#[stable(feature = "unicode_version", since = "1.45.0")]
pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION;

View File

@@ -162,3 +162,183 @@ fn write_u8_min(bh: &mut Bencher) {
black_box(format!("{}", black_box(u8::MIN)));
});
}
#[bench]
fn write_i8_bin(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:b}", black_box(0_i8)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(100_i8)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(-100_i8)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(1_i8 << 4)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i16_bin(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:b}", black_box(0_i16)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(100_i16)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(-100_i16)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(1_i16 << 8)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i32_bin(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:b}", black_box(0_i32)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(100_i32)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(-100_i32)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(1_i32 << 16)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i64_bin(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:b}", black_box(0_i64)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(100_i64)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(-100_i64)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(1_i64 << 32)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i128_bin(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:b}", black_box(0_i128)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(100_i128)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(-100_i128)).unwrap();
write!(black_box(&mut buf), "{:b}", black_box(1_i128 << 64)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i8_oct(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:o}", black_box(0_i8)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(100_i8)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(-100_i8)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(1_i8 << 4)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i16_oct(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:o}", black_box(0_i16)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(100_i16)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(-100_i16)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(1_i16 << 8)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i32_oct(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:o}", black_box(0_i32)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(100_i32)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(-100_i32)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(1_i32 << 16)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i64_oct(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:o}", black_box(0_i64)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(100_i64)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(-100_i64)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(1_i64 << 32)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i128_oct(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:o}", black_box(0_i128)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(100_i128)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(-100_i128)).unwrap();
write!(black_box(&mut buf), "{:o}", black_box(1_i128 << 64)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i8_hex(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:x}", black_box(0_i8)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(100_i8)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(-100_i8)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(1_i8 << 4)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i16_hex(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:x}", black_box(0_i16)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(100_i16)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(-100_i16)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(1_i16 << 8)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i32_hex(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:x}", black_box(0_i32)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(100_i32)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(-100_i32)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(1_i32 << 16)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i64_hex(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:x}", black_box(0_i64)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(100_i64)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(-100_i64)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(1_i64 << 32)).unwrap();
black_box(&mut buf).clear();
});
}
#[bench]
fn write_i128_hex(bh: &mut Bencher) {
let mut buf = String::with_capacity(256);
bh.iter(|| {
write!(black_box(&mut buf), "{:x}", black_box(0_i128)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(100_i128)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(-100_i128)).unwrap();
write!(black_box(&mut buf), "{:x}", black_box(1_i128 << 64)).unwrap();
black_box(&mut buf).clear();
});
}

View File

@@ -3156,6 +3156,25 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result
fs_imp::set_permissions(path.as_ref(), perm.0)
}
/// Set the permissions of a file, unless it is a symlink.
///
/// Note that the non-final path elements are allowed to be symlinks.
///
/// # Platform-specific behavior
///
/// Currently unimplemented on Windows.
///
/// On Unix platforms, this results in a [`FilesystemLoop`] error if the last element is a symlink.
///
/// This behavior may change in the future.
///
/// [`FilesystemLoop`]: crate::io::ErrorKind::FilesystemLoop
#[doc(alias = "chmod", alias = "SetFileAttributes")]
#[unstable(feature = "set_permissions_nofollow", issue = "141607")]
pub fn set_permissions_nofollow<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
fs_imp::set_permissions_nofollow(path.as_ref(), perm)
}
impl DirBuilder {
/// Creates a new set of options with default mode/security settings for all
/// platforms and also non-recursive.

View File

@@ -100,7 +100,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: &'a Mutex<T>,
}
/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
/// A [`MutexGuard`] is not `Send` to maximize platform portability.
///
/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
/// release mutex locks on the same thread they were acquired.

View File

@@ -279,7 +279,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
poison: poison::Guard,
}
/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
/// A [`MutexGuard`] is not `Send` to maximize platform portability.
///
/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
/// release mutex locks on the same thread they were acquired.

View File

@@ -114,6 +114,21 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> {
with_native_path(path, &|path| imp::set_perm(path, perm.clone()))
}
#[cfg(unix)]
pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> {
use crate::fs::OpenOptions;
use crate::os::unix::fs::OpenOptionsExt;
OpenOptions::new().custom_flags(libc::O_NOFOLLOW).open(path)?.set_permissions(perm)
}
#[cfg(not(unix))]
pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> {
crate::unimplemented!(
"`set_permissions_nofollow` is currently only implemented on Unix platforms"
)
}
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
with_native_path(path, &imp::canonicalize)
}

View File

@@ -1,7 +1,7 @@
#![allow(unsafe_op_in_unsafe_fn)]
/// The configure builtins provides runtime support compiler-builtin features
/// which require dynamic intialization to work as expected, e.g. aarch64
/// which require dynamic initialization to work as expected, e.g. aarch64
/// outline-atomics.
mod configure_builtins;

View File

@@ -188,7 +188,7 @@ pub(crate) mod system_time_internal {
Duration::new(epoch, t.nanosecond)
}
/// This algorithm is a modifed version of the one described in the post:
/// This algorithm is a modified version of the one described in the post:
/// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
///
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
@@ -197,7 +197,7 @@ pub(crate) mod system_time_internal {
// Check timzone validity
assert!(timezone <= 1440 && timezone >= -1440);
// FIXME(#126043): use checked_sub_signed once stablized
// FIXME(#126043): use checked_sub_signed once stabilized
let secs =
dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();

View File

@@ -8,6 +8,7 @@ features! {
/// Checks if `loongarch` feature is enabled.
/// Supported arguments are:
///
/// * `"32s"`
/// * `"f"`
/// * `"d"`
/// * `"frecipe"`
@@ -22,6 +23,8 @@ features! {
/// * `"lvz"`
/// * `"ual"`
#[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")]
@FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] _32s: "32s";
/// 32S
@FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] f: "f";
/// F
@FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] d: "d";

View File

@@ -17,22 +17,21 @@ pub(crate) fn detect_features() -> cache::Initializer {
// The values are part of the platform-specific [cpucfg]
//
// [cpucfg]: LoongArch Reference Manual Volume 1: Basic Architecture v1.1
let cpucfg1: usize;
let cpucfg2: usize;
unsafe {
asm!(
"cpucfg {}, {}",
out(reg) cpucfg2, in(reg) 2,
options(pure, nomem, preserves_flags, nostack)
);
}
let cpucfg3: usize;
unsafe {
asm!(
"cpucfg {}, {}",
"cpucfg {}, {}",
"cpucfg {}, {}",
out(reg) cpucfg1, in(reg) 1,
out(reg) cpucfg2, in(reg) 2,
out(reg) cpucfg3, in(reg) 3,
options(pure, nomem, preserves_flags, nostack)
);
}
enable_feature(&mut value, Feature::_32s, bit::test(cpucfg1, 0) || bit::test(cpucfg1, 1));
enable_feature(&mut value, Feature::frecipe, bit::test(cpucfg2, 25));
enable_feature(&mut value, Feature::div32, bit::test(cpucfg2, 26));
enable_feature(&mut value, Feature::lam_bh, bit::test(cpucfg2, 27));

View File

@@ -69,6 +69,8 @@ fn aarch64() {
#[test]
#[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))]
fn loongarch() {
let _ = is_loongarch_feature_detected!("32s");
let _ = is_loongarch_feature_detected!("32s",);
let _ = is_loongarch_feature_detected!("lsx");
let _ = is_loongarch_feature_detected!("lsx",);
}

View File

@@ -45,4 +45,4 @@ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)'
# NOTE: intentionally uses python2 for x.py so we can test it still works.
# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \
src/tools/tidy tidyselftest --extra-checks=py,cpp,js
src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck

View File

@@ -534,10 +534,10 @@ tests, and will reject patches that fail to build or pass the testsuite on a
target. We hold tier 1 targets to our highest standard of requirements.
A proposed new tier 1 target must be reviewed and approved by the compiler team
based on these requirements. In addition, the release team must approve the
viability and value of supporting the target. For a tier 1 target, this will
based on these requirements. In addition, the infra team must approve the
viability of supporting the target. For a tier 1 target, this will
typically take place via a full RFC proposing the target, to be jointly
reviewed and approved by the compiler team and release team.
reviewed and approved by the compiler team and infra team.
In addition, the infrastructure team must approve the integration of the target
into Continuous Integration (CI), and the tier 1 CI-related requirements. This
@@ -617,7 +617,7 @@ including the infrastructure team in the RFC proposing the target.
A tier 1 target may be demoted if it no longer meets these requirements but
still meets the requirements for a lower tier. Any proposal for demotion of a
tier 1 target requires a full RFC process, with approval by the compiler and
release teams. Any such proposal will be communicated widely to the Rust
infra teams. Any such proposal will be communicated widely to the Rust
community, both when initially proposed and before being dropped from a stable
release. A tier 1 target is highly unlikely to be directly removed without
first being demoted to tier 2 or tier 3. (The amount of time between such
@@ -628,7 +628,7 @@ planned and scheduled action.)
Raising the baseline expectations of a tier 1 target (such as the minimum CPU
features or OS version required) requires the approval of the compiler and
release teams, and should be widely communicated as well, but does not
infra teams, and should be widely communicated as well, but does not
necessarily require a full RFC.
### Tier 1 with host tools
@@ -638,11 +638,11 @@ host (such as `rustc` and `cargo`). This allows the target to be used as a
development platform, not just a compilation target.
A proposed new tier 1 target with host tools must be reviewed and approved by
the compiler team based on these requirements. In addition, the release team
must approve the viability and value of supporting host tools for the target.
the compiler team based on these requirements. In addition, the infra team
must approve the viability of supporting host tools for the target.
For a tier 1 target, this will typically take place via a full RFC proposing
the target, to be jointly reviewed and approved by the compiler team and
release team.
infra team.
In addition, the infrastructure team must approve the integration of the
target's host tools into Continuous Integration (CI), and the CI-related
@@ -697,7 +697,7 @@ target with host tools may be demoted (including having its host tools dropped,
or being demoted to tier 2 with host tools) if it no longer meets these
requirements but still meets the requirements for a lower tier. Any proposal
for demotion of a tier 1 target (with or without host tools) requires a full
RFC process, with approval by the compiler and release teams. Any such proposal
RFC process, with approval by the compiler and infra teams. Any such proposal
will be communicated widely to the Rust community, both when initially proposed
and before being dropped from a stable release.

View File

@@ -0,0 +1,19 @@
# `indirect-branch-cs-prefix`
The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116852.
------------------------
Option `-Zindirect-branch-cs-prefix` controls whether a `cs` prefix is added to
`call` and `jmp` to indirect thunks.
It is equivalent to [Clang]'s and [GCC]'s `-mindirect-branch-cs-prefix`. The
Linux kernel uses it for RETPOLINE builds. For details, see
[LLVM commit 6f867f910283] ("[X86] Support ``-mindirect-branch-cs-prefix`` for
call and jmp to indirect thunk") which introduces the feature.
Only x86 and x86_64 are supported.
[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mindirect-branch-cs-prefix
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mindirect-branch-cs-prefix
[LLVM commit 6f867f910283]: https://github.com/llvm/llvm-project/commit/6f867f9102838ebe314c1f3661fdf95700386e5a

View File

@@ -47,7 +47,7 @@ pub(crate) struct Cache {
/// Similar to `paths`, but only holds external paths. This is only used for
/// generating explicit hyperlinks to other crates.
pub(crate) external_paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
pub(crate) external_paths: FxIndexMap<DefId, (Vec<Symbol>, ItemType)>,
/// Maps local `DefId`s of exported types to fully qualified paths.
/// Unlike 'paths', this mapping ignores any renames that occur

View File

@@ -1649,7 +1649,7 @@ function preLoadCss(cssUrl) {
["&#9166;", "Go to active search result"],
["+", "Expand all sections"],
["-", "Collapse all sections"],
// for the sake of brevity, we don't say "inherint impl blocks",
// for the sake of brevity, we don't say "inherit impl blocks",
// although that would be more correct,
// since trait impl blocks are collapsed by -
["_", "Collapse all sections, including impl blocks"],

View File

@@ -1111,6 +1111,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
// For foreign items, try to see if we can emulate them.
if ecx.tcx.is_foreign_item(instance.def_id()) {
let _trace = enter_trace_span!("emulate_foreign_item");
// An external function call that does not have a MIR body. We either find MIR elsewhere
// or emulate its effect.
// This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
@@ -1123,6 +1124,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
}
// Otherwise, load the MIR.
let _trace = enter_trace_span!("load_mir");
interp_ok(Some((ecx.load_mir(instance.def, None)?, instance)))
}

View File

@@ -0,0 +1,34 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
// Validation forces more things into memory, which we can't have here.
//@compile-flags: -Zmiri-disable-validation
#![feature(custom_mir, core_intrinsics)]
use std::intrinsics::mir::*;
pub struct S(i32);
#[custom_mir(dialect = "runtime", phase = "optimized")]
fn main() {
mir! {
let _unit: ();
{
let staging = S(42); // This forces `staging` into memory...
let non_copy = staging; // ... so we move it to a non-inmemory local here.
// This specifically uses a type with scalar representation to tempt Miri to use the
// efficient way of storing local variables (outside adressable memory).
Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
//~[stack]^ ERROR: not granting access
//~[tree]| ERROR: /read access .* forbidden/
}
after_call = {
Return()
}
}
}
pub fn callee(x: S, mut y: S) {
// With the setup above, if `x` and `y` are both moved,
// then writing to `y` will change the value stored in `x`!
y.0 = 0;
assert_eq!(x.0, 42);
}

View File

@@ -0,0 +1,25 @@
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <TAG> was created here, as the root tag for ALLOC
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: <TAG> is this argument
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | y.0 = 0;
| ^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@@ -0,0 +1,33 @@
error: Undefined Behavior: read access through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
= help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
= help: protected tags must never be Disabled
help: the accessed tag <TAG> was created here
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | y.0 = 0;
| ^^^^^^^
help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | y.0 = 0;
| ^^^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: BACKTRACE (of the first span):
= note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@@ -11,8 +11,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
ALLOC (stack variable, size: 4, align: 4) {

View File

@@ -10,11 +10,11 @@ use std::intrinsics::mir::*;
pub fn main() {
mir! {
{
let x = 0;
let ptr = &raw mut x;
let _x = 0;
let ptr = &raw mut _x;
// We arrange for `myfun` to have a pointer that aliases
// its return place. Even just reading from that pointer is UB.
Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
}
after_call = {
@@ -25,7 +25,7 @@ pub fn main() {
fn myfun(ptr: *mut i32) -> i32 {
unsafe { ptr.read() };
//~[stack]^ ERROR: not granting access
//~[stack]^ ERROR: does not exist in the borrow stack
//~[tree]| ERROR: /read access .* forbidden/
//~[none]| ERROR: uninitialized
// Without an aliasing model, reads are "fine" but at least they return uninit data.

View File

@@ -1,8 +1,8 @@
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
error: Undefined Behavior: attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | unsafe { ptr.read() };
| ^^^^^^^^^^ Undefined Behavior occurred here
| ^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -11,12 +11,12 @@ help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
|
LL | / mir! {
LL | | {
LL | | let x = 0;
LL | | let ptr = &raw mut x;
LL | | let _x = 0;
LL | | let ptr = &raw mut _x;
... |
LL | | }
| |_____^
help: <TAG> is this argument
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | unsafe { ptr.read() };
@@ -26,8 +26,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@@ -13,8 +13,8 @@ help: the accessed tag <TAG> was created here
|
LL | / mir! {
LL | | {
LL | | let x = 0;
LL | | let ptr = &raw mut x;
LL | | let _x = 0;
LL | | let ptr = &raw mut _x;
... |
LL | | }
| |_____^
@@ -34,8 +34,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@@ -14,7 +14,7 @@ pub fn main() {
let ptr = &raw mut _x;
// We arrange for `myfun` to have a pointer that aliases
// its return place. Writing to that pointer is UB.
Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
}
after_call = {
@@ -26,7 +26,7 @@ pub fn main() {
fn myfun(ptr: *mut i32) -> i32 {
// This overwrites the return place, which shouldn't be possible through another pointer.
unsafe { ptr.write(0) };
//~[stack]^ ERROR: strongly protected
//~[stack]^ ERROR: does not exist in the borrow stack
//~[tree]| ERROR: /write access .* forbidden/
13
}

View File

@@ -1,8 +1,8 @@
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^ Undefined Behavior occurred here
| ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -16,7 +16,7 @@ LL | | let ptr = &raw mut _x;
... |
LL | | }
| |_____^
help: <TAG> is this argument
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
@@ -26,8 +26,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@@ -34,8 +34,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@@ -16,7 +16,7 @@ pub fn main() {
let ptr = &raw mut _x;
// We arrange for `myfun` to have a pointer that aliases
// its return place. Writing to that pointer is UB.
Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
}
after_call = {
@@ -32,7 +32,7 @@ fn myfun(ptr: *mut i32) -> i32 {
fn myfun2(ptr: *mut i32) -> i32 {
// This overwrites the return place, which shouldn't be possible through another pointer.
unsafe { ptr.write(0) };
//~[stack]^ ERROR: strongly protected
//~[stack]^ ERROR: does not exist in the borrow stack
//~[tree]| ERROR: /write access .* forbidden/
13
}

View File

@@ -1,8 +1,8 @@
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^ Undefined Behavior occurred here
| ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -16,18 +16,18 @@ LL | | let ptr = &raw mut _x;
... |
LL | | }
| |_____^
help: <TAG> is this argument
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
LL | become myfun2(ptr)
| ^^^^^^^^^^^^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@@ -34,8 +34,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main`
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@@ -41,7 +41,6 @@ const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml
const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"];
const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"];
// this must be kept in sync with with .github/workflows/spellcheck.yml
const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"];
pub fn check(
@@ -51,6 +50,7 @@ pub fn check(
librustdoc_path: &Path,
tools_path: &Path,
npm: &Path,
cargo: &Path,
bless: bool,
extra_checks: Option<&str>,
pos_args: &[String],
@@ -63,6 +63,7 @@ pub fn check(
librustdoc_path,
tools_path,
npm,
cargo,
bless,
extra_checks,
pos_args,
@@ -78,6 +79,7 @@ fn check_impl(
librustdoc_path: &Path,
tools_path: &Path,
npm: &Path,
cargo: &Path,
bless: bool,
extra_checks: Option<&str>,
pos_args: &[String],
@@ -293,7 +295,7 @@ fn check_impl(
} else {
eprintln!("spellcheck files");
}
spellcheck_runner(&args)?;
spellcheck_runner(root_path, &outdir, &cargo, &args)?;
}
if js_lint || js_typecheck {
@@ -576,34 +578,25 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> {
if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) }
}
/// Check that spellchecker is installed then run it at the given path
fn spellcheck_runner(args: &[&str]) -> Result<(), Error> {
// sync version with .github/workflows/spellcheck.yml
let expected_version = "typos-cli 1.34.0";
match Command::new("typos").arg("--version").output() {
Ok(o) => {
let stdout = String::from_utf8_lossy(&o.stdout);
if stdout.trim() != expected_version {
return Err(Error::Version {
program: "typos",
required: expected_version,
installed: stdout.trim().to_string(),
});
/// Ensure that spellchecker is installed then run it at the given path
fn spellcheck_runner(
src_root: &Path,
outdir: &Path,
cargo: &Path,
args: &[&str],
) -> Result<(), Error> {
let bin_path =
crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?;
match Command::new(bin_path).current_dir(src_root).args(args).status() {
Ok(status) => {
if status.success() {
Ok(())
} else {
Err(Error::FailedCheck("typos"))
}
}
Err(e) if e.kind() == io::ErrorKind::NotFound => {
return Err(Error::MissingReq(
"typos",
"spellcheck file checks",
// sync version with .github/workflows/spellcheck.yml
Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()),
));
}
Err(e) => return Err(e.into()),
Err(err) => Err(Error::Generic(format!("failed to run typos tool: {err:?}"))),
}
let status = Command::new("typos").args(args).status()?;
if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) }
}
/// Check git for tracked files matching an extension

View File

@@ -4,7 +4,9 @@
//! to be used by tools.
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, io};
use build_helper::ci::CiEnv;
use build_helper::git::{GitConfig, get_closest_upstream_commit};
@@ -180,6 +182,70 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool {
!v.is_empty()
}
/// If the given executable is installed with the given version, use that,
/// otherwise install via cargo.
pub fn ensure_version_or_cargo_install(
build_dir: &Path,
cargo: &Path,
pkg_name: &str,
bin_name: &str,
version: &str,
) -> io::Result<PathBuf> {
// ignore the process exit code here and instead just let the version number check fail.
// we also importantly don't return if the program wasn't installed,
// instead we want to continue to the fallback.
'ck: {
// FIXME: rewrite as if-let chain once this crate is 2024 edition.
let Ok(output) = Command::new(bin_name).arg("--version").output() else {
break 'ck;
};
let Ok(s) = str::from_utf8(&output.stdout) else {
break 'ck;
};
let Some(v) = s.trim().split_whitespace().last() else {
break 'ck;
};
if v == version {
return Ok(PathBuf::from(bin_name));
}
}
let tool_root_dir = build_dir.join("misc-tools");
let tool_bin_dir = tool_root_dir.join("bin");
eprintln!("building external tool {bin_name} from package {pkg_name}@{version}");
// use --force to ensure that if the required version is bumped, we update it.
// use --target-dir to ensure we have a build cache so repeated invocations aren't slow.
// modify PATH so that cargo doesn't print a warning telling the user to modify the path.
let cargo_exit_code = Command::new(cargo)
.args(["install", "--locked", "--force", "--quiet"])
.arg("--root")
.arg(&tool_root_dir)
.arg("--target-dir")
.arg(tool_root_dir.join("target"))
.arg(format!("{pkg_name}@{version}"))
.env(
"PATH",
env::join_paths(
env::split_paths(&env::var("PATH").unwrap())
.chain(std::iter::once(tool_bin_dir.clone())),
)
.expect("build dir contains invalid char"),
)
.env("RUSTFLAGS", "-Copt-level=0")
.spawn()?
.wait()?;
if !cargo_exit_code.success() {
return Err(io::Error::other("cargo install failed"));
}
let bin_path = tool_bin_dir.join(bin_name);
assert!(
matches!(bin_path.try_exists(), Ok(true)),
"cargo install did not produce the expected binary"
);
eprintln!("finished building tool {bin_name}");
Ok(bin_path)
}
pub mod alphabetical;
pub mod bins;
pub mod debug_artifacts;

View File

@@ -184,6 +184,7 @@ fn main() {
&librustdoc_path,
&tools_path,
&npm,
&cargo,
bless,
extra_checks,
pos_args

View File

@@ -0,0 +1,27 @@
// Test that the `cs` prefix is (not) added into a `call` and a `jmp` to the
// indirect thunk when the `-Zindirect-branch-cs-prefix` flag is (not) set.
//@ revisions: unset set
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3 -Cunsafe-allow-abi-mismatch=retpoline,retpoline-external-thunk,indirect-branch-cs-prefix -Zretpoline-external-thunk
//@ [set] compile-flags: -Zindirect-branch-cs-prefix
//@ only-x86_64
//@ ignore-apple Symbol is called `___x86_indirect_thunk` (Darwin's extra underscore)
#![crate_type = "lib"]
// CHECK-LABEL: foo:
#[no_mangle]
pub fn foo(g: fn()) {
// unset-NOT: cs
// unset: callq {{__x86_indirect_thunk.*}}
// set: cs
// set-NEXT: callq {{__x86_indirect_thunk.*}}
g();
// unset-NOT: cs
// unset: jmp {{__x86_indirect_thunk.*}}
// set: cs
// set-NEXT: jmp {{__x86_indirect_thunk.*}}
g();
}

View File

@@ -0,0 +1,18 @@
// Test that the `indirect_branch_cs_prefix` module attribute is (not)
// emitted when the `-Zindirect-branch-cs-prefix` flag is (not) set.
//@ add-core-stubs
//@ revisions: unset set
//@ needs-llvm-components: x86
//@ compile-flags: --target x86_64-unknown-linux-gnu
//@ [set] compile-flags: -Zindirect-branch-cs-prefix
#![crate_type = "lib"]
#![feature(no_core, lang_items)]
#![no_core]
extern crate minicore;
use minicore::*;
// unset-NOT: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1}
// set: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1}

View File

@@ -1,4 +1,5 @@
//@ compile-flags: -Z unstable-options
//@ ignore-stage1
#![feature(rustc_private)]
#![deny(rustc::potential_query_instability)]
@@ -34,4 +35,16 @@ fn main() {
//~^ ERROR using `values_mut` can result in unstable query results
*val = *val + 10;
}
FxHashMap::<u32, i32>::default().extend(x);
//~^ ERROR using `into_iter` can result in unstable query results
}
fn hide_into_iter<T>(x: impl IntoIterator<Item = T>) -> impl Iterator<Item = T> {
x.into_iter()
}
fn take(map: std::collections::HashMap<i32, i32>) {
_ = hide_into_iter(map);
//~^ ERROR using `into_iter` can result in unstable query results
}

View File

@@ -1,18 +1,18 @@
error: using `drain` can result in unstable query results
--> $DIR/query_stability.rs:13:16
--> $DIR/query_stability.rs:14:16
|
LL | for _ in x.drain() {}
| ^^^^^
|
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
note: the lint level is defined here
--> $DIR/query_stability.rs:4:9
--> $DIR/query_stability.rs:5:9
|
LL | #![deny(rustc::potential_query_instability)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using `iter` can result in unstable query results
--> $DIR/query_stability.rs:16:16
--> $DIR/query_stability.rs:17:16
|
LL | for _ in x.iter() {}
| ^^^^
@@ -20,7 +20,7 @@ LL | for _ in x.iter() {}
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: using `iter_mut` can result in unstable query results
--> $DIR/query_stability.rs:19:36
--> $DIR/query_stability.rs:20:36
|
LL | for _ in Some(&mut x).unwrap().iter_mut() {}
| ^^^^^^^^
@@ -28,7 +28,7 @@ LL | for _ in Some(&mut x).unwrap().iter_mut() {}
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: using `into_iter` can result in unstable query results
--> $DIR/query_stability.rs:22:14
--> $DIR/query_stability.rs:23:14
|
LL | for _ in x {}
| ^
@@ -36,7 +36,7 @@ LL | for _ in x {}
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: using `keys` can result in unstable query results
--> $DIR/query_stability.rs:26:15
--> $DIR/query_stability.rs:27:15
|
LL | let _ = x.keys();
| ^^^^
@@ -44,7 +44,7 @@ LL | let _ = x.keys();
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: using `values` can result in unstable query results
--> $DIR/query_stability.rs:29:15
--> $DIR/query_stability.rs:30:15
|
LL | let _ = x.values();
| ^^^^^^
@@ -52,12 +52,28 @@ LL | let _ = x.values();
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: using `values_mut` can result in unstable query results
--> $DIR/query_stability.rs:33:18
--> $DIR/query_stability.rs:34:18
|
LL | for val in x.values_mut() {
| ^^^^^^^^^^
|
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: aborting due to 7 previous errors
error: using `into_iter` can result in unstable query results
--> $DIR/query_stability.rs:39:38
|
LL | FxHashMap::<u32, i32>::default().extend(x);
| ^^^^^^^^^
|
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: using `into_iter` can result in unstable query results
--> $DIR/query_stability.rs:48:9
|
LL | _ = hide_into_iter(map);
| ^^^^^^^^^^^^^^^^^^^
|
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
error: aborting due to 9 previous errors

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/8498
//@ run-pass
pub fn main() {

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/7784
//@ run-pass
use std::ops::Add;

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/78622
#![crate_type = "lib"]
struct S;

View File

@@ -1,5 +1,5 @@
error[E0223]: ambiguous associated type
--> $DIR/issue-78622.rs:5:5
--> $DIR/ambiguous-associated-type-error-78622.rs:6:5
|
LL | S::A::<f> {}
| ^^^^

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/78957
#![deny(unused_attributes)]
use std::marker::PhantomData;

View File

@@ -1,5 +1,5 @@
error: `#[inline]` attribute cannot be used on function params
--> $DIR/issue-78957.rs:5:16
--> $DIR/invalid-attributes-on-const-params-78957.rs:6:16
|
LL | pub struct Foo<#[inline] const N: usize>;
| ^^^^^^^^^
@@ -7,7 +7,7 @@ LL | pub struct Foo<#[inline] const N: usize>;
= help: `#[inline]` can only be applied to functions
error: `#[inline]` attribute cannot be used on function params
--> $DIR/issue-78957.rs:13:17
--> $DIR/invalid-attributes-on-const-params-78957.rs:14:17
|
LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
| ^^^^^^^^^
@@ -15,7 +15,7 @@ LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
= help: `#[inline]` can only be applied to functions
error: `#[inline]` attribute cannot be used on function params
--> $DIR/issue-78957.rs:21:17
--> $DIR/invalid-attributes-on-const-params-78957.rs:22:17
|
LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
| ^^^^^^^^^
@@ -23,25 +23,25 @@ LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
= help: `#[inline]` can only be applied to functions
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-78957.rs:10:23
--> $DIR/invalid-attributes-on-const-params-78957.rs:11:23
|
LL | pub struct Baz<#[repr(C)] const N: usize>;
| ^ -------------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-78957.rs:18:24
--> $DIR/invalid-attributes-on-const-params-78957.rs:19:24
|
LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>);
| ^ -- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-78957.rs:26:24
--> $DIR/invalid-attributes-on-const-params-78957.rs:27:24
|
LL | pub struct Baz3<#[repr(C)] T>(PhantomData<T>);
| ^ - not a struct, enum, or union
error: `#[cold]` attribute cannot be used on function params
--> $DIR/issue-78957.rs:7:16
--> $DIR/invalid-attributes-on-const-params-78957.rs:8:16
|
LL | pub struct Bar<#[cold] const N: usize>;
| ^^^^^^^
@@ -49,13 +49,13 @@ LL | pub struct Bar<#[cold] const N: usize>;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= help: `#[cold]` can only be applied to functions
note: the lint level is defined here
--> $DIR/issue-78957.rs:1:9
--> $DIR/invalid-attributes-on-const-params-78957.rs:2:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: `#[cold]` attribute cannot be used on function params
--> $DIR/issue-78957.rs:15:17
--> $DIR/invalid-attributes-on-const-params-78957.rs:16:17
|
LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
| ^^^^^^^
@@ -64,7 +64,7 @@ LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
= help: `#[cold]` can only be applied to functions
error: `#[cold]` attribute cannot be used on function params
--> $DIR/issue-78957.rs:23:17
--> $DIR/invalid-attributes-on-const-params-78957.rs:24:17
|
LL | pub struct Bar3<#[cold] T>(PhantomData<T>);
| ^^^^^^^

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/77218
//@ run-rustfix
fn main() {
let value = [7u8];

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/77218
//@ run-rustfix
fn main() {
let value = [7u8];

View File

@@ -1,5 +1,5 @@
error[E0070]: invalid left-hand side of assignment
--> $DIR/issue-77218.rs:4:19
--> $DIR/invalid-assignment-in-while-loop-77218.rs:5:19
|
LL | while Some(0) = value.get(0) {}
| - ^

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/78192
//@ run-pass
#![allow(unused_assignments)]

View File

@@ -1,9 +1,9 @@
// https://github.com/rust-lang/rust/issues/7660
//@ run-pass
#![allow(unused_variables)]
// Regression test for issue 7660
// rvalue lifetime too short when equivalent `match` works
use std::collections::HashMap;
struct A(isize, isize);

View File

@@ -6,6 +6,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
|
= note: expected values for `target_feature` are: `10e60`
`2e3`
`32s`
`3e3r1`
`3e3r2`
`3e3r3`

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/76042
//@ run-pass
//@ compile-flags: -Coverflow-checks=off -Ccodegen-units=1 -Copt-level=0

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/8248
//@ run-pass
trait A {

View File

@@ -1,5 +1,5 @@
warning: method `dummy` is never used
--> $DIR/issue-8248.rs:4:8
--> $DIR/mut-trait-coercion-8248.rs:5:8
|
LL | trait A {
| - method in this trait

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/8398
//@ check-pass
#![allow(dead_code)]

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/76191
// Regression test for diagnostic issue #76191
#![allow(non_snake_case)]

View File

@@ -1,11 +1,11 @@
error[E0080]: evaluation panicked: explicit panic
--> $DIR/issue-76191.rs:8:37
--> $DIR/const-range-matching-76191.rs:9:37
|
LL | const RANGE2: RangeInclusive<i32> = panic!();
| ^^^^^^^^ evaluation of `RANGE2` failed here
error[E0308]: mismatched types
--> $DIR/issue-76191.rs:14:9
--> $DIR/const-range-matching-76191.rs:15:9
|
LL | const RANGE: RangeInclusive<i32> = 0..=255;
| -------------------------------- constant defined here
@@ -27,7 +27,7 @@ LL + 0..=255 => {}
|
error[E0308]: mismatched types
--> $DIR/issue-76191.rs:16:9
--> $DIR/const-range-matching-76191.rs:17:9
|
LL | const RANGE2: RangeInclusive<i32> = panic!();
| --------------------------------- constant defined here

View File

@@ -1,11 +1,11 @@
// https://github.com/rust-lang/rust/issues/8259
//@ run-pass
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
//@ aux-build:issue-8259.rs
//@ aux-build:aux-8259.rs
extern crate issue_8259 as other;
extern crate aux_8259 as other;
static a: other::Foo<'static> = other::Foo::A;
pub fn main() {}

View File

@@ -0,0 +1,10 @@
// https://github.com/rust-lang/rust/issues/7899
//@ run-pass
#![allow(unused_variables)]
//@ aux-build:aux-7899.rs
extern crate aux_7899 as testcrate;
fn main() {
let f = testcrate::V2(1.0f32, 2.0f32);
}

View File

@@ -0,0 +1,7 @@
//@ run-pass
//@ aux-build:aux-8401.rs
// https://github.com/rust-lang/rust/issues/8401
extern crate aux_8401;
pub fn main() {}

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/8761
enum Foo {
A = 1i64,
//~^ ERROR mismatched types

View File

@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/issue-8761.rs:2:9
--> $DIR/enum-discriminant-type-mismatch-8761.rs:3:9
|
LL | A = 1i64,
| ^^^^ expected `isize`, found `i64`
@@ -11,7 +11,7 @@ LL + A = 1isize,
|
error[E0308]: mismatched types
--> $DIR/issue-8761.rs:5:9
--> $DIR/enum-discriminant-type-mismatch-8761.rs:6:9
|
LL | B = 2u8
| ^^^ expected `isize`, found `u8`

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/80607
// This tests makes sure the diagnostics print the offending enum variant, not just the type.
pub enum Enum {
V1(i32),

View File

@@ -1,5 +1,5 @@
error[E0559]: variant `Enum::V1` has no field named `x`
--> $DIR/issue-80607.rs:7:16
--> $DIR/enum-variant-field-error-80607.rs:8:16
|
LL | V1(i32),
| -- `Enum::V1` defined here

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/8506
//@ run-pass
#![allow(non_upper_case_globals)]

View File

@@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/75283
extern "C" {
fn lol() { //~ ERROR incorrect function inside `extern` block
println!("");

Some files were not shown because too many files have changed in this diff Show More