Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-09-12 05:15:02 +00:00
commit 93ef7cd2dd
152 changed files with 1903 additions and 2047 deletions

View file

@ -2418,11 +2418,22 @@ impl InlineAsmOperand {
}
}
#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum AsmMacro {
/// The `asm!` macro
Asm,
/// The `global_asm!` macro
GlobalAsm,
/// The `naked_asm!` macro
NakedAsm,
}
/// Inline assembly.
///
/// E.g., `asm!("NOP");`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct InlineAsm {
pub asm_macro: AsmMacro,
pub template: Vec<InlineAsmTemplatePiece>,
pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
pub operands: Vec<(InlineAsmOperand, Span)>,

View file

@ -153,7 +153,7 @@ impl HasTokens for StmtKind {
StmtKind::Let(local) => local.tokens.as_ref(),
StmtKind::Item(item) => item.tokens(),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
StmtKind::Empty => return None,
StmtKind::Empty => None,
StmtKind::MacCall(mac) => mac.tokens.as_ref(),
}
}
@ -162,7 +162,7 @@ impl HasTokens for StmtKind {
StmtKind::Let(local) => Some(&mut local.tokens),
StmtKind::Item(item) => item.tokens_mut(),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
StmtKind::Empty => return None,
StmtKind::Empty => None,
StmtKind::MacCall(mac) => Some(&mut mac.tokens),
}
}

View file

@ -1388,6 +1388,7 @@ fn walk_anon_const<T: MutVisitor>(vis: &mut T, AnonConst { id, value }: &mut Ano
fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) {
// FIXME: Visit spans inside all this currently ignored stuff.
let InlineAsm {
asm_macro: _,
template: _,
template_strs: _,
operands,

View file

@ -976,6 +976,7 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo
pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result {
let InlineAsm {
asm_macro: _,
template: _,
template_strs: _,
operands,

View file

@ -474,8 +474,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
let line_spans =
self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span)));
let hir_asm =
hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
let hir_asm = hir::InlineAsm {
asm_macro: asm.asm_macro,
template,
template_strs,
operands,
options: asm.options,
line_spans,
};
self.arena.alloc(hir_asm)
}
}

View file

@ -1837,7 +1837,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
Safety::Default,
sym::allow,
sym::unreachable_code,
self.lower_span(span),
try_span,
);
let attrs: AttrVec = thin_vec![attr];

View file

@ -1240,5 +1240,5 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
candidates.push(meta_lit.symbol);
}
return Some(candidates);
Some(candidates)
}

View file

@ -3669,7 +3669,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
reinits.push(location);
return true;
}
return false;
false
};
while let Some(location) = stack.pop() {

View file

@ -214,7 +214,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
let delegate = FnMutDelegate {
regions: &mut |br: ty::BoundRegion| {
if let Some(ex_reg_var) = reg_map.get(&br) {
return *ex_reg_var;
*ex_reg_var
} else {
let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name());
debug!(?ex_reg_var);

View file

@ -3,6 +3,7 @@ use lint::BuiltinLintDiag;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::AsmMacro;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::PResult;
use rustc_expand::base::*;
@ -484,6 +485,7 @@ fn parse_reg<'a>(
fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>,
asm_macro: ast::AsmMacro,
args: AsmArgs,
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
let mut template = vec![];
@ -774,6 +776,7 @@ fn expand_preparsed_asm(
}
ExpandResult::Ready(Ok(ast::InlineAsm {
asm_macro,
template,
template_strs: template_strs.into_boxed_slice(),
operands: args.operands,
@ -790,7 +793,7 @@ pub(super) fn expand_asm<'cx>(
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
return ExpandResult::Retry(());
};
let expr = match mac {
@ -819,7 +822,8 @@ pub(super) fn expand_naked_asm<'cx>(
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
else {
return ExpandResult::Retry(());
};
let expr = match mac {
@ -857,7 +861,8 @@ pub(super) fn expand_global_asm<'cx>(
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
else {
return ExpandResult::Retry(());
};
match mac {

View file

@ -277,6 +277,8 @@ pub(crate) fn expand_test_or_bench(
cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
// #[rustc_test_marker = "test_case_sort_key"]
cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
// #[doc(hidden)]
cx.attr_nested_word(sym::doc, sym::hidden, attr_sp),
],
// const $ident: test::TestDescAndFn =
ast::ItemKind::Const(

View file

@ -326,8 +326,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
let main_attr = ecx.attr_word(sym::rustc_main, sp);
// #[coverage(off)]
let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp);
// #[allow(missing_docs)]
let missing_docs_attr = ecx.attr_nested_word(sym::allow, sym::missing_docs, sp);
// #[doc(hidden)]
let doc_hidden_attr = ecx.attr_nested_word(sym::doc, sym::hidden, sp);
// pub fn main() { ... }
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new()));
@ -357,7 +357,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
let main = P(ast::Item {
ident: main_id,
attrs: thin_vec![main_attr, coverage_attr, missing_docs_attr],
attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr],
id: ast::DUMMY_NODE_ID,
kind: main,
vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },

View file

@ -290,7 +290,7 @@ pub(crate) fn check_tied_features(
}
}
}
return None;
None
}
/// Used to generate cfg variables and apply features

View file

@ -438,7 +438,7 @@ fn link_rlib<'a>(
ab.add_file(&lib)
}
return Ok(ab);
Ok(ab)
}
/// Extract all symbols defined in raw-dylib libraries, collated by library name.
@ -1319,7 +1319,7 @@ fn link_sanitizer_runtime(
fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
let path = sess.target_tlib_path.dir.join(filename);
if path.exists() {
return sess.target_tlib_path.dir.clone();
sess.target_tlib_path.dir.clone()
} else {
let default_sysroot =
filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
@ -1327,7 +1327,7 @@ fn link_sanitizer_runtime(
&default_sysroot,
sess.opts.target_triple.triple(),
);
return default_tlib;
default_tlib
}
}

View file

@ -1484,7 +1484,6 @@ impl<'a> Linker for L4Bender<'a> {
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
// ToDo, not implemented, copy from GCC
self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
return;
}
fn subsystem(&mut self, subsystem: &str) {

View file

@ -171,10 +171,10 @@ pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a
"Metadata at offset {offset} with size {len} is beyond .info section"
));
}
return Ok(&info_data[offset..(offset + len)]);
Ok(&info_data[offset..(offset + len)])
} else {
return Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}"));
};
Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}"))
}
}
pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
@ -413,7 +413,7 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach
/// Is Apple's CPU subtype `arm64e`s
fn macho_is_arm64e(target: &Target) -> bool {
return target.llvm_target.starts_with("arm64e");
target.llvm_target.starts_with("arm64e")
}
pub enum MetadataPosition {

View file

@ -235,13 +235,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if self.layout_compat(caller_abi.layout, callee_abi.layout)? {
// Ensure that our checks imply actual ABI compatibility for this concrete call.
assert!(caller_abi.eq_abi(callee_abi));
return Ok(true);
Ok(true)
} else {
trace!(
"check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
caller_abi, callee_abi
);
return Ok(false);
Ok(false)
}
}

View file

@ -433,6 +433,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
Ok(self.offset_(offset, layout, ecx))
}
#[inline(always)]
fn to_op<M: Machine<'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'tcx, M>,
@ -522,6 +523,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
}
}
#[inline(always)]
fn to_op<M: Machine<'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'tcx, M>,

View file

@ -303,8 +303,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let pointee_layout = self.layout_of(pointee_ty)?;
assert!(pointee_layout.abi.is_sized());
// We cannot overflow i64 as a type's size must be <= isize::MAX.
// The size always fits in `i64` as it can be at most `isize::MAX`.
let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
// This uses the same type as `right`, which can be `isize` or `usize`.
// `pointee_size` is guaranteed to fit into both types.
let pointee_size = ImmTy::from_int(pointee_size, right.layout);
// Multiply element size and element count.
let (val, overflowed) = self
@ -316,6 +318,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
let offset_bytes = val.to_target_isize(self)?;
if !right.layout.abi.is_signed() && offset_bytes < 0 {
// We were supposed to do an unsigned offset but the result is negative -- this
// can only mean that the cast wrapped around.
throw_ub!(PointerArithOverflow)
}
let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout))
}

View file

@ -166,6 +166,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout })
}
#[inline(always)]
fn to_op<M: Machine<'tcx, Provenance = Prov>>(
&self,
_ecx: &InterpCx<'tcx, M>,
@ -299,6 +300,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
})
}
#[inline(always)]
fn to_op<M: Machine<'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'tcx, M>,
@ -560,6 +562,7 @@ where
/// Given a place, returns either the underlying mplace or a reference to where the value of
/// this place is stored.
#[inline(always)]
fn as_mplace_or_mutable_local(
&mut self,
place: &PlaceTy<'tcx, M::Provenance>,

View file

@ -8,11 +8,11 @@ use std::thread::panicking;
use rustc_data_structures::fx::FxIndexMap;
use rustc_error_messages::{fluent_value_from_str_list_sep_by_and, FluentValue};
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_lint_defs::Applicability;
use rustc_macros::{Decodable, Encodable};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use rustc_span::{AttrId, Span, DUMMY_SP};
use rustc_span::{Span, DUMMY_SP};
use tracing::debug;
use crate::snippet::Style;
@ -354,26 +354,6 @@ impl DiagInner {
}
}
pub(crate) fn update_unstable_expectation_id(
&mut self,
unstable_to_stable: &FxIndexMap<AttrId, LintExpectationId>,
) {
if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) =
&mut self.level
&& let LintExpectationId::Unstable { attr_id, lint_index } = *expectation_id
{
// The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
// The lint index inside the attribute is manually transferred here.
let Some(stable_id) = unstable_to_stable.get(&attr_id) else {
panic!("{expectation_id:?} must have a matching stable id")
};
let mut stable_id = *stable_id;
stable_id.set_lint_index(lint_index);
*expectation_id = stable_id;
}
}
/// Indicates whether this diagnostic should show up in cargo's future breakage report.
pub(crate) fn has_future_breakage(&self) -> bool {
matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))

View file

