Merge from rustc
This commit is contained in:
commit
93ef7cd2dd
152 changed files with 1903 additions and 2047 deletions
|
|
@ -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)>,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
|
|
@ -1240,5 +1240,5 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
|
|||
candidates.push(meta_lit.symbol);
|
||||
}
|
||||
|
||||
return Some(candidates);
|
||||
Some(candidates)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3669,7 +3669,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
reinits.push(location);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
false
|
||||
};
|
||||
|
||||
while let Some(location) = stack.pop() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ pub(crate) fn check_tied_features(
|
|||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
None
|
||||
}
|
||||
|
||||
/// Used to generate cfg variables and apply features
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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, .. }))
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)],
|
||||
|
|
|
|||
|
|
@ -1038,7 +1038,7 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
false,
|
||||
);
|
||||
|
||||
return diag.emit();
|
||||
diag.emit()
|
||||
}
|
||||
|
||||
fn check_region_bounds_on_impl_item<'tcx>(
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
|
|||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
true
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -1042,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
false
|
||||
}
|
||||
|
||||
fn explain_self_literal(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ fn extract_iterator_next_call<'tcx>(
|
|||
{
|
||||
Some(recv)
|
||||
} else {
|
||||
return None;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.,
|
||||
|
|
|
|||
|
|
@ -2007,7 +2007,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks if the bound region is in Impl Item.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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!();`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
false
|
||||
}
|
||||
|
||||
fn visit_node(&mut self, node: Node<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -5016,5 +5016,5 @@ fn def_id_matches_path(tcx: TyCtxt<'_>, mut def_id: DefId, expected_path: &[&str
|
|||
}
|
||||
def_id = parent;
|
||||
}
|
||||
return true;
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -779,7 +779,7 @@ impl SourceMap {
|
|||
return Ok(false);
|
||||
}
|
||||
}
|
||||
return Ok(true);
|
||||
Ok(true)
|
||||
})
|
||||
.is_ok_and(|is_accessible| is_accessible)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1236,7 +1236,6 @@ symbols! {
|
|||
mir_unwind_unreachable,
|
||||
mir_variant,
|
||||
miri,
|
||||
missing_docs,
|
||||
mmx_reg,
|
||||
modifiers,
|
||||
module,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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?");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue