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:
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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`
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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, &[]),
|
||||
|
||||
@@ -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 two’s-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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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:
|
||||
///
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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",);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -1649,7 +1649,7 @@ function preLoadCss(cssUrl) {
|
||||
["⏎", "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"],
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -184,6 +184,7 @@ fn main() {
|
||||
&librustdoc_path,
|
||||
&tools_path,
|
||||
&npm,
|
||||
&cargo,
|
||||
bless,
|
||||
extra_checks,
|
||||
pos_args
|
||||
|
||||
27
tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs
Normal file
27
tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs
Normal 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();
|
||||
}
|
||||
18
tests/codegen-llvm/indirect-branch-cs-prefix.rs
Normal file
18
tests/codegen-llvm/indirect-branch-cs-prefix.rs
Normal 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}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/8498
|
||||
//@ run-pass
|
||||
|
||||
pub fn main() {
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/7784
|
||||
//@ run-pass
|
||||
|
||||
use std::ops::Add;
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/78622
|
||||
#![crate_type = "lib"]
|
||||
|
||||
struct S;
|
||||
@@ -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> {}
|
||||
| ^^^^
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/78957
|
||||
#![deny(unused_attributes)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
@@ -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>);
|
||||
| ^^^^^^^
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/77218
|
||||
//@ run-rustfix
|
||||
fn main() {
|
||||
let value = [7u8];
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/77218
|
||||
//@ run-rustfix
|
||||
fn main() {
|
||||
let value = [7u8];
|
||||
@@ -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) {}
|
||||
| - ^
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/78192
|
||||
//@ run-pass
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
@@ -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);
|
||||
@@ -6,6 +6,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
|
||||
|
|
||||
= note: expected values for `target_feature` are: `10e60`
|
||||
`2e3`
|
||||
`32s`
|
||||
`3e3r1`
|
||||
`3e3r2`
|
||||
`3e3r3`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/8248
|
||||
//@ run-pass
|
||||
|
||||
trait A {
|
||||
@@ -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
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/8398
|
||||
//@ check-pass
|
||||
#![allow(dead_code)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/76191
|
||||
// Regression test for diagnostic issue #76191
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
@@ -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
|
||||
@@ -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() {}
|
||||
10
tests/ui/cross-crate/tuple-like-structs-cross-crate-7899.rs
Normal file
10
tests/ui/cross-crate/tuple-like-structs-cross-crate-7899.rs
Normal 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);
|
||||
}
|
||||
@@ -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() {}
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/8761
|
||||
enum Foo {
|
||||
A = 1i64,
|
||||
//~^ ERROR mismatched types
|
||||
@@ -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`
|
||||
@@ -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),
|
||||
@@ -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
|
||||
@@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/8506
|
||||
//@ run-pass
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user