@ -69,7 +69,7 @@ use rustc_macros::{Decodable, Encodable};
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
use rustc_span::source_map::SourceMap;
pub use rustc_span::ErrorGuaranteed;
use rustc_span::{AttrId, Loc, Span, DUMMY_SP};
use rustc_span::{Loc, Span, DUMMY_SP};
pub use snippet::Style;
// Used by external projects such as `rust-gpu`.
// See https://github.com/rust-lang/rust/pull/115393.
@ -497,28 +497,18 @@ struct DiagCtxtInner {
future_breakage_diagnostics: Vec<DiagInner>,
/// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
/// dropped. However, it can have values if the compilation is stopped early
/// or is only partially executed. To avoid ICEs, like in rust#94953 we only
/// check if [`Self::unstable_expect_diagnostics`] is empty, if the expectation ids
/// have been converted.
check_unstable_expect_diagnostics: bool,
/// Expected [`DiagInner`][struct@diagnostic::DiagInner]s store a [`LintExpectationId`] as part
/// of the lint level. [`LintExpectationId`]s created early during the compilation
/// (before `HirId`s have been defined) are not stable and can therefore not be
/// stored on disk. This buffer stores these diagnostics until the ID has been
/// replaced by a stable [`LintExpectationId`]. The [`DiagInner`][struct@diagnostic::DiagInner]s
/// are submitted for storage and added to the list of fulfilled expectations.
unstable_expect_diagnostics: Vec<DiagInner>,
/// expected diagnostic will have the level `Expect` which additionally
/// carries the [`LintExpectationId`] of the expectation that can be
/// marked as fulfilled. This is a collection of all [`LintExpectationId`]s
/// that have been marked as fulfilled this way.
///
/// Emitting expectations after having stolen this field can happen. In particular, an
/// `#[expect(warnings)]` can easily make the `UNFULFILLED_LINT_EXPECTATIONS` lint expect
/// itself. To avoid needless complexity in this corner case, we tolerate failing to track
/// those expectations.
///
/// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html
fulfilled_expectations: FxHashSet<LintExpectationId>,
fulfilled_expectations: FxIndexSet<LintExpectationId>,
/// The file where the ICE information is stored. This allows delayed_span_bug backtraces to be
/// stored along side the main panic backtrace.
@ -605,13 +595,6 @@ impl Drop for DiagCtxtInner {
);
}
}
if self.check_unstable_expect_diagnostics {
assert!(
self.unstable_expect_diagnostics.is_empty(),
"all diagnostics with unstable expectations should have been converted",
);
}
}
}
@ -740,8 +723,6 @@ impl DiagCtxt {
emitted_diagnostics,
stashed_diagnostics,
future_breakage_diagnostics,
check_unstable_expect_diagnostics,
unstable_expect_diagnostics,
fulfilled_expectations,
ice_file: _,
} = inner.deref_mut();
@ -761,8 +742,6 @@ impl DiagCtxt {
*emitted_diagnostics = Default::default();
*stashed_diagnostics = Default::default();
*future_breakage_diagnostics = Default::default();
*check_unstable_expect_diagnostics = false;
*unstable_expect_diagnostics = Default::default();
*fulfilled_expectations = Default::default();
}
@ -1094,44 +1073,10 @@ impl<'a> DiagCtxtHandle<'a> {
inner.emitter.emit_unused_externs(lint_level, unused_externs)
}
pub fn update_unstable_expectation_id(
&self,
unstable_to_stable: FxIndexMap<AttrId, LintExpectationId>,
) {
let mut inner = self.inner.borrow_mut();
let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
inner.check_unstable_expect_diagnostics = true;
if !diags.is_empty() {
inner.suppressed_expected_diag = true;
for mut diag in diags.into_iter() {
diag.update_unstable_expectation_id(&unstable_to_stable);
// Here the diagnostic is given back to `emit_diagnostic` where it was first
// intercepted. Now it should be processed as usual, since the unstable expectation
// id is now stable.
inner.emit_diagnostic(diag, self.tainted_with_errors);
}
}
inner
.stashed_diagnostics
.values_mut()
.for_each(|(diag, _guar)| diag.update_unstable_expectation_id(&unstable_to_stable));
inner
.future_breakage_diagnostics
.iter_mut()
.for_each(|diag| diag.update_unstable_expectation_id(&unstable_to_stable));
}
/// This methods steals all [`LintExpectationId`]s that are stored inside
/// [`DiagCtxtInner`] and indicate that the linked expectation has been fulfilled.
#[must_use]
pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
assert!(
self.inner.borrow().unstable_expect_diagnostics.is_empty(),
"`DiagCtxtInner::unstable_expect_diagnostics` should be empty at this point",
);
pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
}
@ -1440,8 +1385,6 @@ impl DiagCtxtInner {
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
check_unstable_expect_diagnostics: false,
unstable_expect_diagnostics: Vec::new(),
fulfilled_expectations: Default::default(),
ice_file: None,
}
@ -1471,24 +1414,6 @@ impl DiagCtxtInner {
mut diagnostic: DiagInner,
taint: Option<&Cell<Option<ErrorGuaranteed>>>,
) -> Option<ErrorGuaranteed> {
match diagnostic.level {
Expect(expect_id) | ForceWarning(Some(expect_id)) => {
// The `LintExpectationId` can be stable or unstable depending on when it was
// created. Diagnostics created before the definition of `HirId`s are unstable and
// can not yet be stored. Instead, they are buffered until the `LintExpectationId`
// is replaced by a stable one by the `LintLevelsBuilder`.
if let LintExpectationId::Unstable { .. } = expect_id {
// We don't call TRACK_DIAGNOSTIC because we wait for the
// unstable ID to be updated, whereupon the diagnostic will be
// passed into this method again.
self.unstable_expect_diagnostics.push(diagnostic);
return None;
}
// Continue through to the `Expect`/`ForceWarning` case below.
}
_ => {}
}
if diagnostic.has_future_breakage() {
// Future breakages aren't emitted if they're `Level::Allow` or
// `Level::Expect`, but they still need to be constructed and
@ -1564,9 +1489,6 @@ impl DiagCtxtInner {
return None;
}
Expect(expect_id) | ForceWarning(Some(expect_id)) => {
if let LintExpectationId::Unstable { .. } = expect_id {
unreachable!(); // this case was handled at the top of this function
}
self.fulfilled_expectations.insert(expect_id);
if let Expect(_) = diagnostic.level {
// Nothing emitted here for expected lints.

View file

@ -773,18 +773,20 @@ fn extract_symbol_from_pnr<'a>(
match pnr {
ParseNtResult::Ident(nt_ident, is_raw) => {
if let IdentIsRaw::Yes = is_raw {
return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR));
Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR))
} else {
Ok(nt_ident.name)
}
return Ok(nt_ident.name);
}
ParseNtResult::Tt(TokenTree::Token(
Token { kind: TokenKind::Ident(symbol, is_raw), .. },
_,
)) => {
if let IdentIsRaw::Yes = is_raw {
return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR));
Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR))
} else {
Ok(*symbol)
}
return Ok(*symbol);
}
ParseNtResult::Tt(TokenTree::Token(
Token {
@ -792,15 +794,13 @@ fn extract_symbol_from_pnr<'a>(
..
},
_,
)) => {
return Ok(*symbol);
}
)) => Ok(*symbol),
ParseNtResult::Nt(nt)
if let Nonterminal::NtLiteral(expr) = &**nt
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) =
&expr.kind =>
{
return Ok(*symbol);
Ok(*symbol)
}
_ => Err(dcx
.struct_err(

View file

@ -2927,6 +2927,7 @@ impl<'hir> InlineAsmOperand<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct InlineAsm<'hir> {
pub asm_macro: ast::AsmMacro,
pub template: &'hir [InlineAsmTemplatePiece],
pub template_strs: &'hir [(Symbol, Option<Symbol>, Span)],
pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],

View file

@ -1038,7 +1038,7 @@ fn report_trait_method_mismatch<'tcx>(
false,
);
return diag.emit();
diag.emit()
}
fn check_region_bounds_on_impl_item<'tcx>(

View file

@ -274,7 +274,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
return false;
}
return true;
true
})
.collect::<Vec<_>>();

View file

@ -389,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
// check that the `if` expr without `else` is the fn body's expr
if expr.span == sp {
return self.get_fn_decl(hir_id).map(|(_, fn_decl, _)| {
return self.get_fn_decl(hir_id).map(|(_, fn_decl)| {
let (ty, span) = match fn_decl.output {
hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span),
hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span),

View file

@ -605,7 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Abi::Rust,
));
return Some(ExpectedSig { cause_span, sig });
Some(ExpectedSig { cause_span, sig })
}
fn sig_of_closure(

View file

@ -1860,10 +1860,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
};
// If this is due to an explicit `return`, suggest adding a return type.
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(block_or_return_id)
if let Some((fn_id, fn_decl)) = fcx.get_fn_decl(block_or_return_id)
&& !due_to_block
{
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, fn_id);
}
// If this is due to a block, then maybe we forgot a `return`/`break`.

View file

@ -1042,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true;
}
}
return false;
false
}
fn explain_self_literal(

View file

@ -774,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.ret_coercion_span.set(Some(expr.span));
}
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
if let Some((_, fn_decl)) = self.get_fn_decl(expr.hir_id) {
coercion.coerce_forced_unit(
self,
&cause,

View file

@ -30,7 +30,7 @@ use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym};
use rustc_span::symbol::kw;
use rustc_span::Span;
use rustc_target::abi::FieldIdx;
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
@ -859,38 +859,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
}
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
/// suggestion can be made, `None` otherwise.
/// Given a `HirId`, return the `HirId` of the enclosing function and its `FnDecl`.
pub(crate) fn get_fn_decl(
&self,
blk_id: HirId,
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>)> {
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
// `while` before reaching it, as block tail returns are not available in them.
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
match self.tcx.hir_node(item_id) {
Node::Item(&hir::Item {
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
owner_id,
..
}) => {
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
// but it will still present it as the reason for the expected type.
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
}
kind: hir::ItemKind::Fn(ref sig, ..), owner_id, ..
}) => Some((owner_id.def_id, sig.decl)),
Node::TraitItem(&hir::TraitItem {
kind: hir::TraitItemKind::Fn(ref sig, ..),
owner_id,
..
}) => Some((owner_id.def_id, sig.decl, true)),
// FIXME: Suggestable if this is not a trait implementation
}) => Some((owner_id.def_id, sig.decl)),
Node::ImplItem(&hir::ImplItem {
kind: hir::ImplItemKind::Fn(ref sig, ..),
owner_id,
..
}) => Some((owner_id.def_id, sig.decl, false)),
}) => Some((owner_id.def_id, sig.decl)),
Node::Expr(&hir::Expr {
hir_id,
kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
@ -901,33 +891,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME(async_closures): Implement this.
return None;
}
hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
hir::ClosureKind::Closure => Some((def_id, fn_decl)),
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
_,
hir::CoroutineSource::Fn,
)) => {
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
let (sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
Node::Item(&hir::Item {
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
owner_id,
..
}) => (ident, sig, owner_id),
}) => (sig, owner_id),
Node::TraitItem(&hir::TraitItem {
ident,
kind: hir::TraitItemKind::Fn(ref sig, ..),
owner_id,
..
}) => (ident, sig, owner_id),
}) => (sig, owner_id),
Node::ImplItem(&hir::ImplItem {
ident,
kind: hir::ImplItemKind::Fn(ref sig, ..),
owner_id,
..
}) => (ident, sig, owner_id),
}) => (sig, owner_id),
_ => return None,
};
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
Some((owner_id.def_id, sig.decl))
}
_ => None,
}

View file

@ -307,7 +307,7 @@ impl<'tcx> ArgMatrix<'tcx> {
permutation.into_iter().map(|x| x.unwrap()).collect();
return Some(Issue::Permutation(final_permutation));
}
return None;
None
}
// Obviously, detecting exact user intention is impossible, so the goal here is to
@ -410,6 +410,6 @@ impl<'tcx> ArgMatrix<'tcx> {
// sort errors with same type by the order they appear in the source
// so that suggestion will be handled properly, see #112507
errors.sort();
return (errors, matched_inputs);
(errors, matched_inputs)
}
}

View file

@ -1873,7 +1873,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// that highlight errors inline.
let mut sp = blk.span;
let mut fn_span = None;
if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
if let Some((fn_def_id, decl)) = self.get_fn_decl(blk.hir_id) {
let ret_sp = decl.output.span();
if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
// HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the

View file

@ -79,9 +79,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// `break` type mismatches provide better context for tail `loop` expressions.
return false;
}
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) {
pointing_at_return_type =
self.suggest_missing_return_type(err, fn_decl, expected, found, can_suggest, fn_id);
self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id);
self.suggest_missing_break_or_return_expr(
err, expr, fn_decl, expected, found, blk_id, fn_id,
);
@ -813,7 +813,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_decl: &hir::FnDecl<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
can_suggest: bool,
fn_id: LocalDefId,
) -> bool {
// Can't suggest `->` on a block-like coroutine
@ -826,28 +825,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let found =
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
// Only suggest changing the return type for methods that
// haven't set a return type at all (and aren't `fn main()` or an impl).
// haven't set a return type at all (and aren't `fn main()`, impl or closure).
match &fn_decl.output {
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
// `fn main()` must return `()`, do not suggest changing return type
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
return true;
}
// For closure with default returns, don't suggest adding return type
&hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {}
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
if let Some(found) = found.make_suggestable(self.tcx, false, None) {
if !self.can_add_return_type(fn_id) {
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
} else if let Some(found) = found.make_suggestable(self.tcx, false, None) {
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
span,
found: found.to_string(),
});
return true;
} else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg });
return true;
} else {
// FIXME: if `found` could be `impl Iterator` we should suggest that.
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
return true;
}
return true;
}
hir::FnRetTy::Return(hir_ty) => {
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
@ -905,6 +902,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
/// Checks whether we can add a return type to a function.
/// Assumes given function doesn't have a explicit return type.
fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
match self.tcx.hir_node_by_def_id(fn_id) {
Node::Item(&hir::Item { ident, .. }) => {
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
// but it will still present it as the reason for the expected type.
ident.name != sym::main
}
Node::ImplItem(item) => {
// If it doesn't impl a trait, we can add a return type
let Node::Item(&hir::Item {
kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }),
..
}) = self.tcx.parent_hir_node(item.hir_id())
else {
unreachable!();
};
of_trait.is_none()
}
_ => true,
}
}
fn try_note_caller_chooses_ty_for_ty_param(
&self,
diag: &mut Diag<'_>,
@ -2028,7 +2051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
return true;
true
}
pub(crate) fn suggest_coercing_result_via_try_operator(

View file

@ -43,7 +43,7 @@ pub use coercion::can_coerce;
use fn_ctxt::FnCtxt;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed};
use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
@ -423,6 +423,36 @@ fn report_unexpected_variant_res(
err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
err
}
Res::Def(DefKind::Variant, _) if expr.is_none() => {
err.span_label(span, format!("not a {expected}"));
let fields = &tcx.expect_variant_res(res).fields.raw;
let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi());
let (msg, sugg) = if fields.is_empty() {
("use the struct variant pattern syntax".to_string(), " {}".to_string())
} else {
let msg = format!(
"the struct variant's field{s} {are} being ignored",
s = pluralize!(fields.len()),
are = pluralize!("is", fields.len())
);
let fields = fields
.iter()
.map(|field| format!("{}: _", field.name.to_ident_string()))
.collect::<Vec<_>>()
.join(", ");
let sugg = format!(" {{ {} }}", fields);
(msg, sugg)
};
err.span_suggestion_verbose(
qpath.span().shrink_to_hi().to(span.shrink_to_hi()),
msg,
sugg,
Applicability::HasPlaceholders,
);
err
}
_ => err.with_span_label(span, format!("not a {expected}")),
}
.emit()

View file

@ -1317,7 +1317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
let mut long_ty_file = None;
let (primary_message, label) = if unimplemented_traits.len() == 1
let (primary_message, label, notes) = if unimplemented_traits.len() == 1
&& unimplemented_traits_only
{
unimplemented_traits
@ -1327,16 +1327,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
{
// Avoid crashing.
return (None, None);
return (None, None, Vec::new());
}
let OnUnimplementedNote { message, label, .. } = self
let OnUnimplementedNote { message, label, notes, .. } = self
.err_ctxt()
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
(message, label)
(message, label, notes)
})
.unwrap()
} else {
(None, None)
(None, None, Vec::new())
};
let primary_message = primary_message.unwrap_or_else(|| {
format!(
@ -1363,6 +1363,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"the following trait bounds were not satisfied:\n{bound_list}"
));
}
for note in notes {
err.note(note);
}
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
unsatisfied_bounds = true;

View file

@ -1481,7 +1481,7 @@ impl<'tcx> InferCtxt<'tcx> {
// This hoists the borrow/release out of the loop body.
let inner = self.inner.try_borrow();
return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) {
move |infer_var: TyOrConstInferVar| match (infer_var, &inner) {
(TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
use self::type_variable::TypeVariableValue;
@ -1491,7 +1491,7 @@ impl<'tcx> InferCtxt<'tcx> {
)
}
_ => false,
};
}
}
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:

View file

@ -259,11 +259,11 @@ impl<'tcx> InferCtxt<'tcx> {
structurally_relate_aliases,
root_vid,
for_universe,
ambient_variance,
root_term: source_term.into(),
ambient_variance,
in_alias: false,
has_unconstrained_ty_var: false,
cache: Default::default(),
has_unconstrained_ty_var: false,
};
let value_may_be_infer = generalizer.relate(source_term, source_term)?;
@ -304,14 +304,12 @@ struct Generalizer<'me, 'tcx> {
/// we reject the relation.
for_universe: ty::UniverseIndex,
/// After we generalize this type, we are going to relate it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
/// The root term (const or type) we're generalizing. Used for cycle errors.
root_term: Term<'tcx>,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
/// After we generalize this type, we are going to relate it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
/// This is set once we're generalizing the arguments of an alias.
///
@ -320,6 +318,8 @@ struct Generalizer<'me, 'tcx> {
/// hold by either normalizing the outer or the inner associated type.
in_alias: bool,
cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
/// See the field `has_unconstrained_ty_var` in `Generalization`.
has_unconstrained_ty_var: bool,
}
@ -451,7 +451,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
if let Some(&result) = self.cache.get(&t) {
if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
return Ok(result);
}
@ -557,7 +557,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
_ => relate::structurally_relate_tys(self, t, t),
}?;
self.cache.insert(t, g);
self.cache.insert((t, self.ambient_variance, self.in_alias), g);
Ok(g)
}

View file

@ -1,10 +1,10 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::{HirId, CRATE_OWNER_ID};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::CRATE_OWNER_ID;
use rustc_middle::lint::LintExpectation;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
use rustc_session::lint::{Level, LintExpectationId};
use rustc_session::lint::LintExpectationId;
use rustc_span::Symbol;
use crate::lints::{Expectation, ExpectationNote};
@ -17,43 +17,12 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
let krate = tcx.hir_crate_items(());
let mut expectations = Vec::new();
let mut unstable_to_stable_ids = FxIndexMap::default();
let mut record_stable = |attr_id, hir_id, attr_index| {
let expect_id = LintExpectationId::Stable { hir_id, attr_index, lint_index: None };
unstable_to_stable_ids.entry(attr_id).or_insert(expect_id);
};
let mut push_expectations = |owner| {
for owner in std::iter::once(CRATE_OWNER_ID).chain(krate.owners()) {
let lints = tcx.shallow_lint_levels_on(owner);
if lints.expectations.is_empty() {
return;
}
expectations.extend_from_slice(&lints.expectations);
let attrs = tcx.hir_attrs(owner);
for &(local_id, attrs) in attrs.map.iter() {
// Some attributes appear multiple times in HIR, to ensure they are correctly taken
// into account where they matter. This means we cannot just associate the AttrId to
// the first HirId where we see it, but need to check it actually appears in a lint
// level.
// FIXME(cjgillot): Can this cause an attribute to appear in multiple expectation ids?
if !lints.specs.contains_key(&local_id) {
continue;
}
for (attr_index, attr) in attrs.iter().enumerate() {
let Some(Level::Expect(_)) = Level::from_attr(attr) else { continue };
record_stable(attr.id, HirId { owner, local_id }, attr_index.try_into().unwrap());
}
}
};
push_expectations(CRATE_OWNER_ID);
for owner in krate.owners() {
push_expectations(owner);
}
tcx.dcx().update_unstable_expectation_id(unstable_to_stable_ids);
expectations
}
@ -61,24 +30,43 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
let lint_expectations = tcx.lint_expectations(());
let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids();
for (id, expectation) in lint_expectations {
// This check will always be true, since `lint_expectations` only
// holds stable ids
if let LintExpectationId::Stable { hir_id, .. } = id {
if !fulfilled_expectations.contains(id)
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
{
let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
let note = expectation.is_unfulfilled_lint_expectations;
tcx.emit_node_span_lint(
UNFULFILLED_LINT_EXPECTATIONS,
*hir_id,
expectation.emission_span,
Expectation { rationale, note },
);
// Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair.
let canonicalize_id = |expect_id: &LintExpectationId| {
match *expect_id {
LintExpectationId::Unstable { attr_id, lint_index: Some(lint_index) } => {
(attr_id, lint_index)
}
} else {
LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
// We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id;
(attr_id, lint_index)
}
_ => panic!("fulfilled expectations must have a lint index"),
}
};
let fulfilled_expectations: FxHashSet<_> =
fulfilled_expectations.iter().map(canonicalize_id).collect();
for (expect_id, expectation) in lint_expectations {
// This check will always be true, since `lint_expectations` only holds stable ids
let LintExpectationId::Stable { hir_id, .. } = expect_id else {
unreachable!("at this stage all `LintExpectationId`s are stable");
};
let expect_id = canonicalize_id(expect_id);
if !fulfilled_expectations.contains(&expect_id)
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
{
let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
let note = expectation.is_unfulfilled_lint_expectations;
tcx.emit_node_span_lint(
UNFULFILLED_LINT_EXPECTATIONS,
*hir_id,
expectation.emission_span,
Expectation { rationale, note },
);
}
}
}

View file

@ -133,7 +133,7 @@ fn extract_iterator_next_call<'tcx>(
{
Some(recv)
} else {
return None;
None
}
}

View file

@ -71,7 +71,7 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
debug_assert_ne!(parent_id, self.current_id);
self.current_id = parent_id;
return Some(parent_id);
Some(parent_id)
}
}
@ -103,7 +103,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
self.current_id = HirId::make_owner(parent_id.def_id);
let node = self.map.tcx.hir_owner_node(self.current_id.owner);
return Some((self.current_id.owner, node));
Some((self.current_id.owner, node))
}
}
@ -1233,14 +1233,14 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
body_owners,
..
} = collector;
return ModuleItems {
ModuleItems {
submodules: submodules.into_boxed_slice(),
free_items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
impl_items: impl_items.into_boxed_slice(),
foreign_items: foreign_items.into_boxed_slice(),
body_owners: body_owners.into_boxed_slice(),
};
}
}
pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
@ -1262,14 +1262,14 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
..
} = collector;
return ModuleItems {
ModuleItems {
submodules: submodules.into_boxed_slice(),
free_items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
impl_items: impl_items.into_boxed_slice(),
foreign_items: foreign_items.into_boxed_slice(),
body_owners: body_owners.into_boxed_slice(),
};
}
}
struct ItemCollector<'tcx> {

View file

@ -641,7 +641,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
self.mark_init(range, false);
self.provenance.clear(range, cx)?;
return Ok(());
Ok(())
}
/// Remove all provenance in the given memory range.

View file

@ -1166,10 +1166,9 @@ impl<'tcx> LocalDecl<'tcx> {
/// Returns `true` if this is a DerefTemp
pub fn is_deref_temp(&self) -> bool {
match self.local_info() {
LocalInfo::DerefTemp => return true,
_ => (),
LocalInfo::DerefTemp => true,
_ => false,
}
return false;
}
/// Returns `true` is the local is from a compiler desugaring, e.g.,

View file

@ -2007,7 +2007,7 @@ impl<'tcx> TyCtxt<'tcx> {
));
}
}
return None;
None
}
/// Checks if the bound region is in Impl Item.

View file

@ -431,7 +431,7 @@ impl BoundRegionKind {
pub fn get_id(&self) -> Option<DefId> {
match *self {
BoundRegionKind::BrNamed(id, _) => return Some(id),
BoundRegionKind::BrNamed(id, _) => Some(id),
_ => None,
}
}

View file

@ -82,13 +82,11 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
fn statement_as_expr(&self, stmt_id: StmtId) -> PResult<ExprId> {
match &self.thir[stmt_id].kind {
StmtKind::Expr { expr, .. } => Ok(*expr),
kind @ StmtKind::Let { pattern, .. } => {
return Err(ParseError {
span: pattern.span,
item_description: format!("{kind:?}"),
expected: "expression".to_string(),
});
}
kind @ StmtKind::Let { pattern, .. } => Err(ParseError {
span: pattern.span,
item_description: format!("{kind:?}"),
expected: "expression".to_string(),
}),
}
}

View file

@ -1193,7 +1193,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
return Some(new.def_id);
}
}
return None;
None
}
/// Scans the MIR in order to find function calls, closures, and drop-glue.

View file

@ -299,7 +299,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
}
return diff_errs;
}
return errs;
errs
}
fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> {

View file

@ -2553,7 +2553,7 @@ impl<'a> Parser<'a> {
err.delay_as_bug();
}
}
return Ok(false); // Don't continue.
Ok(false) // Don't continue.
}
/// Attempt to parse a generic const argument that has not been enclosed in braces.

View file

@ -457,7 +457,7 @@ impl<'a> Parser<'a> {
fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
// To be expanded
return Ok(None);
Ok(None)
}
/// Parses an item macro, e.g., `item!();`.

View file

@ -484,6 +484,9 @@ passes_must_not_suspend =
passes_must_use_no_effect =
`#[must_use]` has no effect when applied to {$article} {$target}
passes_naked_asm_outside_naked_fn =
the `naked_asm!` macro can only be used in functions marked with `#[naked]`
passes_naked_functions_asm_block =
naked functions must contain a single asm block
.label_multiple_asm = multiple asm blocks are unsupported in naked functions

View file

@ -1905,10 +1905,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|| (int_reprs == 1
&& is_c
&& item.is_some_and(|item| {
if let ItemLike::Item(item) = item {
return is_c_like_enum(item);
}
return false;
if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false }
}))
{
self.tcx.emit_node_span_lint(

View file

@ -394,7 +394,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
}
return false;
false
}
fn visit_node(&mut self, node: Node<'tcx>) {

View file

@ -1221,6 +1221,13 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
pub attr: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes_naked_asm_outside_naked_fn)]
pub(crate) struct NakedAsmOutsideNakedFn {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_attr_only_in_functions)]
pub(crate) struct AttrOnlyInFunctions {

View file

@ -6,6 +6,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, HirIdSet, InlineAsmOperand, StmtKind};
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
@ -14,8 +15,9 @@ use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use crate::errors::{
NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedFunctionsMustUseNoreturn,
NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, UndefinedNakedFunctionAbi,
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
UndefinedNakedFunctionAbi,
};
pub(crate) fn provide(providers: &mut Providers) {
@ -29,11 +31,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
continue;
}
let naked = tcx.has_attr(def_id, sym::naked);
if !naked {
continue;
}
let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
| hir::Node::TraitItem(hir::TraitItem {
@ -48,10 +45,17 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
};
let body = tcx.hir().body(body_id);
check_abi(tcx, def_id, fn_header.abi);
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);
check_asm(tcx, def_id, body);
if tcx.has_attr(def_id, sym::naked) {
check_abi(tcx, def_id, fn_header.abi);
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);
check_asm(tcx, def_id, body);
} else {
// `naked_asm!` is not allowed outside of functions marked as `#[naked]`
let mut visitor = CheckNakedAsmInNakedFn { tcx };
visitor.visit_body(body);
}
}
}
@ -276,3 +280,25 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
self.check_expr(expr, expr.span);
}
}
struct CheckNakedAsmInNakedFn<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> {
type NestedFilter = OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if let ExprKind::InlineAsm(inline_asm) = expr.kind {
if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro {
self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span });
}
}
hir::intravisit::walk_expr(self, expr);
}
}

View file

@ -951,7 +951,11 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
let empty_arms_are_unreachable = self.validity.is_known_valid();
// We don't want to warn empty patterns as unreachable by default just yet. We will in a
// later version of rust or under a different lint name, see
// https://github.com/rust-lang/rust/pull/129103.
let empty_arms_are_unreachable = self.validity.is_known_valid()
&& (is_toplevel_exception || cx.is_exhaustive_patterns_feature_on());
// Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
// toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
let can_omit_empty_arms = self.validity.is_known_valid()

View file

@ -3076,7 +3076,7 @@ fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
}
}
}
return None;
None
}
fn is_span_suitable_for_use_injection(s: Span) -> bool {

View file

@ -5016,5 +5016,5 @@ fn def_id_matches_path(tcx: TyCtxt<'_>, mut def_id: DefId, expected_path: &[&str
}
def_id = parent;
}
return true;
true
}

View file

@ -779,7 +779,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
}
return (false, candidates);
(false, candidates)
}
fn suggest_trait_and_bounds(

View file

@ -182,7 +182,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
}
}
return sysroot_candidates;
sysroot_candidates
}
/// Returns the provided sysroot or calls [`get_or_default_sysroot`] if it's none.

View file

@ -353,7 +353,7 @@ fn build_options<O: Default>(
None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
}
}
return op;
op
}
#[allow(non_upper_case_globals)]

View file

@ -96,7 +96,7 @@ impl SearchPath {
Self::new(PathKind::All, make_target_lib_path(sysroot, triple))
}
fn new(kind: PathKind, dir: PathBuf) -> Self {
pub fn new(kind: PathKind, dir: PathBuf) -> Self {
// Get the files within the directory.
let files = match std::fs::read_dir(&dir) {
Ok(files) => files

View file

@ -779,7 +779,7 @@ impl SourceMap {
return Ok(false);
}
}
return Ok(true);
Ok(true)
})
.is_ok_and(|is_accessible| is_accessible)
}

View file

@ -1236,7 +1236,6 @@ symbols! {
mir_unwind_unreachable,
mir_variant,
miri,
missing_docs,
mmx_reg,
modifiers,
module,

View file

@ -188,7 +188,7 @@ impl ArgAttributes {
if self.arg_ext != other.arg_ext {
return false;
}
return true;
true
}
}
@ -632,7 +632,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
PassMode::Indirect { .. } => {
self.mode = PassMode::Direct(ArgAttributes::new());
}
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => return, // already direct
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => {} // already direct
_ => panic!("Tried to make {:?} direct", self.mode),
}
}
@ -646,7 +646,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
}
PassMode::Indirect { attrs: _, meta_attrs: _, on_stack: false } => {
// already indirect
return;
}
_ => panic!("Tried to make {:?} indirect", self.mode),
}
@ -661,7 +660,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
}
PassMode::Indirect { attrs: _, meta_attrs: _, on_stack: false } => {
// already indirect
return;
}
_ => panic!("Tried to make {:?} indirect (expected `PassMode::Ignore`)", self.mode),
}

View file

@ -66,7 +66,7 @@ where
data.last_offset = offset + Reg::f64().size;
}
data.prefix_index += 1;
return data;
data
}
fn arg_scalar_pair<C>(
@ -92,7 +92,7 @@ where
offset += Size::from_bytes(4 - (offset.bytes() % 4));
}
data = arg_scalar(cx, scalar2, offset, data);
return data;
data
}
fn parse_structure<'a, Ty, C>(
@ -128,7 +128,7 @@ where
}
}
return data;
data
}
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size)

View file

@ -439,10 +439,6 @@ impl f128 {
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
// Other float types suffer from various platform bugs that violate the usual IEEE semantics
// and also make bitwise classification not always work reliably. However, `f128` cannot fit
// into any other float types so this is not a concern, and we can rely on bit patterns.
let bits = self.to_bits();
match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,

View file

@ -424,42 +424,13 @@ impl f16 {
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
// A previous implementation for f32/f64 tried to only use bitmask-based checks,
// using `to_bits` to transmute the float to its bit repr and match on that.
// If we only cared about being "technically" correct, that's an entirely legit
// implementation.
//
// Unfortunately, there are platforms out there that do not correctly implement the IEEE
// float semantics Rust relies on: some hardware flushes denormals to zero, and some
// platforms convert to `f32` to perform operations without properly rounding back (e.g.
// WASM, see llvm/llvm-project#96437). These are platforms bugs, and Rust will misbehave on
// such platforms, but we can at least try to make things seem as sane as possible by being
// careful here.
if self.is_infinite() {
// Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
FpCategory::Infinite
} else if self.is_nan() {
// And it may not be NaN, as it can simply be an "overextended" finite value.
FpCategory::Nan
} else {
// However, std can't simply compare to zero to check for zero, either,
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
// Most of std's targets don't use those, but they are used for thumbv7neon.
// So, this does use bitpattern matching for the rest. On x87, due to the incorrect
// float codegen on this hardware, this doesn't actually return a right answer for NaN
// because it cannot correctly discern between a floating point NaN, and some normal
// floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
// we are fine.
// FIXME(jubilee): This probably could at least answer things correctly for Infinity,
// like the f64 version does, but I need to run more checks on how things go on x86.
// I fear losing mantissa data that would have answered that differently.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
}

View file

@ -652,45 +652,18 @@ impl f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
// A previous implementation tried to only use bitmask-based checks,
// using f32::to_bits to transmute the float to its bit repr and match on that.
// If we only cared about being "technically" correct, that's an entirely legit
// implementation.
//
// Unfortunately, there is hardware out there that does not correctly implement the IEEE
// float semantics Rust relies on: x87 uses a too-large mantissa and exponent, and some
// hardware flushes subnormals to zero. These are platforms bugs, and Rust will misbehave on
// such hardware, but we can at least try to make things seem as sane as possible by being
// careful here.
//
// FIXME(jubilee): Using x87 operations is never necessary in order to function
// on x86 processors for Rust-to-Rust calls, so this issue should not happen.
// Code generation should be adjusted to use non-C calling conventions, avoiding this.
if self.is_infinite() {
// A value may compare unequal to infinity, despite having a "full" exponent mask.
FpCategory::Infinite
} else if self.is_nan() {
// And it may not be NaN, as it can simply be an "overextended" finite value.
FpCategory::Nan
} else {
// However, std can't simply compare to zero to check for zero, either,
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
// Most of std's targets don't use those, but they are used for thumbv7neon.
// So, this does use bitpattern matching for the rest. On x87, due to the incorrect
// float codegen on this hardware, this doesn't actually return a right answer for NaN
// because it cannot correctly discern between a floating point NaN, and some normal
// floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
// we are fine.
// FIXME(jubilee): This probably could at least answer things correctly for Infinity,
// like the f64 version does, but I need to run more checks on how things go on x86.
// I fear losing mantissa data that would have answered that differently.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
// We used to have complicated logic here that avoids the simple bit-based tests to work
// around buggy codegen for x87 targets (see
// https://github.com/rust-lang/rust/issues/114479). However, some LLVM versions later, none
// of our tests is able to find any difference between the complicated and the naive
// version, so now we are back to the naive version.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
}

View file

@ -651,41 +651,18 @@ impl f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
// A previous implementation tried to only use bitmask-based checks,
// using f64::to_bits to transmute the float to its bit repr and match on that.
// If we only cared about being "technically" correct, that's an entirely legit
// implementation.
//
// Unfortunately, there is hardware out there that does not correctly implement the IEEE
// float semantics Rust relies on: x87 uses a too-large exponent, and some hardware flushes
// subnormals to zero. These are platforms bugs, and Rust will misbehave on such hardware,
// but we can at least try to make things seem as sane as possible by being careful here.
//
// FIXME(jubilee): Using x87 operations is never necessary in order to function
// on x86 processors for Rust-to-Rust calls, so this issue should not happen.
// Code generation should be adjusted to use non-C calling conventions, avoiding this.
//
// Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
// And it may not be NaN, as it can simply be an "overextended" finite value.
if self.is_nan() {
FpCategory::Nan
} else {
// However, std can't simply compare to zero to check for zero, either,
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
// Most of std's targets don't use those, but they are used for thumbv7neon.
// So, this does use bitpattern matching for the rest. On x87, due to the incorrect
// float codegen on this hardware, this doesn't actually return a right answer for NaN
// because it cannot correctly discern between a floating point NaN, and some normal
// floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
// we are fine.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
// We used to have complicated logic here that avoids the simple bit-based tests to work
// around buggy codegen for x87 targets (see
// https://github.com/rust-lang/rust/issues/114479). However, some LLVM versions later, none
// of our tests is able to find any difference between the complicated and the naive
// version, so now we are back to the naive version.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
}

View file

@ -118,7 +118,7 @@ const SINGLETONS0U: &[(u8, u8)] = &[
(0x30, 4),
(0x31, 2),
(0x32, 1),
(0xa7, 2),
(0xa7, 4),
(0xa9, 2),
(0xaa, 4),
(0xab, 8),
@ -155,17 +155,18 @@ const SINGLETONS0L: &[u8] = &[
0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe,
0xff, 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x1f,
0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae,
0xaf, 0x7f, 0xbb, 0xbc, 0x16, 0x17, 0x1e, 0x1f,
0xaf, 0x4d, 0xbb, 0xbc, 0x16, 0x17, 0x1e, 0x1f,
0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e,
0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0,
0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96,
0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7,
0xcf, 0xd7, 0xdf, 0x9a, 0x00, 0x40, 0x97, 0x98,
0x30, 0x8f, 0x1f, 0xd2, 0xd4, 0xce, 0xff, 0x4e,
0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f,
0x42, 0x45, 0x90, 0x91, 0x53, 0x67, 0x75, 0xc8,
0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff,
0x30, 0x8f, 0x1f, 0xce, 0xcf, 0xd2, 0xd4, 0xce,
0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f,
0x10, 0x27, 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37,
0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, 0x53, 0x67,
0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
0xfe, 0xff,
];
#[rustfmt::skip]
const SINGLETONS1U: &[(u8, u8)] = &[
@ -183,7 +184,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[
(0x10, 1),
(0x11, 2),
(0x12, 5),
(0x13, 17),
(0x13, 28),
(0x14, 1),
(0x15, 2),
(0x17, 2),
@ -211,7 +212,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[
(0xee, 32),
(0xf0, 4),
(0xf8, 2),
(0xfa, 3),
(0xfa, 4),
(0xfb, 1),
];
#[rustfmt::skip]
@ -224,23 +225,24 @@ const SINGLETONS1L: &[u8] = &[
0xbd, 0x35, 0xe0, 0x12, 0x87, 0x89, 0x8e, 0x9e,
0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34,
0x3a, 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64,
0x65, 0x5c, 0xb6, 0xb7, 0x1b, 0x1c, 0x07, 0x08,
0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8,
0xa9, 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8,
0x07, 0x0a, 0x3b, 0x3e, 0x66, 0x69, 0x8f, 0x92,
0x11, 0x6f, 0x5f, 0xbf, 0xee, 0xef, 0x5a, 0x62,
0xf4, 0xfc, 0xff, 0x53, 0x54, 0x9a, 0x9b, 0x2e,
0x2f, 0x27, 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3,
0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, 0xc4, 0x06,
0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51,
0xa6, 0xa7, 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a,
0x22, 0x25, 0x3e, 0x3f, 0xe7, 0xec, 0xef, 0xff,
0xc5, 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28,
0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53,
0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63,
0x65, 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a,
0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0xae, 0xaf,
0x6e, 0x6f, 0xbe, 0x93,
0x65, 0x8a, 0x8c, 0x8d, 0x8f, 0xb6, 0xc1, 0xc3,
0xc4, 0xc6, 0xcb, 0xd6, 0x5c, 0xb6, 0xb7, 0x1b,
0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36,
0x39, 0x3a, 0xa8, 0xa9, 0xd8, 0xd9, 0x09, 0x37,
0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
0x69, 0x8f, 0x92, 0x11, 0x6f, 0x5f, 0xbf, 0xee,
0xef, 0x5a, 0x62, 0xf4, 0xfc, 0xff, 0x53, 0x54,
0x9a, 0x9b, 0x2e, 0x2f, 0x27, 0x28, 0x55, 0x9d,
0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba,
0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a,
0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, 0xa0,
0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xe7,
0xec, 0xef, 0xff, 0xc5, 0xc6, 0x04, 0x20, 0x23,
0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a,
0x4c, 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c,
0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b, 0x73, 0x78,
0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0,
0xd0, 0xae, 0xaf, 0x6e, 0x6f, 0xdd, 0xde, 0x93,
];
#[rustfmt::skip]
const NORMAL0: &[u8] = &[
@ -252,8 +254,8 @@ const NORMAL0: &[u8] = &[
0x06, 0x11,
0x81, 0xac, 0x0e,
0x80, 0xab, 0x05,
0x1f, 0x09,
0x81, 0x1b, 0x03,
0x1f, 0x08,
0x81, 0x1c, 0x03,
0x19, 0x08,
0x01, 0x04,
0x2f, 0x04,
@ -318,11 +320,10 @@ const NORMAL0: &[u8] = &[
0x80, 0xac, 0x06,
0x0a, 0x06,
0x2f, 0x31,
0x4d, 0x03,
0x80, 0xa4, 0x08,
0x80, 0xf4, 0x08,
0x3c, 0x03,
0x0f, 0x03,
0x3c, 0x07,
0x3e, 0x05,
0x38, 0x08,
0x2b, 0x05,
0x82, 0xff, 0x11,
@ -332,7 +333,7 @@ const NORMAL0: &[u8] = &[
0x21, 0x0f,
0x21, 0x0f,
0x80, 0x8c, 0x04,
0x82, 0x97, 0x19,
0x82, 0x9a, 0x16,
0x0b, 0x15,
0x88, 0x94, 0x05,
0x2f, 0x05,
@ -343,13 +344,12 @@ const NORMAL0: &[u8] = &[
0x74, 0x0c,
0x80, 0xd6, 0x1a,
0x81, 0x10, 0x05,
0x80, 0xdf, 0x0b,
0x80, 0xe1, 0x09,
0xf2, 0x9e, 0x03,
0x37, 0x09,
0x81, 0x5c, 0x14,
0x80, 0xb8, 0x08,
0x80, 0xcb, 0x05,
0x0a, 0x18,
0x80, 0xdd, 0x15,
0x3b, 0x03,
0x0a, 0x06,
0x38, 0x08,
@ -402,7 +402,8 @@ const NORMAL1: &[u8] = &[
0x24, 0x04,
0x28, 0x08,
0x34, 0x0b,
0x4e, 0x43,
0x4e, 0x03,
0x34, 0x0c,
0x81, 0x37, 0x09,
0x16, 0x0a,
0x08, 0x18,
@ -431,9 +432,13 @@ const NORMAL1: &[u8] = &[
0x33, 0x0d,
0x33, 0x07,
0x2e, 0x08,
0x0a, 0x81, 0x26,
0x52, 0x4b,
0x2b, 0x08,
0x0a, 0x06,
0x26, 0x03,
0x1d, 0x08,
0x02, 0x80, 0xd0,
0x52, 0x10,
0x03, 0x37,
0x2c, 0x08,
0x2a, 0x16,
0x1a, 0x26,
0x1c, 0x14,
@ -453,7 +458,9 @@ const NORMAL1: &[u8] = &[
0x51, 0x06,
0x01, 0x05,
0x10, 0x03,
0x05, 0x80, 0x8b,
0x05, 0x0b,
0x59, 0x08,
0x02, 0x1d,
0x62, 0x1e,
0x48, 0x08,
0x0a, 0x80, 0xa6,
@ -462,7 +469,8 @@ const NORMAL1: &[u8] = &[
0x0a, 0x06,
0x0d, 0x13,
0x3a, 0x06,
0x0a, 0x36,
0x0a, 0x06,
0x14, 0x1c,
0x2c, 0x04,
0x17, 0x80, 0xb9,
0x3c, 0x64,
@ -473,7 +481,9 @@ const NORMAL1: &[u8] = &[
0x48, 0x08,
0x53, 0x0d,
0x49, 0x07,
0x0a, 0x80, 0xf6,
0x0a, 0x80, 0xb6,
0x22, 0x0e,
0x0a, 0x06,
0x46, 0x0a,
0x1d, 0x03,
0x47, 0x49,
@ -484,7 +494,7 @@ const NORMAL1: &[u8] = &[
0x0a, 0x81, 0x36,
0x19, 0x07,
0x3b, 0x03,
0x1c, 0x56,
0x1d, 0x55,
0x01, 0x0f,
0x32, 0x0d,
0x83, 0x9b, 0x66,
@ -492,15 +502,18 @@ const NORMAL1: &[u8] = &[
0x80, 0xc4, 0x8a, 0x4c,
0x63, 0x0d,
0x84, 0x30, 0x10,
0x16, 0x8f, 0xaa,
0x82, 0x47, 0xa1, 0xb9,
0x16, 0x0a,
0x8f, 0x9b, 0x05,
0x82, 0x47, 0x9a, 0xb9,
0x3a, 0x86, 0xc6,
0x82, 0x39, 0x07,
0x2a, 0x04,
0x5c, 0x06,
0x26, 0x0a,
0x46, 0x0a,
0x28, 0x05,
0x13, 0x82, 0xb0,
0x13, 0x81, 0xb0,
0x3a, 0x80, 0xc6,
0x5b, 0x65,
0x4b, 0x04,
0x39, 0x07,
@ -508,8 +521,8 @@ const NORMAL1: &[u8] = &[
0x05, 0x0b,
0x02, 0x0e,
0x97, 0xf8, 0x08,
0x84, 0xd6, 0x2a,
0x09, 0xa2, 0xe7,
0x84, 0xd6, 0x29,
0x0a, 0xa2, 0xe7,
0x81, 0x33, 0x0f,
0x01, 0x1d,
0x06, 0x0e,
@ -518,7 +531,9 @@ const NORMAL1: &[u8] = &[
0x6b, 0x05,
0x0d, 0x03,
0x09, 0x07,
0x10, 0x92, 0x60,
0x10, 0x8f, 0x60,
0x80, 0xfa, 0x06,
0x81, 0xb4, 0x4c,
0x47, 0x09,
0x74, 0x3c,
0x80, 0xf6, 0x0a,
@ -543,7 +558,9 @@ const NORMAL1: &[u8] = &[
0x1f, 0x11,
0x3a, 0x05,
0x01, 0x81, 0xd0,
0x2a, 0x82, 0xe6,
0x2a, 0x80, 0xd6,
0x2b, 0x04,
0x01, 0x81, 0xe0,
0x80, 0xf7, 0x29,
0x4c, 0x04,
0x0a, 0x04,
@ -575,14 +592,13 @@ const NORMAL1: &[u8] = &[
0x38, 0x08,
0x0a, 0x06,
0x28, 0x08,
0x22, 0x4e,
0x2c, 0x04,
0x02, 0x3e,
0x81, 0x54, 0x0c,
0x1d, 0x03,
0x0a, 0x05,
0x38, 0x07,
0x1c, 0x06,
0x09, 0x07,
0x36, 0x08,
0x0e, 0x04,
0x09, 0x07,
0x09, 0x07,
0x80, 0xcb, 0x25,
0x0a, 0x84, 0x06,
0x80, 0xfa, 0x84, 0x06,
];

File diff suppressed because it is too large Load diff

View file

@ -79,42 +79,50 @@
//! see each type's documentation, and note that the names of actual methods may
//! differ from the tables below on certain collections.
//!
//! Throughout the documentation, we will follow a few conventions. For all
//! operations, the collection's size is denoted by n. If another collection is
//! involved in the operation, it contains m elements. Operations which have an
//! *amortized* cost are suffixed with a `*`. Operations with an *expected*
//! cost are suffixed with a `~`.
//! Throughout the documentation, we will adhere to the following conventions
//! for operation notation:
//!
//! All amortized costs are for the potential need to resize when capacity is
//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never
//! automatically shrink, so removal operations aren't amortized. Over a
//! sufficiently large series of operations, the average cost per operation will
//! deterministically equal the given cost.
//! * The collection's size is denoted by `n`.
//! * If a second collection is involved, its size is denoted by `m`.
//! * Item indices are denoted by `i`.
//! * Operations which have an *amortized* cost are suffixed with a `*`.
//! * Operations with an *expected* cost are suffixed with a `~`.
//!
//! Only [`HashMap`] has expected costs, due to the probabilistic nature of hashing.
//! It is theoretically possible, though very unlikely, for [`HashMap`] to
//! experience worse performance.
//! Calling operations that add to a collection will occasionally require a
//! collection to be resized - an extra operation that takes *O*(*n*) time.
//!
//! ## Sequences
//! *Amortized* costs are calculated to account for the time cost of such resize
//! operations *over a sufficiently large series of operations*. An individual
//! operation may be slower or faster due to the sporadic nature of collection
//! resizing, however the average cost per operation will approach the amortized
//! cost.
//!
//! | | get(i) | insert(i) | remove(i) | append | split_off(i) |
//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------|
//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) |
//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) |
//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) |
//! Rust's collections never automatically shrink, so removal operations aren't
//! amortized.
//!
//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and
//! [`VecDeque`] is generally going to be faster than [`LinkedList`].
//! [`HashMap`] uses *expected* costs. It is theoretically possible, though very
//! unlikely, for [`HashMap`] to experience significantly worse performance than
//! the expected cost. This is due to the probabilistic nature of hashing - i.e.
//! it is possible to generate a duplicate hash given some input key that will
//! requires extra computation to correct.
//!
//! ## Maps
//! ## Cost of Collection Operations
//!
//!
//! | | get(i) | insert(i) | remove(i) | append(Vec(m)) | split_off(i) | range | append |
//! |----------------|------------------------|-------------------------|------------------------|-------------------|------------------------|-----------------|--------------|
//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | N/A | N/A |
//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | N/A | N/A |
//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | N/A | N/A |
//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | N/A | N/A |
//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | N/A | N/A | *O*(log(*n*)) | *O*(*n*+*m*) |
//!
//! Note that where ties occur, [`Vec`] is generally going to be faster than
//! [`VecDeque`], and [`VecDeque`] is generally going to be faster than
//! [`LinkedList`].
//!
//! For Sets, all operations have the cost of the equivalent Map operation.
//!
//! | | get | insert | remove | range | append |
//! |--------------|---------------|---------------|---------------|---------------|--------------|
//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A |
//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) |
//!
//! # Correct and Efficient Usage of Collections
//!
//! Of course, knowing which collection is the right one for the job doesn't

View file

@ -2,31 +2,24 @@ use crate::f32::consts;
use crate::num::{FpCategory as Fp, *};
/// Smallest number
#[allow(dead_code)] // unused on x86
const TINY_BITS: u32 = 0x1;
/// Next smallest number
#[allow(dead_code)] // unused on x86
const TINY_UP_BITS: u32 = 0x2;
/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0
#[allow(dead_code)] // unused on x86
const MAX_DOWN_BITS: u32 = 0x7f7f_fffe;
/// Zeroed exponent, full significant
#[allow(dead_code)] // unused on x86
const LARGEST_SUBNORMAL_BITS: u32 = 0x007f_ffff;
/// Exponent = 0b1, zeroed significand
#[allow(dead_code)] // unused on x86
const SMALLEST_NORMAL_BITS: u32 = 0x0080_0000;
/// First pattern over the mantissa
#[allow(dead_code)] // unused on x86
const NAN_MASK1: u32 = 0x002a_aaaa;
/// Second pattern over the mantissa
#[allow(dead_code)] // unused on x86
const NAN_MASK2: u32 = 0x0055_5555;
#[allow(unused_macros)]
@ -353,9 +346,6 @@ fn test_is_sign_negative() {
assert!((-f32::NAN).is_sign_negative());
}
// Ignore test on x87 floating point, these platforms do not guarantee NaN
// payloads are preserved and flush denormals to zero, failing the tests.
#[cfg(not(target_arch = "x86"))]
#[test]
fn test_next_up() {
let tiny = f32::from_bits(TINY_BITS);
@ -386,9 +376,6 @@ fn test_next_up() {
assert_f32_biteq!(nan2.next_up(), nan2);
}
// Ignore test on x87 floating point, these platforms do not guarantee NaN
// payloads are preserved and flush denormals to zero, failing the tests.
#[cfg(not(target_arch = "x86"))]
#[test]
fn test_next_down() {
let tiny = f32::from_bits(TINY_BITS);

View file

@ -2,31 +2,24 @@ use crate::f64::consts;
use crate::num::{FpCategory as Fp, *};
/// Smallest number
#[allow(dead_code)] // unused on x86
const TINY_BITS: u64 = 0x1;
/// Next smallest number
#[allow(dead_code)] // unused on x86
const TINY_UP_BITS: u64 = 0x2;
/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0
#[allow(dead_code)] // unused on x86
const MAX_DOWN_BITS: u64 = 0x7fef_ffff_ffff_fffe;
/// Zeroed exponent, full significant
#[allow(dead_code)] // unused on x86
const LARGEST_SUBNORMAL_BITS: u64 = 0x000f_ffff_ffff_ffff;
/// Exponent = 0b1, zeroed significand
#[allow(dead_code)] // unused on x86
const SMALLEST_NORMAL_BITS: u64 = 0x0010_0000_0000_0000;
/// First pattern over the mantissa
#[allow(dead_code)] // unused on x86
const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;
/// Second pattern over the mantissa
#[allow(dead_code)] // unused on x86
const NAN_MASK2: u64 = 0x0005_5555_5555_5555;
#[allow(unused_macros)]
@ -343,9 +336,6 @@ fn test_is_sign_negative() {
assert!((-f64::NAN).is_sign_negative());
}
// Ignore test on x87 floating point, these platforms do not guarantee NaN
// payloads are preserved and flush denormals to zero, failing the tests.
#[cfg(not(target_arch = "x86"))]
#[test]
fn test_next_up() {
let tiny = f64::from_bits(TINY_BITS);
@ -375,9 +365,6 @@ fn test_next_up() {
assert_f64_biteq!(nan2.next_up(), nan2);
}
// Ignore test on x87 floating point, these platforms do not guarantee NaN
// payloads are preserved and flush denormals to zero, failing the tests.
#[cfg(not(target_arch = "x86"))]
#[test]
fn test_next_down() {
let tiny = f64::from_bits(TINY_BITS);

View file

@ -298,7 +298,7 @@ impl OpenOptionsExt for OpenOptions {
/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
///
/// [`BY_HANDLE_FILE_INFORMATION`]:
/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
/// https://docs.microsoft.com/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the value of the `dwFileAttributes` field of this metadata.
@ -322,7 +322,7 @@ pub trait MetadataExt {
/// ```
///
/// [File Attribute Constants]:
/// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
/// https://docs.microsoft.com/windows/win32/fileio/file-attribute-constants
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn file_attributes(&self) -> u32;
@ -351,7 +351,7 @@ pub trait MetadataExt {
/// }
/// ```
///
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
/// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn creation_time(&self) -> u64;
@ -386,7 +386,7 @@ pub trait MetadataExt {
/// }
/// ```
///
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
/// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn last_access_time(&self) -> u64;
@ -419,11 +419,11 @@ pub trait MetadataExt {
/// }
/// ```
///
/// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
/// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn last_write_time(&self) -> u64;
/// Returns the value of the `nFileSize{High,Low}` fields of this
/// Returns the value of the `nFileSize` fields of this
/// metadata.
///
/// The returned value does not have meaning for directories.
@ -462,7 +462,7 @@ pub trait MetadataExt {
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn number_of_links(&self) -> Option<u32>;
/// Returns the value of the `nFileIndex{Low,High}` fields of this
/// Returns the value of the `nFileIndex` fields of this
/// metadata.
///
/// This will return `None` if the `Metadata` instance was created from a
@ -471,10 +471,14 @@ pub trait MetadataExt {
#[unstable(feature = "windows_by_handle", issue = "63010")]
fn file_index(&self) -> Option<u64>;
/// Returns the change time, which is the last time file metadata was changed, such as
/// renames, attributes, etc
/// Returns the value of the `ChangeTime` fields of this metadata.
///
/// This will return `None` if the `Metadata` instance was not created using the `FILE_BASIC_INFO` type.
/// `ChangeTime` is the last time file metadata was changed, such as
/// renames, attributes, etc.
///
/// This will return `None` if `Metadata` instance was created from a call to
/// `DirEntry::metadata` or if the `target_vendor` is outside the current platform
/// support for this api.
#[unstable(feature = "windows_change_time", issue = "121478")]
fn change_time(&self) -> Option<u64>;
}

View file

@ -1731,7 +1731,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
run_path_with_cstr(original, &|original| {
run_path_with_cstr(link, &|link| {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nto"))] {
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] {
// VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
// it implementation-defined whether `link` follows symlinks, so rely on the
// `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.

View file

@ -122,6 +122,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop,
_ => {}
}
@ -139,6 +140,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
c::WSAEHOSTUNREACH => HostUnreachable,
c::WSAENETDOWN => NetworkDown,
c::WSAENETUNREACH => NetworkUnreachable,
c::WSAEDQUOT => FilesystemQuotaExceeded,
_ => Uncategorized,
}

View file

@ -54,10 +54,10 @@ pub enum EHAction {
Terminate,
}
/// 32-bit Apple ARM uses SjLj exceptions, except for watchOS.
/// 32-bit ARM Darwin platforms uses SjLj exceptions.
///
/// I.e. iOS and tvOS, as those are the only Apple OSes that used 32-bit ARM
/// devices.
/// The exception is watchOS armv7k (specifically that subarchitecture), which
/// instead uses DWARF Call Frame Information (CFI) unwinding.
///
/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.4/clang/lib/Driver/ToolChains/Darwin.cpp#L3107-L3119>
pub const USING_SJLJ_EXCEPTIONS: bool =

View file

@ -95,14 +95,15 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
cfg_if::cfg_if! {
if #[cfg(all(
target_arch = "arm",
not(all(target_vendor = "apple", not(target_os = "watchos"))),
not(target_os = "netbsd"),
))] {
target_arch = "arm",
not(target_vendor = "apple"),
not(target_os = "netbsd"),
))] {
/// personality fn called by [ARM EHABI][armeabi-eh]
///
/// Apple 32-bit ARM (but not watchOS) uses the default routine instead
/// since it uses "setjmp-longjmp" unwinding.
/// 32-bit ARM on iOS/tvOS/watchOS does not use ARM EHABI, it uses
/// either "setjmp-longjmp" unwinding or DWARF CFI unwinding, which is
/// handled by the default routine.
///
/// [armeabi-eh]: https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
#[lang = "eh_personality"]

@ -1 +1 @@
Subproject commit d9466edb4c53cece8686ee6e17b028436ddf4151
Subproject commit ace72223a0e321c1b0a37b5862aa756fe8ab5111

View file

@ -33,10 +33,10 @@ pub const unwinder_private_data_size: usize = 2;
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
pub const unwinder_private_data_size: usize = 6;
#[cfg(all(target_arch = "arm", not(all(target_vendor = "apple", not(target_os = "watchos")))))]
#[cfg(all(target_arch = "arm", not(target_vendor = "apple")))]
pub const unwinder_private_data_size: usize = 20;
#[cfg(all(target_arch = "arm", all(target_vendor = "apple", not(target_os = "watchos"))))]
#[cfg(all(target_arch = "arm", target_vendor = "apple"))]
pub const unwinder_private_data_size: usize = 5;
#[cfg(all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")))]
@ -123,8 +123,11 @@ extern "C" {
}
cfg_if::cfg_if! {
if #[cfg(any(all(target_vendor = "apple", not(target_os = "watchos")), target_os = "netbsd", not(target_arch = "arm")))] {
if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "arm")))] {
// Not ARM EHABI
//
// 32-bit ARM on iOS/tvOS/watchOS use either DWARF/Compact unwinding or
// "setjmp-longjmp" / SjLj unwinding.
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum _Unwind_Action {
@ -259,8 +262,8 @@ if #[cfg(any(all(target_vendor = "apple", not(target_os = "watchos")), target_os
cfg_if::cfg_if! {
if #[cfg(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm"))] {
// 32-bit ARM Apple (except for watchOS) uses SjLj and does not provide
// _Unwind_Backtrace()
// 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and
// does not provide _Unwind_Backtrace()
extern "C-unwind" {
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}

View file

@ -15,6 +15,7 @@ use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::{env, fs, str};
use build_helper::git::get_closest_merge_commit;
use serde_derive::Deserialize;
use crate::core::build_steps::tool::SourceType;
@ -26,8 +27,7 @@ use crate::core::builder::{
use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
use crate::utils::exec::command;
use crate::utils::helpers::{
self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib,
symlink_dir, t, up_to_date,
self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
};
use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};
@ -127,13 +127,9 @@ impl Step for Std {
// the `rust.download-rustc=true` option.
let force_recompile =
if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
let closest_merge_commit = get_closest_merge_base_commit(
Some(&builder.src),
&builder.config.git_config(),
&builder.config.stage0_metadata.config.git_merge_commit_email,
&[],
)
.unwrap();
let closest_merge_commit =
get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[])
.unwrap();
// Check if `library` has changes (returns false otherwise)
!t!(helpers::git(Some(&builder.src))

View file

@ -200,6 +200,11 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
adjective = Some("modified");
match get_modified_rs_files(build) {
Ok(Some(files)) => {
if files.is_empty() {
println!("fmt info: No modified files detected for formatting.");
return;
}
for file in files {
override_builder.add(&format!("/{file}")).expect(&file);
}

View file

@ -16,6 +16,7 @@ use std::sync::OnceLock;
use std::{env, io};
use build_helper::ci::CiEnv;
use build_helper::git::get_closest_merge_commit;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::core::config::{Config, TargetSelection};
@ -153,10 +154,9 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
/// This retrieves the LLVM sha we *want* to use, according to git history.
pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
let llvm_sha = if is_git {
helpers::get_closest_merge_base_commit(
get_closest_merge_commit(
Some(&config.src),
&config.git_config(),
&config.stage0_metadata.config.git_merge_commit_email,
&[
config.src.join("src/llvm-project"),
config.src.join("src/bootstrap/download-ci-llvm-stamp"),

View file

@ -17,6 +17,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
.tool_cmd(Tool::SuggestTests)
.env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
.env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
.env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
.run_capture_stdout(builder)
.stdout();

View file

@ -2098,6 +2098,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
let git_config = builder.config.git_config();
cmd.arg("--git-repository").arg(git_config.git_repository);
cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
cmd.force_coloring_in_ci();
#[cfg(feature = "build-metrics")]

View file

@ -1,6 +1,8 @@
use std::path::PathBuf;
use std::{env, fs};
use build_helper::git::get_closest_merge_commit;
use crate::core::build_steps::compile;
use crate::core::build_steps::toolstate::ToolState;
use crate::core::builder;
@ -8,7 +10,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun,
use crate::core::config::TargetSelection;
use crate::utils::channel::GitInfo;
use crate::utils::exec::{command, BootstrapCommand};
use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t};
use crate::utils::helpers::{add_dylib_path, exe, git, t};
use crate::{gha, Compiler, Kind, Mode};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
@ -576,10 +578,9 @@ impl Step for Rustdoc {
&& target_compiler.stage > 0
&& builder.rust_info().is_managed_git_subrepository()
{
let commit = get_closest_merge_base_commit(
let commit = get_closest_merge_commit(
Some(&builder.config.src),
&builder.config.git_config(),
&builder.config.stage0_metadata.config.git_merge_commit_email,
&[],
)
.unwrap();

View file

@ -14,7 +14,7 @@ use std::sync::OnceLock;
use std::{cmp, env, fs};
use build_helper::exit;
use build_helper::git::{output_result, GitConfig};
use build_helper::git::{get_closest_merge_commit, output_result, GitConfig};
use serde::{Deserialize, Deserializer};
use serde_derive::Deserialize;
@ -24,7 +24,7 @@ pub use crate::core::config::flags::Subcommand;
use crate::core::config::flags::{Color, Flags, Warnings};
use crate::utils::cache::{Interned, INTERNER};
use crate::utils::channel::{self, GitInfo};
use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
use crate::utils::helpers::{self, exe, output, t};
macro_rules! check_ci_llvm {
($name:expr) => {
@ -2512,6 +2512,7 @@ impl Config {
GitConfig {
git_repository: &self.stage0_metadata.config.git_repository,
nightly_branch: &self.stage0_metadata.config.nightly_branch,
git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email,
}
}
@ -2688,13 +2689,7 @@ impl Config {
// Look for a version to compare to based on the current commit.
// Only commits merged by bors will have CI artifacts.
let commit = get_closest_merge_base_commit(
Some(&self.src),
&self.git_config(),
&self.stage0_metadata.config.git_merge_commit_email,
&[],
)
.unwrap();
let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
if commit.is_empty() {
println!("ERROR: could not find commit hash for downloading rustc");
println!("HELP: maybe your repository history is too shallow?");
@ -2786,13 +2781,7 @@ impl Config {
) -> Option<String> {
// Look for a version to compare to based on the current commit.
// Only commits merged by bors will have CI artifacts.
let commit = get_closest_merge_base_commit(
Some(&self.src),
&self.git_config(),
&self.stage0_metadata.config.git_merge_commit_email,
&[],
)
.unwrap();
let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
if commit.is_empty() {
println!("error: could not find commit hash for downloading components from CI");
println!("help: maybe your repository history is too shallow?");

View file

@ -10,7 +10,6 @@ use std::sync::OnceLock;
use std::time::{Instant, SystemTime, UNIX_EPOCH};
use std::{env, fs, io, str};
use build_helper::git::{get_git_merge_base, output_result, GitConfig};
use build_helper::util::fail;
use crate::core::builder::Builder;
@ -523,28 +522,6 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
git
}
/// Returns the closest commit available from upstream for the given `author` and `target_paths`.
///
/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD.
pub fn get_closest_merge_base_commit(
source_dir: Option<&Path>,
config: &GitConfig<'_>,
author: &str,
target_paths: &[PathBuf],
) -> Result<String, String> {
let mut git = git(source_dir);
let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
if !target_paths.is_empty() {
git.arg("--").args(target_paths);
}
Ok(output_result(git.as_command_mut())?.trim().to_owned())
}
/// Sets the file times for a given file at `path`.
pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Result<()> {
// Windows requires file to be writable to modify file times. But on Linux CI the file does not

@ -1 +1 @@
Subproject commit 2b259b3c201f939f2ed8d2fb0a0e9b37dd2d1321
Subproject commit 4b8d29c585687084bbcf21471e04f279d1eddc0a

View file

@ -1,9 +1,10 @@
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
pub struct GitConfig<'a> {
pub git_repository: &'a str,
pub nightly_branch: &'a str,
pub git_merge_commit_email: &'a str,
}
/// Runs a command and returns the output
@ -95,7 +96,11 @@ pub fn updated_master_branch(
Err("Cannot find any suitable upstream master branch".to_owned())
}
pub fn get_git_merge_base(
/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state.
/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`.
/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote
/// to be configured.
fn git_upstream_merge_base(
config: &GitConfig<'_>,
git_dir: Option<&Path>,
) -> Result<String, String> {
@ -107,6 +112,38 @@ pub fn get_git_merge_base(
Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
}
/// Searches for the nearest merge commit in the repository that also exists upstream.
///
/// If it fails to find the upstream remote, it then looks for the most recent commit made
/// by the merge bot by matching the author's email address with the merge bot's email.
pub fn get_closest_merge_commit(
git_dir: Option<&Path>,
config: &GitConfig<'_>,
target_paths: &[PathBuf],
) -> Result<String, String> {
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
git.current_dir(git_dir);
}
let merge_base = git_upstream_merge_base(config, git_dir).unwrap_or_else(|_| "HEAD".into());
git.args([
"rev-list",
&format!("--author={}", config.git_merge_commit_email),
"-n1",
"--first-parent",
&merge_base,
]);
if !target_paths.is_empty() {
git.arg("--").args(target_paths);
}
Ok(output_result(&mut git)?.trim().to_owned())
}
/// Returns the files that have been modified in the current branch compared to the master branch.
/// The `extensions` parameter can be used to filter the files by their extension.
/// Does not include removed files.
@ -116,7 +153,7 @@ pub fn get_git_modified_files(
git_dir: Option<&Path>,
extensions: &[&str],
) -> Result<Option<Vec<String>>, String> {
let merge_base = get_git_merge_base(config, git_dir)?;
let merge_base = get_closest_merge_commit(git_dir, config, &[])?;
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {

View file

@ -384,6 +384,7 @@ pub struct Config {
// Needed both to construct build_helper::git::GitConfig
pub git_repository: String,
pub nightly_branch: String,
pub git_merge_commit_email: String,
/// True if the profiler runtime is enabled for this target.
/// Used by the "needs-profiler-support" header in test files.
@ -461,7 +462,11 @@ impl Config {
}
pub fn git_config(&self) -> GitConfig<'_> {
GitConfig { git_repository: &self.git_repository, nightly_branch: &self.nightly_branch }
GitConfig {
git_repository: &self.git_repository,
nightly_branch: &self.nightly_branch,
git_merge_commit_email: &self.git_merge_commit_email,
}
}
}

View file

@ -148,6 +148,7 @@ impl ConfigBuilder {
self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
"--git-repository=",
"--nightly-branch=",
"--git-merge-commit-email=",
];
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();

View file

@ -163,7 +163,13 @@ pub fn parse_config(args: Vec<String>) -> Config {
)
.optopt("", "edition", "default Rust edition", "EDITION")
.reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH");
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH")
.reqopt(
"",
"git-merge-commit-email",
"email address used for finding merge commits",
"EMAIL",
);
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@ -346,6 +352,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
git_repository: matches.opt_str("git-repository").unwrap(),
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
profiler_support: matches.opt_present("profiler-support"),
}

View file

@ -666,22 +666,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let (right, right_len) = this.operand_to_simd(right)?;
let (dest, dest_len) = this.mplace_to_simd(dest)?;
// `index` is an array, not a SIMD type
let ty::Array(_, index_len) = index.layout.ty.kind() else {
span_bug!(
this.cur_span(),
"simd_shuffle index argument has non-array type {}",
index.layout.ty
)
// `index` is an array or a SIMD type
let (index, index_len) = match index.layout.ty.kind() {
// FIXME: remove this once `index` must always be a SIMD vector.
ty::Array(..) => (index.assert_mem_place(), index.len(this)?),
_ => this.operand_to_simd(index)?,
};
let index_len = index_len.eval_target_usize(*this.tcx, this.param_env());
assert_eq!(left_len, right_len);
assert_eq!(index_len, dest_len);
for i in 0..dest_len {
let src_index: u64 = this
.read_immediate(&this.project_index(index, i)?)?
.read_immediate(&this.project_index(&index, i)?)?
.to_scalar()
.to_u32()?
.into();

View file

@ -0,0 +1,7 @@
fn main() {
let x = &[0i32; 2];
let x = x.as_ptr().wrapping_add(1);
// If the `!0` is interpreted as `isize`, it is just `-1` and hence harmless.
// However, this is unsigned arithmetic, so really this is `usize::MAX` and hence UB.
unsafe { x.byte_add(!0).read() }; //~ERROR: does not fit in an `isize`
}

View file

@ -0,0 +1,15 @@
error: Undefined Behavior: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
--> $DIR/ptr_offset_unsigned_overflow.rs:LL:CC
|
LL | unsafe { x.byte_add(!0).read() };
| ^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/ptr_offset_unsigned_overflow.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -620,6 +620,10 @@ fn simd_intrinsics() {
);
assert_eq!(simd_shuffle_generic::<_, i32x4, { &[3, 1, 0, 2] }>(a, b), a,);
assert_eq!(simd_shuffle::<_, _, i32x4>(a, b, const { [3u32, 1, 0, 2] }), a,);
assert_eq!(
simd_shuffle::<_, _, i32x4>(a, b, const { u32x4::from_array([3u32, 1, 0, 2]) }),
a,
);
assert_eq!(
simd_shuffle_generic::<_, i32x4, { &[7, 5, 4, 6] }>(a, b),
i32x4::from_array([4, 2, 1, 10]),
@ -628,6 +632,10 @@ fn simd_intrinsics() {
simd_shuffle::<_, _, i32x4>(a, b, const { [7u32, 5, 4, 6] }),
i32x4::from_array([4, 2, 1, 10]),
);
assert_eq!(
simd_shuffle::<_, _, i32x4>(a, b, const { u32x4::from_array([7u32, 5, 4, 6]) }),
i32x4::from_array([4, 2, 1, 10]),
);
}
}

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