Merge pull request #2451 from jieyouxu/rustc-pull
This commit is contained in:
commit
033b829e0a
217 changed files with 3227 additions and 1605 deletions
2
.mailmap
2
.mailmap
|
|
@ -653,7 +653,7 @@ Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
|
|||
Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com>
|
||||
Trevor Gross <tmgross@umich.edu> <tgross@intrepidcs.com>
|
||||
Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt>
|
||||
Tshepang Mbambo <tshepang@gmail.com>
|
||||
Tshepang Mbambo <hopsi@tuta.io> <tshepang@gmail.com>
|
||||
Ty Overby <ty@pre-alpha.com>
|
||||
Tyler Mandry <tmandry@gmail.com> <tmandry@google.com>
|
||||
Tyler Ruckinger <t.ruckinger@gmail.com>
|
||||
|
|
|
|||
52
Cargo.lock
52
Cargo.lock
|
|
@ -177,56 +177,26 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7"
|
||||
dependencies = [
|
||||
"askama_derive 0.13.1",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||
dependencies = [
|
||||
"askama_derive 0.14.0",
|
||||
"askama_derive",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac"
|
||||
dependencies = [
|
||||
"askama_parser 0.13.0",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||
dependencies = [
|
||||
"askama_parser 0.14.0",
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
|
|
@ -237,18 +207,6 @@ dependencies = [
|
|||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow 0.7.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.14.0"
|
||||
|
|
@ -582,7 +540,7 @@ name = "clippy"
|
|||
version = "0.1.89"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama 0.13.1",
|
||||
"askama",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
|
|
@ -1432,7 +1390,7 @@ name = "generate-copyright"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama 0.14.0",
|
||||
"askama",
|
||||
"cargo_metadata 0.18.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -4676,7 +4634,7 @@ name = "rustdoc"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"askama 0.14.0",
|
||||
"askama",
|
||||
"base64",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||
|
|
@ -527,7 +528,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
UseTreeKind::Glob => {
|
||||
let res = self.expect_full_res(id);
|
||||
let res = smallvec![self.lower_res(res)];
|
||||
let res = self.lower_res(res);
|
||||
// Put the result in the appropriate namespace.
|
||||
let res = match res {
|
||||
Res::Def(DefKind::Mod | DefKind::Trait, _) => {
|
||||
PerNS { type_ns: Some(res), value_ns: None, macro_ns: None }
|
||||
}
|
||||
Res::Def(DefKind::Enum, _) => {
|
||||
PerNS { type_ns: None, value_ns: Some(res), macro_ns: None }
|
||||
}
|
||||
Res::Err => {
|
||||
// Propagate the error to all namespaces, just to be sure.
|
||||
let err = Some(Res::Err);
|
||||
PerNS { type_ns: err, value_ns: err, macro_ns: err }
|
||||
}
|
||||
_ => span_bug!(path.span, "bad glob res {:?}", res),
|
||||
};
|
||||
let path = Path { segments, span: path.span, tokens: None };
|
||||
let path = self.lower_use_path(res, &path, ParamMode::Explicit);
|
||||
hir::ItemKind::Use(path, hir::UseKind::Glob)
|
||||
|
|
@ -601,7 +617,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
} else {
|
||||
// For non-empty lists we can just drop all the data, the prefix is already
|
||||
// present in HIR as a part of nested imports.
|
||||
self.arena.alloc(hir::UsePath { res: smallvec![], segments: &[], span })
|
||||
self.arena.alloc(hir::UsePath { res: PerNS::default(), segments: &[], span })
|
||||
};
|
||||
hir::ItemKind::Use(path, hir::UseKind::ListStem)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
|||
use rustc_session::parse::{add_feature_diagnostics, feature_err};
|
||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use smallvec::SmallVec;
|
||||
use thin_vec::ThinVec;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
|
|
@ -705,14 +705,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
|
||||
}
|
||||
|
||||
fn lower_import_res(&mut self, id: NodeId, span: Span) -> SmallVec<[Res; 3]> {
|
||||
let res = self.resolver.get_import_res(id).present_items();
|
||||
let res: SmallVec<_> = res.map(|res| self.lower_res(res)).collect();
|
||||
if res.is_empty() {
|
||||
fn lower_import_res(&mut self, id: NodeId, span: Span) -> PerNS<Option<Res>> {
|
||||
let per_ns = self.resolver.get_import_res(id);
|
||||
let per_ns = per_ns.map(|res| res.map(|res| self.lower_res(res)));
|
||||
if per_ns.is_empty() {
|
||||
// Propagate the error to all namespaces, just to be sure.
|
||||
self.dcx().span_delayed_bug(span, "no resolution for an import");
|
||||
return smallvec![Res::Err];
|
||||
let err = Some(Res::Err);
|
||||
return PerNS { type_ns: err, value_ns: err, macro_ns: err };
|
||||
}
|
||||
res
|
||||
per_ns
|
||||
}
|
||||
|
||||
fn make_lang_item_qpath(
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_hir::def::{DefKind, PartialRes, Res};
|
||||
use rustc_hir::def::{DefKind, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, GenericArg};
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_session::parse::add_feature_diagnostics;
|
||||
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use smallvec::smallvec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::errors::{
|
||||
|
|
@ -226,11 +226,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
pub(crate) fn lower_use_path(
|
||||
&mut self,
|
||||
res: SmallVec<[Res; 3]>,
|
||||
res: PerNS<Option<Res>>,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
) -> &'hir hir::UsePath<'hir> {
|
||||
assert!((1..=3).contains(&res.len()));
|
||||
assert!(!res.is_empty());
|
||||
self.arena.alloc(hir::UsePath {
|
||||
res,
|
||||
segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
|
||||
|
|
|
|||
|
|
@ -840,14 +840,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
} else {
|
||||
bug!("not an upvar")
|
||||
};
|
||||
err.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"calling `{}` requires mutable binding due to {}",
|
||||
self.describe_place(the_place_err).unwrap(),
|
||||
reason
|
||||
),
|
||||
);
|
||||
// sometimes we deliberately don't store the name of a place when coming from a macro in
|
||||
// another crate. We generally want to limit those diagnostics a little, to hide
|
||||
// implementation details (such as those from pin!() or format!()). In that case show a
|
||||
// slightly different error message, or none at all if something else happened. In other
|
||||
// cases the message is likely not useful.
|
||||
if let Some(place_name) = self.describe_place(the_place_err) {
|
||||
err.span_label(
|
||||
*span,
|
||||
format!("calling `{place_name}` requires mutable binding due to {reason}"),
|
||||
);
|
||||
} else if span.from_expansion() {
|
||||
err.span_label(
|
||||
*span,
|
||||
format!("a call in this macro requires a mutable binding due to {reason}",),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use rustc_codegen_ssa::traits::{
|
|||
use rustc_middle::bug;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::callconv::{ArgAbi, PassMode};
|
||||
|
|
@ -205,21 +205,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
span: Span,
|
||||
) -> Result<(), Instance<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let callee_ty = instance.ty(tcx, self.typing_env());
|
||||
|
||||
let (def_id, fn_args) = match *callee_ty.kind() {
|
||||
ty::FnDef(def_id, fn_args) => (def_id, fn_args),
|
||||
_ => bug!("expected fn item type, found {}", callee_ty),
|
||||
};
|
||||
|
||||
let sig = callee_ty.fn_sig(tcx);
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig);
|
||||
let arg_tys = sig.inputs();
|
||||
let ret_ty = sig.output();
|
||||
let name = tcx.item_name(def_id);
|
||||
let name = tcx.item_name(instance.def_id());
|
||||
let name_str = name.as_str();
|
||||
|
||||
let llret_ty = self.layout_of(ret_ty).gcc_type(self);
|
||||
let fn_args = instance.args;
|
||||
|
||||
let simple = get_simple_intrinsic(self, name);
|
||||
let simple_func = get_simple_function(self, name);
|
||||
|
|
@ -320,8 +309,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
| sym::rotate_right
|
||||
| sym::saturating_add
|
||||
| sym::saturating_sub => {
|
||||
let ty = arg_tys[0];
|
||||
match int_type_width_signed(ty, self) {
|
||||
match int_type_width_signed(args[0].layout.ty, self) {
|
||||
Some((width, signed)) => match name {
|
||||
sym::ctlz | sym::cttz => {
|
||||
let func = self.current_func.borrow().expect("func");
|
||||
|
|
@ -400,7 +388,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
|
||||
span,
|
||||
name,
|
||||
ty,
|
||||
ty: args[0].layout.ty,
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -492,7 +480,14 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
}
|
||||
|
||||
_ if name_str.starts_with("simd_") => {
|
||||
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
|
||||
match generic_simd_intrinsic(
|
||||
self,
|
||||
name,
|
||||
args,
|
||||
result.layout.ty,
|
||||
result.layout.gcc_type(self),
|
||||
span,
|
||||
) {
|
||||
Ok(value) => value,
|
||||
Err(()) => return Ok(()),
|
||||
}
|
||||
|
|
@ -503,13 +498,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
};
|
||||
|
||||
if result.layout.ty.is_bool() {
|
||||
OperandRef::from_immediate_or_packed_pair(self, value, result.layout)
|
||||
.val
|
||||
.store(self, result);
|
||||
let val = self.from_immediate(value);
|
||||
self.store_to_place(val, result.val);
|
||||
} else if !result.layout.ty.is_unit() {
|
||||
let ptr_llty = self.type_ptr_to(result.layout.gcc_type(self));
|
||||
let ptr = self.pointercast(result.val.llval, ptr_llty);
|
||||
self.store(value, ptr, result.val.align);
|
||||
self.store_to_place(value, result.val);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ use crate::context::CodegenCx;
|
|||
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
bx: &mut Builder<'a, 'gcc, 'tcx>,
|
||||
name: Symbol,
|
||||
callee_ty: Ty<'tcx>,
|
||||
args: &[OperandRef<'tcx, RValue<'gcc>>],
|
||||
ret_ty: Ty<'tcx>,
|
||||
llret_ty: Type<'gcc>,
|
||||
|
|
@ -54,24 +53,17 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
};
|
||||
}
|
||||
|
||||
let tcx = bx.tcx();
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
callee_ty.fn_sig(tcx),
|
||||
);
|
||||
let arg_tys = sig.inputs();
|
||||
|
||||
if name == sym::simd_select_bitmask {
|
||||
require_simd!(
|
||||
arg_tys[1],
|
||||
InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
|
||||
args[1].layout.ty,
|
||||
InvalidMonomorphization::SimdArgument { span, name, ty: args[1].layout.ty }
|
||||
);
|
||||
let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (len, _) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
|
||||
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
|
||||
let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
|
||||
|
||||
let mask_ty = arg_tys[0];
|
||||
let mask_ty = args[0].layout.ty;
|
||||
let mut mask = match *mask_ty.kind() {
|
||||
ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
|
|
@ -121,8 +113,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
}
|
||||
|
||||
// every intrinsic below takes a SIMD vector as its first argument
|
||||
require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
|
||||
let in_ty = arg_tys[0];
|
||||
require_simd!(
|
||||
args[0].layout.ty,
|
||||
InvalidMonomorphization::SimdInput { span, name, ty: args[0].layout.ty }
|
||||
);
|
||||
let in_ty = args[0].layout.ty;
|
||||
|
||||
let comparison = match name {
|
||||
sym::simd_eq => Some(BinOp::Eq),
|
||||
|
|
@ -134,7 +129,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||
let (in_len, in_elem) = args[0].layout.ty.simd_size_and_type(bx.tcx());
|
||||
if let Some(cmp_op) = comparison {
|
||||
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
|
||||
|
||||
|
|
@ -401,13 +396,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
#[cfg(feature = "master")]
|
||||
if name == sym::simd_insert || name == sym::simd_insert_dyn {
|
||||
require!(
|
||||
in_elem == arg_tys[2],
|
||||
in_elem == args[2].layout.ty,
|
||||
InvalidMonomorphization::InsertedType {
|
||||
span,
|
||||
name,
|
||||
in_elem,
|
||||
in_ty,
|
||||
out_ty: arg_tys[2]
|
||||
out_ty: args[2].layout.ty
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -439,10 +434,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
let m_elem_ty = in_elem;
|
||||
let m_len = in_len;
|
||||
require_simd!(
|
||||
arg_tys[1],
|
||||
InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
|
||||
args[1].layout.ty,
|
||||
InvalidMonomorphization::SimdArgument { span, name, ty: args[1].layout.ty }
|
||||
);
|
||||
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (v_len, _) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
m_len == v_len,
|
||||
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
|
||||
|
|
@ -911,18 +906,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
// All types must be simd vector types
|
||||
require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
|
||||
require_simd!(
|
||||
arg_tys[1],
|
||||
InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
|
||||
args[1].layout.ty,
|
||||
InvalidMonomorphization::SimdSecond { span, name, ty: args[1].layout.ty }
|
||||
);
|
||||
require_simd!(
|
||||
arg_tys[2],
|
||||
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
|
||||
args[2].layout.ty,
|
||||
InvalidMonomorphization::SimdThird { span, name, ty: args[2].layout.ty }
|
||||
);
|
||||
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
|
||||
|
||||
// Of the same length:
|
||||
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
let (out_len, _) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (out_len2, _) = args[2].layout.ty.simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphization::SecondArgumentLength {
|
||||
|
|
@ -930,7 +925,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[1],
|
||||
arg_ty: args[1].layout.ty,
|
||||
out_len
|
||||
}
|
||||
);
|
||||
|
|
@ -941,7 +936,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[2],
|
||||
arg_ty: args[2].layout.ty,
|
||||
out_len: out_len2
|
||||
}
|
||||
);
|
||||
|
|
@ -970,8 +965,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
|
||||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty0) = args[0].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty1) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (pointer_count, underlying_ty) = match *element_ty1.kind() {
|
||||
ty::RawPtr(p_ty, _) if p_ty == in_elem => {
|
||||
(ptr_count(element_ty1), non_ptr(element_ty1))
|
||||
|
|
@ -983,7 +978,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
span,
|
||||
name,
|
||||
expected_element: element_ty1,
|
||||
second_arg: arg_tys[1],
|
||||
second_arg: args[1].layout.ty,
|
||||
in_elem,
|
||||
in_ty,
|
||||
mutability: ExpectedPointerMutability::Not,
|
||||
|
|
@ -998,7 +993,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
|
||||
// The element type of the third argument must be an integer type of any width:
|
||||
// TODO: also support unsigned integers.
|
||||
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty2) = args[2].layout.ty.simd_size_and_type(bx.tcx());
|
||||
match *element_ty2.kind() {
|
||||
ty::Int(_) => (),
|
||||
_ => {
|
||||
|
|
@ -1030,17 +1025,17 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
// All types must be simd vector types
|
||||
require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
|
||||
require_simd!(
|
||||
arg_tys[1],
|
||||
InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
|
||||
args[1].layout.ty,
|
||||
InvalidMonomorphization::SimdSecond { span, name, ty: args[1].layout.ty }
|
||||
);
|
||||
require_simd!(
|
||||
arg_tys[2],
|
||||
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
|
||||
args[2].layout.ty,
|
||||
InvalidMonomorphization::SimdThird { span, name, ty: args[2].layout.ty }
|
||||
);
|
||||
|
||||
// Of the same length:
|
||||
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
let (element_len1, _) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (element_len2, _) = args[2].layout.ty.simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
in_len == element_len1,
|
||||
InvalidMonomorphization::SecondArgumentLength {
|
||||
|
|
@ -1048,7 +1043,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[1],
|
||||
arg_ty: args[1].layout.ty,
|
||||
out_len: element_len1
|
||||
}
|
||||
);
|
||||
|
|
@ -1059,7 +1054,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[2],
|
||||
arg_ty: args[2].layout.ty,
|
||||
out_len: element_len2
|
||||
}
|
||||
);
|
||||
|
|
@ -1082,9 +1077,9 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
|
||||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty0) = args[0].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty1) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty2) = args[2].layout.ty.simd_size_and_type(bx.tcx());
|
||||
let (pointer_count, underlying_ty) = match *element_ty1.kind() {
|
||||
ty::RawPtr(p_ty, mutbl) if p_ty == in_elem && mutbl == hir::Mutability::Mut => {
|
||||
(ptr_count(element_ty1), non_ptr(element_ty1))
|
||||
|
|
@ -1096,7 +1091,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
span,
|
||||
name,
|
||||
expected_element: element_ty1,
|
||||
second_arg: arg_tys[1],
|
||||
second_arg: args[1].layout.ty,
|
||||
in_elem,
|
||||
in_ty,
|
||||
mutability: ExpectedPointerMutability::Mut,
|
||||
|
|
@ -1194,8 +1189,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
return_error!(InvalidMonomorphization::ExpectedVectorElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: arg_tys[0].simd_size_and_type(bx.tcx()).1,
|
||||
vector_type: arg_tys[0],
|
||||
expected_element: args[0].layout.ty.simd_size_and_type(bx.tcx()).1,
|
||||
vector_type: args[0].layout.ty,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -169,19 +169,9 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
span: Span,
|
||||
) -> Result<(), ty::Instance<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let callee_ty = instance.ty(tcx, self.typing_env());
|
||||
|
||||
let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else {
|
||||
bug!("expected fn item type, found {}", callee_ty);
|
||||
};
|
||||
|
||||
let sig = callee_ty.fn_sig(tcx);
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig);
|
||||
let arg_tys = sig.inputs();
|
||||
let ret_ty = sig.output();
|
||||
let name = tcx.item_name(def_id);
|
||||
|
||||
let llret_ty = self.layout_of(ret_ty).llvm_type(self);
|
||||
let name = tcx.item_name(instance.def_id());
|
||||
let fn_args = instance.args;
|
||||
|
||||
let simple = get_simple_intrinsic(self, name);
|
||||
let llval = match name {
|
||||
|
|
@ -265,22 +255,22 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
BackendRepr::Scalar(scalar) => {
|
||||
match scalar.primitive() {
|
||||
Primitive::Int(..) => {
|
||||
if self.cx().size_of(ret_ty).bytes() < 4 {
|
||||
if self.cx().size_of(result.layout.ty).bytes() < 4 {
|
||||
// `va_arg` should not be called on an integer type
|
||||
// less than 4 bytes in length. If it is, promote
|
||||
// the integer to an `i32` and truncate the result
|
||||
// back to the smaller type.
|
||||
let promoted_result = emit_va_arg(self, args[0], tcx.types.i32);
|
||||
self.trunc(promoted_result, llret_ty)
|
||||
self.trunc(promoted_result, result.layout.llvm_type(self))
|
||||
} else {
|
||||
emit_va_arg(self, args[0], ret_ty)
|
||||
emit_va_arg(self, args[0], result.layout.ty)
|
||||
}
|
||||
}
|
||||
Primitive::Float(Float::F16) => {
|
||||
bug!("the va_arg intrinsic does not work with `f16`")
|
||||
}
|
||||
Primitive::Float(Float::F64) | Primitive::Pointer(_) => {
|
||||
emit_va_arg(self, args[0], ret_ty)
|
||||
emit_va_arg(self, args[0], result.layout.ty)
|
||||
}
|
||||
// `va_arg` should never be used with the return type f32.
|
||||
Primitive::Float(Float::F32) => {
|
||||
|
|
@ -384,7 +374,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
| sym::rotate_right
|
||||
| sym::saturating_add
|
||||
| sym::saturating_sub => {
|
||||
let ty = arg_tys[0];
|
||||
let ty = args[0].layout.ty;
|
||||
if !ty.is_integral() {
|
||||
tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
|
||||
span,
|
||||
|
|
@ -403,26 +393,26 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
&[args[0].immediate(), y],
|
||||
);
|
||||
|
||||
self.intcast(ret, llret_ty, false)
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::ctlz_nonzero => {
|
||||
let y = self.const_bool(true);
|
||||
let llvm_name = &format!("llvm.ctlz.i{width}");
|
||||
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
|
||||
self.intcast(ret, llret_ty, false)
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::cttz_nonzero => {
|
||||
let y = self.const_bool(true);
|
||||
let llvm_name = &format!("llvm.cttz.i{width}");
|
||||
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
|
||||
self.intcast(ret, llret_ty, false)
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::ctpop => {
|
||||
let ret = self.call_intrinsic(
|
||||
&format!("llvm.ctpop.i{width}"),
|
||||
&[args[0].immediate()],
|
||||
);
|
||||
self.intcast(ret, llret_ty, false)
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::bswap => {
|
||||
if width == 8 {
|
||||
|
|
@ -554,16 +544,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
// Unpack non-power-of-2 #[repr(packed, simd)] arguments.
|
||||
// This gives them the expected layout of a regular #[repr(simd)] vector.
|
||||
let mut loaded_args = Vec::new();
|
||||
for (ty, arg) in arg_tys.iter().zip(args) {
|
||||
for arg in args {
|
||||
loaded_args.push(
|
||||
// #[repr(packed, simd)] vectors are passed like arrays (as references,
|
||||
// with reduced alignment and no padding) rather than as immediates.
|
||||
// We can use a vector load to fix the layout and turn the argument
|
||||
// into an immediate.
|
||||
if ty.is_simd()
|
||||
if arg.layout.ty.is_simd()
|
||||
&& let OperandValue::Ref(place) = arg.val
|
||||
{
|
||||
let (size, elem_ty) = ty.simd_size_and_type(self.tcx());
|
||||
let (size, elem_ty) = arg.layout.ty.simd_size_and_type(self.tcx());
|
||||
let elem_ll_ty = match elem_ty.kind() {
|
||||
ty::Float(f) => self.type_float_from_ty(*f),
|
||||
ty::Int(i) => self.type_int_from_ty(*i),
|
||||
|
|
@ -580,10 +570,10 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let llret_ty = if ret_ty.is_simd()
|
||||
&& let BackendRepr::Memory { .. } = self.layout_of(ret_ty).layout.backend_repr
|
||||
let llret_ty = if result.layout.ty.is_simd()
|
||||
&& let BackendRepr::Memory { .. } = result.layout.backend_repr
|
||||
{
|
||||
let (size, elem_ty) = ret_ty.simd_size_and_type(self.tcx());
|
||||
let (size, elem_ty) = result.layout.ty.simd_size_and_type(self.tcx());
|
||||
let elem_ll_ty = match elem_ty.kind() {
|
||||
ty::Float(f) => self.type_float_from_ty(*f),
|
||||
ty::Int(i) => self.type_int_from_ty(*i),
|
||||
|
|
@ -593,16 +583,15 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
};
|
||||
self.type_vector(elem_ll_ty, size)
|
||||
} else {
|
||||
llret_ty
|
||||
result.layout.llvm_type(self)
|
||||
};
|
||||
|
||||
match generic_simd_intrinsic(
|
||||
self,
|
||||
name,
|
||||
callee_ty,
|
||||
fn_args,
|
||||
&loaded_args,
|
||||
ret_ty,
|
||||
result.layout.ty,
|
||||
llret_ty,
|
||||
span,
|
||||
) {
|
||||
|
|
@ -621,9 +610,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
};
|
||||
|
||||
if result.layout.ty.is_bool() {
|
||||
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
|
||||
.val
|
||||
.store(self, result);
|
||||
let val = self.from_immediate(llval);
|
||||
self.store_to_place(val, result.val);
|
||||
} else if !result.layout.ty.is_unit() {
|
||||
self.store_to_place(llval, result.val);
|
||||
}
|
||||
|
|
@ -1151,7 +1139,6 @@ fn get_rust_try_fn<'a, 'll, 'tcx>(
|
|||
fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
name: Symbol,
|
||||
callee_ty: Ty<'tcx>,
|
||||
fn_args: GenericArgsRef<'tcx>,
|
||||
args: &[OperandRef<'tcx, &'ll Value>],
|
||||
ret_ty: Ty<'tcx>,
|
||||
|
|
@ -1222,26 +1209,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len))
|
||||
}
|
||||
|
||||
let tcx = bx.tcx();
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(bx.typing_env(), callee_ty.fn_sig(tcx));
|
||||
let arg_tys = sig.inputs();
|
||||
|
||||
// Sanity-check: all vector arguments must be immediates.
|
||||
if cfg!(debug_assertions) {
|
||||
for (ty, arg) in arg_tys.iter().zip(args) {
|
||||
if ty.is_simd() {
|
||||
for arg in args {
|
||||
if arg.layout.ty.is_simd() {
|
||||
assert_matches!(arg.val, OperandValue::Immediate(_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if name == sym::simd_select_bitmask {
|
||||
let (len, _) = require_simd!(arg_tys[1], SimdArgument);
|
||||
let (len, _) = require_simd!(args[1].layout.ty, SimdArgument);
|
||||
|
||||
let expected_int_bits = len.max(8).next_power_of_two();
|
||||
let expected_bytes = len.div_ceil(8);
|
||||
|
||||
let mask_ty = arg_tys[0];
|
||||
let mask_ty = args[0].layout.ty;
|
||||
let mask = match mask_ty.kind() {
|
||||
ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
|
|
@ -1275,8 +1258,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
// every intrinsic below takes a SIMD vector as its first argument
|
||||
let (in_len, in_elem) = require_simd!(arg_tys[0], SimdInput);
|
||||
let in_ty = arg_tys[0];
|
||||
let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput);
|
||||
let in_ty = args[0].layout.ty;
|
||||
|
||||
let comparison = match name {
|
||||
sym::simd_eq => Some(BinOp::Eq),
|
||||
|
|
@ -1407,13 +1390,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
|
||||
if name == sym::simd_insert || name == sym::simd_insert_dyn {
|
||||
require!(
|
||||
in_elem == arg_tys[2],
|
||||
in_elem == args[2].layout.ty,
|
||||
InvalidMonomorphization::InsertedType {
|
||||
span,
|
||||
name,
|
||||
in_elem,
|
||||
in_ty,
|
||||
out_ty: arg_tys[2]
|
||||
out_ty: args[2].layout.ty
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -1464,7 +1447,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
if name == sym::simd_select {
|
||||
let m_elem_ty = in_elem;
|
||||
let m_len = in_len;
|
||||
let (v_len, _) = require_simd!(arg_tys[1], SimdArgument);
|
||||
let (v_len, _) = require_simd!(args[1].layout.ty, SimdArgument);
|
||||
require!(
|
||||
m_len == v_len,
|
||||
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
|
||||
|
|
@ -1665,9 +1648,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = require_simd!(in_ty, SimdFirst);
|
||||
let (out_len, element_ty1) = require_simd!(arg_tys[1], SimdSecond);
|
||||
let (out_len, element_ty1) = require_simd!(args[1].layout.ty, SimdSecond);
|
||||
// The element type of the third argument must be a signed integer type of any width:
|
||||
let (out_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird);
|
||||
let (out_len2, element_ty2) = require_simd!(args[2].layout.ty, SimdThird);
|
||||
require_simd!(ret_ty, SimdReturn);
|
||||
|
||||
// Of the same length:
|
||||
|
|
@ -1678,7 +1661,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[1],
|
||||
arg_ty: args[1].layout.ty,
|
||||
out_len
|
||||
}
|
||||
);
|
||||
|
|
@ -1689,7 +1672,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[2],
|
||||
arg_ty: args[2].layout.ty,
|
||||
out_len: out_len2
|
||||
}
|
||||
);
|
||||
|
|
@ -1709,7 +1692,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
span,
|
||||
name,
|
||||
expected_element: element_ty1,
|
||||
second_arg: arg_tys[1],
|
||||
second_arg: args[1].layout.ty,
|
||||
in_elem,
|
||||
in_ty,
|
||||
mutability: ExpectedPointerMutability::Not,
|
||||
|
|
@ -1770,10 +1753,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let (mask_len, mask_elem) = (in_len, in_elem);
|
||||
|
||||
// The second argument must be a pointer matching the element type
|
||||
let pointer_ty = arg_tys[1];
|
||||
let pointer_ty = args[1].layout.ty;
|
||||
|
||||
// The last argument is a passthrough vector providing values for disabled lanes
|
||||
let values_ty = arg_tys[2];
|
||||
let values_ty = args[2].layout.ty;
|
||||
let (values_len, values_elem) = require_simd!(values_ty, SimdThird);
|
||||
|
||||
require_simd!(ret_ty, SimdReturn);
|
||||
|
|
@ -1861,10 +1844,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let (mask_len, mask_elem) = (in_len, in_elem);
|
||||
|
||||
// The second argument must be a pointer matching the element type
|
||||
let pointer_ty = arg_tys[1];
|
||||
let pointer_ty = args[1].layout.ty;
|
||||
|
||||
// The last argument specifies the values to store to memory
|
||||
let values_ty = arg_tys[2];
|
||||
let values_ty = args[2].layout.ty;
|
||||
let (values_len, values_elem) = require_simd!(values_ty, SimdThird);
|
||||
|
||||
// Of the same length:
|
||||
|
|
@ -1944,8 +1927,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = require_simd!(in_ty, SimdFirst);
|
||||
let (element_len1, element_ty1) = require_simd!(arg_tys[1], SimdSecond);
|
||||
let (element_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird);
|
||||
let (element_len1, element_ty1) = require_simd!(args[1].layout.ty, SimdSecond);
|
||||
let (element_len2, element_ty2) = require_simd!(args[2].layout.ty, SimdThird);
|
||||
|
||||
// Of the same length:
|
||||
require!(
|
||||
|
|
@ -1955,7 +1938,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[1],
|
||||
arg_ty: args[1].layout.ty,
|
||||
out_len: element_len1
|
||||
}
|
||||
);
|
||||
|
|
@ -1966,7 +1949,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
arg_ty: arg_tys[2],
|
||||
arg_ty: args[2].layout.ty,
|
||||
out_len: element_len2
|
||||
}
|
||||
);
|
||||
|
|
@ -1981,7 +1964,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
span,
|
||||
name,
|
||||
expected_element: element_ty1,
|
||||
second_arg: arg_tys[1],
|
||||
second_arg: args[1].layout.ty,
|
||||
in_elem,
|
||||
in_ty,
|
||||
mutability: ExpectedPointerMutability::Mut,
|
||||
|
|
@ -2503,7 +2486,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let ptrs = args[0].immediate();
|
||||
// The second argument must be a ptr-sized integer.
|
||||
// (We don't care about the signedness, this is wrapping anyway.)
|
||||
let (_offsets_len, offsets_elem) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (_offsets_len, offsets_elem) = args[1].layout.ty.simd_size_and_type(bx.tcx());
|
||||
if !matches!(offsets_elem.kind(), ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize)) {
|
||||
span_bug!(
|
||||
span,
|
||||
|
|
@ -2527,8 +2510,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
return_error!(InvalidMonomorphization::ExpectedVectorElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: arg_tys[0].simd_size_and_type(bx.tcx()).1,
|
||||
vector_type: arg_tys[0]
|
||||
expected_element: args[0].layout.ty.simd_size_and_type(bx.tcx()).1,
|
||||
vector_type: args[0].layout.ty
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ mod raw_dylib;
|
|||
use std::collections::BTreeSet;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{File, OpenOptions, read};
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::io::{BufReader, BufWriter, Write};
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Output, Stdio};
|
||||
|
|
@ -184,6 +184,12 @@ pub fn link_binary(
|
|||
);
|
||||
}
|
||||
|
||||
if sess.target.binary_format == BinaryFormat::Elf {
|
||||
if let Err(err) = warn_if_linked_with_gold(sess, &out_filename) {
|
||||
info!(?err, "Error while checking if gold was the linker");
|
||||
}
|
||||
}
|
||||
|
||||
if output.is_stdout() {
|
||||
if output.is_tty() {
|
||||
sess.dcx().emit_err(errors::BinaryOutputToTty {
|
||||
|
|
@ -3375,3 +3381,54 @@ fn add_lld_args(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gold has been deprecated with binutils 2.44
|
||||
// and is known to behave incorrectly around Rust programs.
|
||||
// There have been reports of being unable to bootstrap with gold:
|
||||
// https://github.com/rust-lang/rust/issues/139425
|
||||
// Additionally, gold miscompiles SHF_GNU_RETAIN sections, which are
|
||||
// emitted with `#[used(linker)]`.
|
||||
fn warn_if_linked_with_gold(sess: &Session, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use object::read::elf::{FileHeader, SectionHeader};
|
||||
use object::read::{ReadCache, ReadRef, Result};
|
||||
use object::{Endianness, elf};
|
||||
|
||||
fn elf_has_gold_version_note<'a>(
|
||||
elf: &impl FileHeader,
|
||||
data: impl ReadRef<'a>,
|
||||
) -> Result<bool> {
|
||||
let endian = elf.endian()?;
|
||||
|
||||
let section =
|
||||
elf.sections(endian, data)?.section_by_name(endian, b".note.gnu.gold-version");
|
||||
if let Some((_, section)) = section {
|
||||
if let Some(mut notes) = section.notes(endian, data)? {
|
||||
return Ok(notes.any(|note| {
|
||||
note.is_ok_and(|note| note.n_type(endian) == elf::NT_GNU_GOLD_VERSION)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
let data = ReadCache::new(BufReader::new(File::open(path)?));
|
||||
|
||||
let was_linked_with_gold = if sess.target.pointer_width == 64 {
|
||||
let elf = elf::FileHeader64::<Endianness>::parse(&data)?;
|
||||
elf_has_gold_version_note(elf, &data)?
|
||||
} else if sess.target.pointer_width == 32 {
|
||||
let elf = elf::FileHeader32::<Endianness>::parse(&data)?;
|
||||
elf_has_gold_version_note(elf, &data)?
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if was_linked_with_gold {
|
||||
let mut warn =
|
||||
sess.dcx().struct_warn("the gold linker is deprecated and has known bugs with Rust");
|
||||
warn.help("consider using LLD or ld from GNU binutils instead");
|
||||
warn.emit();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_abi::WrappingRange;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::SourceInfo;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::sym;
|
||||
|
||||
|
|
@ -60,18 +60,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
source_info: SourceInfo,
|
||||
) -> Result<(), ty::Instance<'tcx>> {
|
||||
let span = source_info.span;
|
||||
let callee_ty = instance.ty(bx.tcx(), bx.typing_env());
|
||||
|
||||
let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else {
|
||||
span_bug!(span, "expected fn item type, found {}", callee_ty);
|
||||
};
|
||||
|
||||
let sig = callee_ty.fn_sig(bx.tcx());
|
||||
let sig = bx.tcx().normalize_erasing_late_bound_regions(bx.typing_env(), sig);
|
||||
let arg_tys = sig.inputs();
|
||||
let ret_ty = sig.output();
|
||||
let name = bx.tcx().item_name(def_id);
|
||||
let name = bx.tcx().item_name(instance.def_id());
|
||||
let name_str = name.as_str();
|
||||
let fn_args = instance.args;
|
||||
|
||||
// If we're swapping something that's *not* an `OperandValue::Ref`,
|
||||
// then we can do it directly and avoid the alloca.
|
||||
|
|
@ -97,13 +89,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
let llret_ty = bx.backend_type(bx.layout_of(ret_ty));
|
||||
|
||||
let ret_llval = |bx: &mut Bx, llval| {
|
||||
if result.layout.ty.is_bool() {
|
||||
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
|
||||
.val
|
||||
.store(bx, result);
|
||||
let val = bx.from_immediate(llval);
|
||||
bx.store_to_place(val, result.val);
|
||||
} else if !result.layout.ty.is_unit() {
|
||||
bx.store_to_place(llval, result.val);
|
||||
}
|
||||
|
|
@ -143,7 +132,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN,
|
||||
_ => bug!(),
|
||||
};
|
||||
let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable, callee_ty);
|
||||
let value = meth::VirtualIndex::from_index(idx).get_usize(
|
||||
bx,
|
||||
vtable,
|
||||
instance.ty(bx.tcx(), bx.typing_env()),
|
||||
);
|
||||
match name {
|
||||
// Size is always <= isize::MAX.
|
||||
sym::vtable_size => {
|
||||
|
|
@ -164,7 +157,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
| sym::type_name
|
||||
| sym::variant_count => {
|
||||
let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap();
|
||||
OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
|
||||
OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx)
|
||||
}
|
||||
sym::arith_offset => {
|
||||
let ty = fn_args.type_at(0);
|
||||
|
|
@ -248,7 +241,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.or_disjoint(a, b)
|
||||
}
|
||||
sym::exact_div => {
|
||||
let ty = arg_tys[0];
|
||||
let ty = args[0].layout.ty;
|
||||
match int_type_width_signed(ty, bx.tcx()) {
|
||||
Some((_width, signed)) => {
|
||||
if signed {
|
||||
|
|
@ -268,7 +261,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
|
||||
match float_type_width(arg_tys[0]) {
|
||||
match float_type_width(args[0].layout.ty) {
|
||||
Some(_width) => match name {
|
||||
sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()),
|
||||
sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()),
|
||||
|
|
@ -281,7 +274,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
|
||||
span,
|
||||
name,
|
||||
ty: arg_tys[0],
|
||||
ty: args[0].layout.ty,
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -291,7 +284,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
| sym::fsub_algebraic
|
||||
| sym::fmul_algebraic
|
||||
| sym::fdiv_algebraic
|
||||
| sym::frem_algebraic => match float_type_width(arg_tys[0]) {
|
||||
| sym::frem_algebraic => match float_type_width(args[0].layout.ty) {
|
||||
Some(_width) => match name {
|
||||
sym::fadd_algebraic => {
|
||||
bx.fadd_algebraic(args[0].immediate(), args[1].immediate())
|
||||
|
|
@ -314,31 +307,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
|
||||
span,
|
||||
name,
|
||||
ty: arg_tys[0],
|
||||
ty: args[0].layout.ty,
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
|
||||
sym::float_to_int_unchecked => {
|
||||
if float_type_width(arg_tys[0]).is_none() {
|
||||
if float_type_width(args[0].layout.ty).is_none() {
|
||||
bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
|
||||
span,
|
||||
ty: arg_tys[0],
|
||||
ty: args[0].layout.ty,
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
|
||||
let Some((_width, signed)) = int_type_width_signed(result.layout.ty, bx.tcx())
|
||||
else {
|
||||
bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
|
||||
span,
|
||||
ty: ret_ty,
|
||||
ty: result.layout.ty,
|
||||
});
|
||||
return Ok(());
|
||||
};
|
||||
if signed {
|
||||
bx.fptosi(args[0].immediate(), llret_ty)
|
||||
bx.fptosi(args[0].immediate(), bx.backend_type(result.layout))
|
||||
} else {
|
||||
bx.fptoui(args[0].immediate(), llret_ty)
|
||||
bx.fptoui(args[0].immediate(), bx.backend_type(result.layout))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,18 @@
|
|||
//! green/native threading. This is just a bare-bones enough solution for
|
||||
//! librustdoc, it is not production quality at all.
|
||||
|
||||
cfg_select! {
|
||||
// cfg(bootstrap)
|
||||
macro_rules! cfg_select_dispatch {
|
||||
($($tokens:tt)*) => {
|
||||
#[cfg(bootstrap)]
|
||||
cfg_match! { $($tokens)* }
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
cfg_select! { $($tokens)* }
|
||||
};
|
||||
}
|
||||
|
||||
cfg_select_dispatch! {
|
||||
target_os = "linux" => {
|
||||
mod linux;
|
||||
use linux as imp;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![cfg_attr(bootstrap, feature(cfg_match))]
|
||||
#![cfg_attr(not(bootstrap), feature(cfg_select))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
|
|
@ -19,7 +21,6 @@
|
|||
#![feature(ascii_char_variants)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(auto_traits)]
|
||||
#![feature(cfg_select)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(extend_one)]
|
||||
|
|
|
|||
|
|
@ -859,8 +859,19 @@ fn get_thread_id() -> u32 {
|
|||
std::thread::current().id().as_u64().get() as u32
|
||||
}
|
||||
|
||||
// cfg(bootstrap)
|
||||
macro_rules! cfg_select_dispatch {
|
||||
($($tokens:tt)*) => {
|
||||
#[cfg(bootstrap)]
|
||||
cfg_match! { $($tokens)* }
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
cfg_select! { $($tokens)* }
|
||||
};
|
||||
}
|
||||
|
||||
// Memory reporting
|
||||
cfg_select! {
|
||||
cfg_select_dispatch! {
|
||||
windows => {
|
||||
pub fn get_resident_set_size() -> Option<usize> {
|
||||
use windows::{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ macro_rules! arena_types {
|
|||
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
|
||||
[] attribute: rustc_hir::Attribute,
|
||||
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
|
||||
[] use_path: rustc_hir::UsePath<'tcx>,
|
||||
[] lit: rustc_hir::Lit,
|
||||
[] macro_def: rustc_ast::MacroDef,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -584,7 +584,7 @@ impl<CTX: crate::HashStableContext> ToStableHashKey<CTX> for Namespace {
|
|||
}
|
||||
|
||||
/// Just a helper ‒ separate structure for each namespace.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
#[derive(Copy, Clone, Default, Debug, HashStable_Generic)]
|
||||
pub struct PerNS<T> {
|
||||
pub value_ns: T,
|
||||
pub type_ns: T,
|
||||
|
|
@ -596,10 +596,16 @@ impl<T> PerNS<T> {
|
|||
PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) }
|
||||
}
|
||||
|
||||
/// Note: Do you really want to use this? Often you know which namespace a
|
||||
/// name will belong in, and you can consider just that namespace directly,
|
||||
/// rather than iterating through all of them.
|
||||
pub fn into_iter(self) -> IntoIter<T, 3> {
|
||||
[self.value_ns, self.type_ns, self.macro_ns].into_iter()
|
||||
}
|
||||
|
||||
/// Note: Do you really want to use this? Often you know which namespace a
|
||||
/// name will belong in, and you can consider just that namespace directly,
|
||||
/// rather than iterating through all of them.
|
||||
pub fn iter(&self) -> IntoIter<&T, 3> {
|
||||
[&self.value_ns, &self.type_ns, &self.macro_ns].into_iter()
|
||||
}
|
||||
|
|
@ -634,6 +640,10 @@ impl<T> PerNS<Option<T>> {
|
|||
}
|
||||
|
||||
/// Returns an iterator over the items which are `Some`.
|
||||
///
|
||||
/// Note: Do you really want to use this? Often you know which namespace a
|
||||
/// name will belong in, and you can consider just that namespace directly,
|
||||
/// rather than iterating through all of them.
|
||||
pub fn present_items(self) -> impl Iterator<Item = T> {
|
||||
[self.type_ns, self.value_ns, self.macro_ns].into_iter().flatten()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use thin_vec::ThinVec;
|
|||
use tracing::debug;
|
||||
|
||||
use crate::LangItem;
|
||||
use crate::def::{CtorKind, DefKind, Res};
|
||||
use crate::def::{CtorKind, DefKind, PerNS, Res};
|
||||
use crate::def_id::{DefId, LocalDefIdMap};
|
||||
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
|
||||
use crate::intravisit::{FnKind, VisitorExt};
|
||||
|
|
@ -347,7 +347,7 @@ pub struct Path<'hir, R = Res> {
|
|||
}
|
||||
|
||||
/// Up to three resolutions for type, value and macro namespaces.
|
||||
pub type UsePath<'hir> = Path<'hir, SmallVec<[Res; 3]>>;
|
||||
pub type UsePath<'hir> = Path<'hir, PerNS<Option<Res>>>;
|
||||
|
||||
impl Path<'_> {
|
||||
pub fn is_global(&self) -> bool {
|
||||
|
|
@ -2370,6 +2370,10 @@ impl Expr<'_> {
|
|||
// Lang item paths cannot currently be local variables or statics.
|
||||
ExprKind::Path(QPath::LangItem(..)) => false,
|
||||
|
||||
// Suppress errors for bad expressions.
|
||||
ExprKind::Err(_guar)
|
||||
| ExprKind::Let(&LetExpr { recovered: ast::Recovered::Yes(_guar), .. }) => true,
|
||||
|
||||
// Partially qualified paths in expressions can only legally
|
||||
// refer to associated items which are always rvalues.
|
||||
ExprKind::Path(QPath::TypeRelative(..))
|
||||
|
|
@ -2401,8 +2405,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Binary(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Cast(..)
|
||||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Err(_) => false,
|
||||
| ExprKind::DropTemps(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1148,7 +1148,7 @@ pub fn walk_use<'v, V: Visitor<'v>>(
|
|||
hir_id: HirId,
|
||||
) -> V::Result {
|
||||
let UsePath { segments, ref res, span } = *path;
|
||||
for &res in res {
|
||||
for res in res.present_items() {
|
||||
try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id));
|
||||
}
|
||||
V::Result::output()
|
||||
|
|
|
|||
|
|
@ -1012,10 +1012,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
{
|
||||
tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
|
||||
}
|
||||
});
|
||||
});
|
||||
sess.time("coroutine_obligations", || {
|
||||
tcx.par_hir_body_owners(|def_id| {
|
||||
if tcx.is_coroutine(def_id.to_def_id()) {
|
||||
tcx.ensure_ok().mir_coroutine_witnesses(def_id);
|
||||
let _ = tcx.ensure_ok().check_coroutine_obligations(
|
||||
|
|
|
|||
|
|
@ -715,6 +715,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
untracked!(no_analysis, true);
|
||||
untracked!(no_leak_check, true);
|
||||
untracked!(no_parallel_backend, true);
|
||||
untracked!(no_steal_thir, true);
|
||||
untracked!(parse_crate_root_only, true);
|
||||
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
|
||||
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
|
||||
|
|
|
|||
|
|
@ -328,16 +328,19 @@ impl<'tcx> LateLintPass<'tcx> for TypeIr {
|
|||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return };
|
||||
|
||||
let is_mod_inherent = |def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id);
|
||||
let is_mod_inherent = |res: Res| {
|
||||
res.opt_def_id()
|
||||
.is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id))
|
||||
};
|
||||
|
||||
// Path segments except for the final.
|
||||
if let Some(seg) =
|
||||
path.segments.iter().find(|seg| seg.res.opt_def_id().is_some_and(is_mod_inherent))
|
||||
{
|
||||
if let Some(seg) = path.segments.iter().find(|seg| is_mod_inherent(seg.res)) {
|
||||
cx.emit_span_lint(USAGE_OF_TYPE_IR_INHERENT, seg.ident.span, TypeIrInherentUsage);
|
||||
}
|
||||
// Final path resolutions, like `use rustc_type_ir::inherent`
|
||||
else if path.res.iter().any(|res| res.opt_def_id().is_some_and(is_mod_inherent)) {
|
||||
else if let Some(type_ns) = path.res.type_ns
|
||||
&& is_mod_inherent(type_ns)
|
||||
{
|
||||
cx.emit_span_lint(
|
||||
USAGE_OF_TYPE_IR_INHERENT,
|
||||
path.segments.last().unwrap().ident.span,
|
||||
|
|
@ -346,13 +349,12 @@ impl<'tcx> LateLintPass<'tcx> for TypeIr {
|
|||
}
|
||||
|
||||
let (lo, hi, snippet) = match path.segments {
|
||||
[.., penultimate, segment]
|
||||
if penultimate.res.opt_def_id().is_some_and(is_mod_inherent) =>
|
||||
{
|
||||
[.., penultimate, segment] if is_mod_inherent(penultimate.res) => {
|
||||
(segment.ident.span, item.kind.ident().unwrap().span, "*")
|
||||
}
|
||||
[.., segment]
|
||||
if path.res.iter().flat_map(Res::opt_def_id).any(is_mod_inherent)
|
||||
if let Some(type_ns) = path.res.type_ns
|
||||
&& is_mod_inherent(type_ns)
|
||||
&& let rustc_hir::UseKind::Single(ident) = kind =>
|
||||
{
|
||||
let (lo, snippet) =
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::kw;
|
||||
|
|
@ -47,17 +46,15 @@ declare_lint_pass!(UnqualifiedLocalImports => [UNQUALIFIED_LOCAL_IMPORTS]);
|
|||
impl<'tcx> LateLintPass<'tcx> for UnqualifiedLocalImports {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let hir::ItemKind::Use(path, _kind) = item.kind else { return };
|
||||
// `path` has three resolutions for the type, module, value namespaces.
|
||||
// Check if any of them qualifies: local crate, and not a macro.
|
||||
// (Macros can't be imported any other way so we don't complain about them.)
|
||||
let is_local_import = |res: &Res| {
|
||||
matches!(
|
||||
res,
|
||||
hir::def::Res::Def(def_kind, def_id)
|
||||
if def_id.is_local() && !matches!(def_kind, DefKind::Macro(_)),
|
||||
)
|
||||
};
|
||||
if !path.res.iter().any(is_local_import) {
|
||||
// Check the type and value namespace resolutions for a local crate.
|
||||
let is_local_import = matches!(
|
||||
path.res.type_ns,
|
||||
Some(hir::def::Res::Def(_, def_id)) if def_id.is_local()
|
||||
) || matches!(
|
||||
path.res.value_ns,
|
||||
Some(hir::def::Res::Def(_, def_id)) if def_id.is_local()
|
||||
);
|
||||
if !is_local_import {
|
||||
return;
|
||||
}
|
||||
// So this does refer to something local. Let's check whether it starts with `self`,
|
||||
|
|
|
|||
|
|
@ -535,7 +535,8 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Fetch the THIR for a given body.
|
||||
/// Fetch the THIR for a given body. The THIR body gets stolen by unsafety checking unless
|
||||
/// `-Zno-steal-thir` is on.
|
||||
query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> {
|
||||
// Perf tests revealed that hashing THIR is inefficient (see #85729).
|
||||
no_hash
|
||||
|
|
|
|||
|
|
@ -201,9 +201,14 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
|||
/// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body.
|
||||
fn visit_inner_body(&mut self, def: LocalDefId) {
|
||||
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
|
||||
// Runs all other queries that depend on THIR.
|
||||
// Run all other queries that depend on THIR.
|
||||
self.tcx.ensure_done().mir_built(def);
|
||||
let inner_thir = &inner_thir.steal();
|
||||
let inner_thir = if self.tcx.sess.opts.unstable_opts.no_steal_thir {
|
||||
&inner_thir.borrow()
|
||||
} else {
|
||||
// We don't have other use for the THIR. Steal it to reduce memory usage.
|
||||
&inner_thir.steal()
|
||||
};
|
||||
let hir_context = self.tcx.local_def_id_to_hir_id(def);
|
||||
let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
|
||||
let mut inner_visitor = UnsafetyVisitor {
|
||||
|
|
@ -1157,7 +1162,12 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
|
|||
let Ok((thir, expr)) = tcx.thir_body(def) else { return };
|
||||
// Runs all other queries that depend on THIR.
|
||||
tcx.ensure_done().mir_built(def);
|
||||
let thir = &thir.steal();
|
||||
let thir = if tcx.sess.opts.unstable_opts.no_steal_thir {
|
||||
&thir.borrow()
|
||||
} else {
|
||||
// We don't have other use for the THIR. Steal it to reduce memory usage.
|
||||
&thir.steal()
|
||||
};
|
||||
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def);
|
||||
let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
|
||||
|
|
|
|||
|
|
@ -1047,26 +1047,21 @@ fn find_fallback_pattern_typo<'tcx>(
|
|||
let hir::ItemKind::Use(path, _) = item.kind else {
|
||||
continue;
|
||||
};
|
||||
for res in &path.res {
|
||||
if let Res::Def(DefKind::Const, id) = res
|
||||
&& infcx.can_eq(param_env, ty, cx.tcx.type_of(id).instantiate_identity())
|
||||
{
|
||||
if cx.tcx.visibility(id).is_accessible_from(parent, cx.tcx) {
|
||||
// The original const is accessible, suggest using it directly.
|
||||
let item_name = cx.tcx.item_name(*id);
|
||||
accessible.push(item_name);
|
||||
accessible_path.push(with_no_trimmed_paths!(cx.tcx.def_path_str(id)));
|
||||
} else if cx
|
||||
.tcx
|
||||
.visibility(item.owner_id)
|
||||
.is_accessible_from(parent, cx.tcx)
|
||||
{
|
||||
// The const is accessible only through the re-export, point at
|
||||
// the `use`.
|
||||
let ident = item.kind.ident().unwrap();
|
||||
imported.push(ident.name);
|
||||
imported_spans.push(ident.span);
|
||||
}
|
||||
if let Some(value_ns) = path.res.value_ns
|
||||
&& let Res::Def(DefKind::Const, id) = value_ns
|
||||
&& infcx.can_eq(param_env, ty, cx.tcx.type_of(id).instantiate_identity())
|
||||
{
|
||||
if cx.tcx.visibility(id).is_accessible_from(parent, cx.tcx) {
|
||||
// The original const is accessible, suggest using it directly.
|
||||
let item_name = cx.tcx.item_name(id);
|
||||
accessible.push(item_name);
|
||||
accessible_path.push(with_no_trimmed_paths!(cx.tcx.def_path_str(id)));
|
||||
} else if cx.tcx.visibility(item.owner_id).is_accessible_from(parent, cx.tcx) {
|
||||
// The const is accessible only through the re-export, point at
|
||||
// the `use`.
|
||||
let ident = item.kind.ident().unwrap();
|
||||
imported.push(ident.name);
|
||||
imported_spans.push(ident.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{fmt, iter, mem};
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::mir::*;
|
||||
|
|
@ -254,8 +255,19 @@ where
|
|||
// impl_item_refs may be empty if drop fn is not implemented in 'impl AsyncDrop for ...'
|
||||
// (#140974).
|
||||
// Such code will report error, so just generate sync drop here and return
|
||||
let Some(drop_fn_def_id) =
|
||||
tcx.associated_item_def_ids(drop_trait).into_iter().nth(0).copied()
|
||||
let Some(drop_fn_def_id) = tcx
|
||||
.associated_item_def_ids(drop_trait)
|
||||
.first()
|
||||
.and_then(|def_id| {
|
||||
if tcx.def_kind(def_id) == DefKind::AssocFn
|
||||
&& tcx.check_args_compatible(*def_id, trait_args)
|
||||
{
|
||||
Some(def_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.copied()
|
||||
else {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
self.elaborator.body().span,
|
||||
|
|
|
|||
|
|
@ -2312,7 +2312,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
|
||||
let name = attr.name().unwrap();
|
||||
let Some(name) = attr.name() else {
|
||||
return;
|
||||
};
|
||||
match target {
|
||||
Target::ExternCrate | Target::Mod => {}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ impl<'tcx> Visitor<'tcx> for ExportableItemCollector<'tcx> {
|
|||
self.add_exportable(def_id);
|
||||
}
|
||||
hir::ItemKind::Use(path, _) => {
|
||||
for res in &path.res {
|
||||
for res in path.res.present_items() {
|
||||
// Only local items are exportable.
|
||||
if let Some(res_id) = res.opt_def_id()
|
||||
&& let Some(res_id) = res_id.as_local()
|
||||
|
|
|
|||
|
|
@ -118,9 +118,10 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
|
|||
ast::UseTreeKind::Simple(Some(ident)) => {
|
||||
if ident.name == kw::Underscore
|
||||
&& !self.r.import_res_map.get(&id).is_some_and(|per_ns| {
|
||||
per_ns.iter().filter_map(|res| res.as_ref()).any(|res| {
|
||||
matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
|
||||
})
|
||||
matches!(
|
||||
per_ns.type_ns,
|
||||
Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
|
||||
)
|
||||
})
|
||||
{
|
||||
self.unused_import(self.base_id).add(id);
|
||||
|
|
@ -193,6 +194,16 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let module = self
|
||||
.r
|
||||
.get_nearest_non_block_module(self.r.local_def_id(extern_crate.id).to_def_id());
|
||||
if module.no_implicit_prelude {
|
||||
// If the module has `no_implicit_prelude`, then we don't suggest
|
||||
// replacing the extern crate with a use, as it would not be
|
||||
// inserted into the prelude. User writes `extern` style deliberately.
|
||||
continue;
|
||||
}
|
||||
|
||||
let vis_span = extern_crate
|
||||
.vis_span
|
||||
.find_ancestor_inside(extern_crate.span)
|
||||
|
|
|
|||
|
|
@ -4898,11 +4898,28 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
self.resolve_expr(e, Some(expr));
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pat, ref scrutinee, _, _) => {
|
||||
ExprKind::Let(ref pat, ref scrutinee, _, Recovered::No) => {
|
||||
self.visit_expr(scrutinee);
|
||||
self.resolve_pattern_top(pat, PatternSource::Let);
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pat, ref scrutinee, _, Recovered::Yes(_)) => {
|
||||
self.visit_expr(scrutinee);
|
||||
// This is basically a tweaked, inlined `resolve_pattern_top`.
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
self.resolve_pattern(pat, PatternSource::Let, &mut bindings);
|
||||
// We still collect the bindings in this `let` expression which is in
|
||||
// an invalid position (and therefore shouldn't declare variables into
|
||||
// its parent scope). To avoid unnecessary errors though, we do just
|
||||
// reassign the resolutions to `Res::Err`.
|
||||
for (_, bindings) in &mut bindings {
|
||||
for (_, binding) in bindings {
|
||||
*binding = Res::Err;
|
||||
}
|
||||
}
|
||||
self.apply_pattern_bindings(bindings);
|
||||
}
|
||||
|
||||
ExprKind::If(ref cond, ref then, ref opt_else) => {
|
||||
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
||||
let old = this.diag_metadata.in_if_condition.replace(cond);
|
||||
|
|
|
|||
|
|
@ -2366,6 +2366,8 @@ options! {
|
|||
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
|
||||
no_profiler_runtime: bool = (false, parse_no_value, [TRACKED],
|
||||
"prevent automatic injection of the profiler_builtins crate"),
|
||||
no_steal_thir: bool = (false, parse_bool, [UNTRACKED],
|
||||
"don't steal the THIR when we're done with it; useful for rustc drivers (default: no)"),
|
||||
no_trait_vptr: bool = (false, parse_no_value, [TRACKED],
|
||||
"disable generation of trait vptr in vtable for upcasting"),
|
||||
no_unique_section_names: bool = (false, parse_bool, [TRACKED],
|
||||
|
|
|
|||
|
|
@ -29,7 +29,18 @@ pub(crate) fn analyze_source_file(src: &str) -> (Vec<RelativeBytePos>, Vec<Multi
|
|||
(lines, multi_byte_chars)
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
// cfg(bootstrap)
|
||||
macro_rules! cfg_select_dispatch {
|
||||
($($tokens:tt)*) => {
|
||||
#[cfg(bootstrap)]
|
||||
cfg_match! { $($tokens)* }
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
cfg_select! { $($tokens)* }
|
||||
};
|
||||
}
|
||||
|
||||
cfg_select_dispatch! {
|
||||
any(target_arch = "x86", target_arch = "x86_64") => {
|
||||
fn analyze_source_file_dispatch(
|
||||
src: &str,
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(cfg_match))]
|
||||
#![cfg_attr(not(bootstrap), feature(cfg_select))]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(array_windows)]
|
||||
#![feature(cfg_select)]
|
||||
#![feature(core_io_borrowed_buf)]
|
||||
#![feature(hash_set_entry)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
|
|||
|
|
@ -937,8 +937,10 @@ symbols! {
|
|||
external_doc,
|
||||
f,
|
||||
f128,
|
||||
f128_epsilon,
|
||||
f128_nan,
|
||||
f16,
|
||||
f16_epsilon,
|
||||
f16_nan,
|
||||
f16c_target_feature,
|
||||
f32,
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ pub trait Unsize<T: ?Sized> {
|
|||
///
|
||||
/// Constants are only allowed as patterns if (a) their type implements
|
||||
/// `PartialEq`, and (b) interpreting the value of the constant as a pattern
|
||||
/// is equialent to calling `PartialEq`. This ensures that constants used as
|
||||
/// is equivalent to calling `PartialEq`. This ensures that constants used as
|
||||
/// patterns cannot expose implementation details in an unexpected way or
|
||||
/// cause semver hazards.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ use crate::ptr;
|
|||
/// use std::mem::ManuallyDrop;
|
||||
///
|
||||
/// pub struct BadOption<T> {
|
||||
/// // Invariant: Has been dropped iff `is_some` is false.
|
||||
/// // Invariant: Has been dropped if `is_some` is false.
|
||||
/// value: ManuallyDrop<T>,
|
||||
/// is_some: bool,
|
||||
/// }
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ impl f128 {
|
|||
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
|
||||
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
#[rustc_diagnostic_item = "f128_epsilon"]
|
||||
pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128;
|
||||
|
||||
/// Smallest finite `f128` value.
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ impl f16 {
|
|||
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
|
||||
/// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
#[rustc_diagnostic_item = "f16_epsilon"]
|
||||
pub const EPSILON: f16 = 9.7656e-4_f16;
|
||||
|
||||
/// Smallest finite `f16` value.
|
||||
|
|
|
|||
|
|
@ -159,8 +159,11 @@ impl<T> OnceLock<T> {
|
|||
|
||||
/// Gets the mutable reference to the underlying value.
|
||||
///
|
||||
/// Returns `None` if the cell is uninitialized, or being initialized.
|
||||
/// This method never blocks.
|
||||
/// Returns `None` if the cell is uninitialized.
|
||||
///
|
||||
/// This method never blocks. Since it borrows the `OnceLock` mutably,
|
||||
/// it is statically guaranteed that no active borrows to the `OnceLock`
|
||||
/// exist, including from other threads.
|
||||
#[inline]
|
||||
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||
pub fn get_mut(&mut self) -> Option<&mut T> {
|
||||
|
|
@ -315,7 +318,9 @@ impl<T> OnceLock<T> {
|
|||
/// Gets the mutable reference of the contents of the cell, initializing
|
||||
/// it to `f()` if the cell was uninitialized.
|
||||
///
|
||||
/// This method never blocks.
|
||||
/// This method never blocks. Since it borrows the `OnceLock` mutably,
|
||||
/// it is statically guaranteed that no active borrows to the `OnceLock`
|
||||
/// exist, including from other threads.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
@ -405,7 +410,9 @@ impl<T> OnceLock<T> {
|
|||
/// it to `f()` if the cell was uninitialized. If the cell was uninitialized
|
||||
/// and `f()` failed, an error is returned.
|
||||
///
|
||||
/// This method never blocks.
|
||||
/// This method never blocks. Since it borrows the `OnceLock` mutably,
|
||||
/// it is statically guaranteed that no active borrows to the `OnceLock`
|
||||
/// exist, including from other threads.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
@ -469,7 +476,8 @@ impl<T> OnceLock<T> {
|
|||
///
|
||||
/// Has no effect and returns `None` if the `OnceLock` was uninitialized.
|
||||
///
|
||||
/// Safety is guaranteed by requiring a mutable reference.
|
||||
/// Since this method borrows the `OnceLock` mutably, it is statically guaranteed that
|
||||
/// no active borrows to the `OnceLock` exist, including from other threads.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
# These defaults are meant for contributors to the standard library and documentation.
|
||||
[build]
|
||||
# When building the standard library, you almost never want to build the compiler itself.
|
||||
build-stage = 0
|
||||
test-stage = 0
|
||||
bench-stage = 0
|
||||
build-stage = 1
|
||||
test-stage = 1
|
||||
bench-stage = 1
|
||||
|
||||
[rust]
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
||||
# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
|
||||
lto = "off"
|
||||
# Download rustc by default for library profile if compiler-affecting
|
||||
# directories are not modified. For CI this is disabled.
|
||||
# When building the standard library, you almost never want to build the compiler itself.
|
||||
#
|
||||
# If compiler-affecting directories are not modified, use precompiled rustc to speed up
|
||||
# library development by skipping compiler builds.
|
||||
download-rustc = "if-unchanged"
|
||||
|
||||
[llvm]
|
||||
|
|
|
|||
|
|
@ -54,13 +54,15 @@ check-aux:
|
|||
src/etc/test-float-parse \
|
||||
$(BOOTSTRAP_ARGS)
|
||||
# Run standard library tests in Miri.
|
||||
$(Q)$(BOOTSTRAP) miri --stage 2 \
|
||||
$(Q)MIRIFLAGS="-Zmiri-strict-provenance" \
|
||||
$(BOOTSTRAP) miri --stage 2 \
|
||||
library/coretests \
|
||||
library/alloctests \
|
||||
library/alloc \
|
||||
$(BOOTSTRAP_ARGS) \
|
||||
--no-doc
|
||||
# Some doctests use file system operations to demonstrate dealing with `Result`.
|
||||
# Some doctests use file system operations to demonstrate dealing with `Result`,
|
||||
# so we have to run them with isolation disabled.
|
||||
$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
|
||||
$(BOOTSTRAP) miri --stage 2 \
|
||||
library/coretests \
|
||||
|
|
@ -70,22 +72,19 @@ check-aux:
|
|||
--doc
|
||||
# In `std` we cannot test everything, so we skip some modules.
|
||||
$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
|
||||
$(BOOTSTRAP) miri --stage 2 library/std \
|
||||
$(BOOTSTRAP) miri --stage 2 \
|
||||
library/std \
|
||||
$(BOOTSTRAP_ARGS) \
|
||||
--no-doc -- \
|
||||
--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
|
||||
$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
|
||||
$(BOOTSTRAP) miri --stage 2 library/std \
|
||||
$(BOOTSTRAP_ARGS) \
|
||||
--doc -- \
|
||||
-- \
|
||||
--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
|
||||
# Also test some very target-specific modules on other targets
|
||||
# (making sure to cover an i686 target as well).
|
||||
$(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
|
||||
$(BOOTSTRAP) miri --stage 2 library/std \
|
||||
$(BOOTSTRAP_ARGS) \
|
||||
$(BOOTSTRAP) miri --stage 2 \
|
||||
library/std \
|
||||
--target aarch64-apple-darwin,i686-pc-windows-msvc \
|
||||
--no-doc -- \
|
||||
$(BOOTSTRAP_ARGS) \
|
||||
-- \
|
||||
time:: sync:: thread:: env::
|
||||
dist:
|
||||
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
|
||||
|
|
|
|||
|
|
@ -120,14 +120,12 @@ fn main() {
|
|||
};
|
||||
cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
if let Some(crate_name) = crate_name {
|
||||
if let Some(target) = env::var_os("RUSTC_TIME") {
|
||||
if target == "all"
|
||||
|| target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
|
||||
{
|
||||
cmd.arg("-Ztime-passes");
|
||||
}
|
||||
}
|
||||
if let Some(crate_name) = crate_name
|
||||
&& let Some(target) = env::var_os("RUSTC_TIME")
|
||||
&& (target == "all"
|
||||
|| target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name))
|
||||
{
|
||||
cmd.arg("-Ztime-passes");
|
||||
}
|
||||
|
||||
// Print backtrace in case of ICE
|
||||
|
|
@ -242,10 +240,10 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some() {
|
||||
if let Some("rustc_driver") = crate_name {
|
||||
cmd.arg("-Clink-args=-Wl,-q");
|
||||
}
|
||||
if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some()
|
||||
&& let Some("rustc_driver") = crate_name
|
||||
{
|
||||
cmd.arg("-Clink-args=-Wl,-q");
|
||||
}
|
||||
|
||||
let is_test = args.iter().any(|a| a == "--test");
|
||||
|
|
@ -282,25 +280,24 @@ fn main() {
|
|||
(child, status)
|
||||
};
|
||||
|
||||
if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
|
||||
|| env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
|
||||
if (env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
|
||||
|| env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some())
|
||||
&& let Some(crate_name) = crate_name
|
||||
{
|
||||
if let Some(crate_name) = crate_name {
|
||||
let dur = start.elapsed();
|
||||
// If the user requested resource usage data, then
|
||||
// include that in addition to the timing output.
|
||||
let rusage_data =
|
||||
env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data(child));
|
||||
eprintln!(
|
||||
"[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
|
||||
crate_name,
|
||||
is_test,
|
||||
dur.as_secs(),
|
||||
dur.subsec_millis(),
|
||||
if rusage_data.is_some() { " " } else { "" },
|
||||
rusage_data.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
let dur = start.elapsed();
|
||||
// If the user requested resource usage data, then
|
||||
// include that in addition to the timing output.
|
||||
let rusage_data =
|
||||
env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data(child));
|
||||
eprintln!(
|
||||
"[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
|
||||
crate_name,
|
||||
is_test,
|
||||
dur.as_secs(),
|
||||
dur.subsec_millis(),
|
||||
if rusage_data.is_some() { " " } else { "" },
|
||||
rusage_data.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
|
||||
if status.success() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
|
||||
|
||||
use crate::core::build_steps::compile;
|
||||
use crate::core::build_steps::compile::{
|
||||
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
|
||||
};
|
||||
|
|
@ -45,10 +46,12 @@ impl Step for Std {
|
|||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let stage = run.builder.top_stage;
|
||||
run.crate_or_deps("sysroot")
|
||||
.crate_or_deps("coretests")
|
||||
.crate_or_deps("alloctests")
|
||||
.path("library")
|
||||
.default_condition(stage != 0)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
|
|
@ -62,6 +65,12 @@ impl Step for Std {
|
|||
let target = self.target;
|
||||
let compiler = builder.compiler(builder.top_stage, builder.config.build);
|
||||
|
||||
if builder.top_stage == 0 {
|
||||
// Reuse the stage0 libstd
|
||||
builder.ensure(compile::Std::new(compiler, target));
|
||||
return;
|
||||
}
|
||||
|
||||
let mut cargo = builder::Cargo::new(
|
||||
builder,
|
||||
compiler,
|
||||
|
|
|
|||
|
|
@ -207,16 +207,18 @@ impl Step for Rustc {
|
|||
let compiler = builder.compiler(builder.top_stage, builder.config.build);
|
||||
let target = self.target;
|
||||
|
||||
if compiler.stage != 0 {
|
||||
// If we're not in stage 0, then we won't have a std from the beta
|
||||
// compiler around. That means we need to make sure there's one in
|
||||
// the sysroot for the compiler to find. Otherwise, we're going to
|
||||
// fail when building crates that need to generate code (e.g., build
|
||||
// scripts and their dependencies).
|
||||
builder.ensure(compile::Std::new(compiler, compiler.host));
|
||||
builder.ensure(compile::Std::new(compiler, target));
|
||||
} else {
|
||||
builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check)));
|
||||
if !builder.download_rustc() {
|
||||
if compiler.stage != 0 {
|
||||
// If we're not in stage 0, then we won't have a std from the beta
|
||||
// compiler around. That means we need to make sure there's one in
|
||||
// the sysroot for the compiler to find. Otherwise, we're going to
|
||||
// fail when building crates that need to generate code (e.g., build
|
||||
// scripts and their dependencies).
|
||||
builder.ensure(compile::Std::new(compiler, compiler.host));
|
||||
builder.ensure(compile::Std::new(compiler, target));
|
||||
} else {
|
||||
builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check)));
|
||||
}
|
||||
}
|
||||
|
||||
let mut cargo = builder::Cargo::new(
|
||||
|
|
@ -286,7 +288,9 @@ macro_rules! lint_any {
|
|||
let compiler = builder.compiler(builder.top_stage, builder.config.build);
|
||||
let target = self.target;
|
||||
|
||||
builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check)));
|
||||
if !builder.download_rustc() {
|
||||
builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check)));
|
||||
};
|
||||
|
||||
let cargo = prepare_tool_cargo(
|
||||
builder,
|
||||
|
|
|
|||
|
|
@ -147,14 +147,27 @@ impl Step for Std {
|
|||
)]
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let target = self.target;
|
||||
let compiler = self.compiler;
|
||||
|
||||
// We already have std ready to be used for stage 0.
|
||||
if self.compiler.stage == 0 {
|
||||
let compiler = self.compiler;
|
||||
builder.ensure(StdLink::from_std(self, compiler));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let compiler = if builder.download_rustc() && self.force_recompile {
|
||||
// When there are changes in the library tree with CI-rustc, we want to build
|
||||
// the stageN library and that requires using stageN-1 compiler.
|
||||
builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.build)
|
||||
} else {
|
||||
self.compiler
|
||||
};
|
||||
|
||||
// When using `download-rustc`, we already have artifacts for the host available. Don't
|
||||
// recompile them.
|
||||
if builder.download_rustc() && builder.config.is_host_target(target)
|
||||
// NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so
|
||||
// its artifacts can't be reused.
|
||||
&& compiler.stage != 0
|
||||
if builder.download_rustc()
|
||||
&& builder.config.is_host_target(target)
|
||||
&& !self.force_recompile
|
||||
{
|
||||
let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
|
||||
|
|
@ -189,7 +202,13 @@ impl Step for Std {
|
|||
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
|
||||
trace!(?compiler_to_use);
|
||||
|
||||
if compiler_to_use != compiler {
|
||||
if compiler_to_use != compiler
|
||||
// Never uplift std unless we have compiled stage 1; if stage 1 is compiled,
|
||||
// uplift it from there.
|
||||
//
|
||||
// FIXME: improve `fn compiler_for` to avoid adding stage condition here.
|
||||
&& compiler.stage > 1
|
||||
{
|
||||
trace!(?compiler_to_use, ?compiler, "compiler != compiler_to_use, uplifting library");
|
||||
|
||||
builder.ensure(Std::new(compiler_to_use, target));
|
||||
|
|
@ -222,27 +241,6 @@ impl Step for Std {
|
|||
|
||||
target_deps.extend(self.copy_extra_objects(builder, &compiler, target));
|
||||
|
||||
// The LLD wrappers and `rust-lld` are self-contained linking components that can be
|
||||
// necessary to link the stdlib on some targets. We'll also need to copy these binaries to
|
||||
// the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target.
|
||||
if compiler.stage == 0 && builder.config.is_host_target(compiler.host) {
|
||||
trace!(
|
||||
"(build == host) copying linking components to `stage0-sysroot` for bootstrapping"
|
||||
);
|
||||
// We want to copy the host `bin` folder within the `rustlib` folder in the sysroot.
|
||||
let src_sysroot_bin = builder
|
||||
.rustc_snapshot_sysroot()
|
||||
.join("lib")
|
||||
.join("rustlib")
|
||||
.join(compiler.host)
|
||||
.join("bin");
|
||||
if src_sysroot_bin.exists() {
|
||||
let target_sysroot_bin = builder.sysroot_target_bindir(compiler, target);
|
||||
t!(fs::create_dir_all(&target_sysroot_bin));
|
||||
builder.cp_link_r(&src_sysroot_bin, &target_sysroot_bin);
|
||||
}
|
||||
}
|
||||
|
||||
// We build a sysroot for mir-opt tests using the same trick that Miri does: A check build
|
||||
// with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
|
||||
// fact that this is a check build integrates nicely with run_cargo.
|
||||
|
|
@ -628,18 +626,18 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
|
|||
|
||||
// Help the libc crate compile by assisting it in finding various
|
||||
// sysroot native libraries.
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = builder.musl_libdir(target) {
|
||||
let root = format!("native={}", p.to_str().unwrap());
|
||||
cargo.rustflag("-L").rustflag(&root);
|
||||
}
|
||||
if target.contains("musl")
|
||||
&& let Some(p) = builder.musl_libdir(target)
|
||||
{
|
||||
let root = format!("native={}", p.to_str().unwrap());
|
||||
cargo.rustflag("-L").rustflag(&root);
|
||||
}
|
||||
|
||||
if target.contains("-wasi") {
|
||||
if let Some(dir) = builder.wasi_libdir(target) {
|
||||
let root = format!("native={}", dir.to_str().unwrap());
|
||||
cargo.rustflag("-L").rustflag(&root);
|
||||
}
|
||||
if target.contains("-wasi")
|
||||
&& let Some(dir) = builder.wasi_libdir(target)
|
||||
{
|
||||
let root = format!("native={}", dir.to_str().unwrap());
|
||||
cargo.rustflag("-L").rustflag(&root);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -737,7 +735,7 @@ impl Step for StdLink {
|
|||
let target = self.target;
|
||||
|
||||
// NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`.
|
||||
let (libdir, hostdir) = if self.force_recompile && builder.download_rustc() {
|
||||
let (libdir, hostdir) = if !self.force_recompile && builder.download_rustc() {
|
||||
// NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too
|
||||
let lib = builder.sysroot_libdir_relative(self.compiler);
|
||||
let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {
|
||||
|
|
@ -753,23 +751,16 @@ impl Step for StdLink {
|
|||
(libdir, hostdir)
|
||||
};
|
||||
|
||||
add_to_sysroot(
|
||||
builder,
|
||||
&libdir,
|
||||
&hostdir,
|
||||
&build_stamp::libstd_stamp(builder, compiler, target),
|
||||
);
|
||||
let is_downloaded_beta_stage0 = builder
|
||||
.build
|
||||
.config
|
||||
.initial_rustc
|
||||
.starts_with(builder.out.join(compiler.host).join("stage0/bin"));
|
||||
|
||||
// Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0`
|
||||
// work for stage0-sysroot. We only do this if the stage0 compiler comes from beta,
|
||||
// and is not set to a custom path.
|
||||
if compiler.stage == 0
|
||||
&& builder
|
||||
.build
|
||||
.config
|
||||
.initial_rustc
|
||||
.starts_with(builder.out.join(compiler.host).join("stage0/bin"))
|
||||
{
|
||||
if compiler.stage == 0 && is_downloaded_beta_stage0 {
|
||||
// Copy bin files from stage0/bin to stage0-sysroot/bin
|
||||
let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");
|
||||
|
||||
|
|
@ -779,21 +770,9 @@ impl Step for StdLink {
|
|||
t!(fs::create_dir_all(&sysroot_bin_dir));
|
||||
builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);
|
||||
|
||||
// Copy all files from stage0/lib to stage0-sysroot/lib
|
||||
let stage0_lib_dir = builder.out.join(host).join("stage0/lib");
|
||||
if let Ok(files) = fs::read_dir(stage0_lib_dir) {
|
||||
for file in files {
|
||||
let file = t!(file);
|
||||
let path = file.path();
|
||||
if path.is_file() {
|
||||
builder.copy_link(
|
||||
&path,
|
||||
&sysroot.join("lib").join(path.file_name().unwrap()),
|
||||
FileType::Regular,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
t!(fs::create_dir_all(sysroot.join("lib")));
|
||||
builder.cp_link_r(&stage0_lib_dir, &sysroot.join("lib"));
|
||||
|
||||
// Copy codegen-backends from stage0
|
||||
let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler);
|
||||
|
|
@ -807,6 +786,30 @@ impl Step for StdLink {
|
|||
if stage0_codegen_backends.exists() {
|
||||
builder.cp_link_r(&stage0_codegen_backends, &sysroot_codegen_backends);
|
||||
}
|
||||
} else if compiler.stage == 0 {
|
||||
let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");
|
||||
|
||||
if builder.local_rebuild {
|
||||
// On local rebuilds this path might be a symlink to the project root,
|
||||
// which can be read-only (e.g., on CI). So remove it before copying
|
||||
// the stage0 lib.
|
||||
let _ = fs::remove_dir_all(sysroot.join("lib/rustlib/src/rust"));
|
||||
}
|
||||
|
||||
builder.cp_link_r(&builder.initial_sysroot.join("lib"), &sysroot.join("lib"));
|
||||
} else {
|
||||
if builder.download_rustc() {
|
||||
// Ensure there are no CI-rustc std artifacts.
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
let _ = fs::remove_dir_all(&hostdir);
|
||||
}
|
||||
|
||||
add_to_sysroot(
|
||||
builder,
|
||||
&libdir,
|
||||
&hostdir,
|
||||
&build_stamp::libstd_stamp(builder, compiler, target),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1029,7 +1032,7 @@ impl Step for Rustc {
|
|||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
|
||||
// NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
|
||||
// NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler,
|
||||
// so its artifacts can't be reused.
|
||||
if builder.download_rustc() && compiler.stage != 0 {
|
||||
trace!(stage = compiler.stage, "`download_rustc` requested");
|
||||
|
|
@ -1388,12 +1391,13 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
|
|||
// found. This is to avoid the linker errors about undefined references to
|
||||
// `__llvm_profile_instrument_memop` when linking `rustc_driver`.
|
||||
let mut llvm_linker_flags = String::new();
|
||||
if builder.config.llvm_profile_generate && target.is_msvc() {
|
||||
if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
|
||||
// Add clang's runtime library directory to the search path
|
||||
let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
|
||||
llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
|
||||
}
|
||||
if builder.config.llvm_profile_generate
|
||||
&& target.is_msvc()
|
||||
&& let Some(ref clang_cl_path) = builder.config.llvm_clang_cl
|
||||
{
|
||||
// Add clang's runtime library directory to the search path
|
||||
let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
|
||||
llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
|
||||
}
|
||||
|
||||
// The config can also specify its own llvm linker flags.
|
||||
|
|
@ -1785,9 +1789,9 @@ impl Step for Sysroot {
|
|||
t!(fs::create_dir_all(&sysroot));
|
||||
|
||||
// In some cases(see https://github.com/rust-lang/rust/issues/109314), when the stage0
|
||||
// compiler relies on more recent version of LLVM than the beta compiler, it may not
|
||||
// compiler relies on more recent version of LLVM than the stage0 compiler, it may not
|
||||
// be able to locate the correct LLVM in the sysroot. This situation typically occurs
|
||||
// when we upgrade LLVM version while the beta compiler continues to use an older version.
|
||||
// when we upgrade LLVM version while the stage0 compiler continues to use an older version.
|
||||
//
|
||||
// Make sure to add the correct version of LLVM into the stage0 sysroot.
|
||||
if compiler.stage == 0 {
|
||||
|
|
|
|||
|
|
@ -2276,11 +2276,12 @@ impl Step for LlvmTools {
|
|||
let target = self.target;
|
||||
|
||||
// Run only if a custom llvm-config is not used
|
||||
if let Some(config) = builder.config.target_config.get(&target) {
|
||||
if !builder.config.llvm_from_ci && config.llvm_config.is_some() {
|
||||
builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
|
||||
return None;
|
||||
}
|
||||
if let Some(config) = builder.config.target_config.get(&target)
|
||||
&& !builder.config.llvm_from_ci
|
||||
&& config.llvm_config.is_some()
|
||||
{
|
||||
builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
|
||||
return None;
|
||||
}
|
||||
|
||||
if !builder.config.dry_run() {
|
||||
|
|
@ -2398,11 +2399,11 @@ impl Step for RustDev {
|
|||
let target = self.target;
|
||||
|
||||
/* run only if llvm-config isn't used */
|
||||
if let Some(config) = builder.config.target_config.get(&target) {
|
||||
if let Some(ref _s) = config.llvm_config {
|
||||
builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
|
||||
return None;
|
||||
}
|
||||
if let Some(config) = builder.config.target_config.get(&target)
|
||||
&& let Some(ref _s) = config.llvm_config
|
||||
{
|
||||
builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
|
||||
return None;
|
||||
}
|
||||
|
||||
if !builder.config.dry_run() {
|
||||
|
|
|
|||
|
|
@ -318,10 +318,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||
// `into_path` produces an absolute path. Try to strip `cwd` to get a shorter
|
||||
// relative path.
|
||||
let mut path = entry.clone().into_path();
|
||||
if let Ok(cwd) = cwd {
|
||||
if let Ok(path2) = path.strip_prefix(cwd) {
|
||||
path = path2.to_path_buf();
|
||||
}
|
||||
if let Ok(cwd) = cwd
|
||||
&& let Ok(path2) = path.strip_prefix(cwd)
|
||||
{
|
||||
path = path2.to_path_buf();
|
||||
}
|
||||
path.display().to_string()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -107,18 +107,18 @@ pub fn prebuilt_llvm_config(
|
|||
|
||||
// If we're using a custom LLVM bail out here, but we can only use a
|
||||
// custom LLVM for the build triple.
|
||||
if let Some(config) = builder.config.target_config.get(&target) {
|
||||
if let Some(ref s) = config.llvm_config {
|
||||
check_llvm_version(builder, s);
|
||||
let llvm_config = s.to_path_buf();
|
||||
let mut llvm_cmake_dir = llvm_config.clone();
|
||||
llvm_cmake_dir.pop();
|
||||
llvm_cmake_dir.pop();
|
||||
llvm_cmake_dir.push("lib");
|
||||
llvm_cmake_dir.push("cmake");
|
||||
llvm_cmake_dir.push("llvm");
|
||||
return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir });
|
||||
}
|
||||
if let Some(config) = builder.config.target_config.get(&target)
|
||||
&& let Some(ref s) = config.llvm_config
|
||||
{
|
||||
check_llvm_version(builder, s);
|
||||
let llvm_config = s.to_path_buf();
|
||||
let mut llvm_cmake_dir = llvm_config.clone();
|
||||
llvm_cmake_dir.pop();
|
||||
llvm_cmake_dir.pop();
|
||||
llvm_cmake_dir.push("lib");
|
||||
llvm_cmake_dir.push("cmake");
|
||||
llvm_cmake_dir.push("llvm");
|
||||
return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir });
|
||||
}
|
||||
|
||||
if handle_submodule_when_needed {
|
||||
|
|
@ -468,10 +468,10 @@ impl Step for Llvm {
|
|||
cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";"));
|
||||
}
|
||||
|
||||
if let Some(num_linkers) = builder.config.llvm_link_jobs {
|
||||
if num_linkers > 0 {
|
||||
cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
|
||||
}
|
||||
if let Some(num_linkers) = builder.config.llvm_link_jobs
|
||||
&& num_linkers > 0
|
||||
{
|
||||
cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
|
||||
}
|
||||
|
||||
// https://llvm.org/docs/HowToCrossCompileLLVM.html
|
||||
|
|
@ -597,10 +597,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
|
|||
|
||||
let version = get_llvm_version(builder, llvm_config);
|
||||
let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
|
||||
if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
|
||||
if major >= 19 {
|
||||
return;
|
||||
}
|
||||
if let (Some(major), Some(_minor)) = (parts.next(), parts.next())
|
||||
&& major >= 19
|
||||
{
|
||||
return;
|
||||
}
|
||||
panic!("\n\nbad LLVM version: {version}, need >=19\n\n")
|
||||
}
|
||||
|
|
@ -730,11 +730,9 @@ fn configure_cmake(
|
|||
|
||||
// If ccache is configured we inform the build a little differently how
|
||||
// to invoke ccache while also invoking our compilers.
|
||||
if use_compiler_launcher {
|
||||
if let Some(ref ccache) = builder.config.ccache {
|
||||
cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
|
||||
.define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
|
||||
}
|
||||
if use_compiler_launcher && let Some(ref ccache) = builder.config.ccache {
|
||||
cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
|
||||
.define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
|
||||
}
|
||||
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
|
||||
.define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx))
|
||||
|
|
@ -792,20 +790,20 @@ fn configure_cmake(
|
|||
cxxflags.push(format!(" --target={target}"));
|
||||
}
|
||||
cfg.define("CMAKE_CXX_FLAGS", cxxflags);
|
||||
if let Some(ar) = builder.ar(target) {
|
||||
if ar.is_absolute() {
|
||||
// LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
|
||||
// tries to resolve this path in the LLVM build directory.
|
||||
cfg.define("CMAKE_AR", sanitize_cc(&ar));
|
||||
}
|
||||
if let Some(ar) = builder.ar(target)
|
||||
&& ar.is_absolute()
|
||||
{
|
||||
// LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
|
||||
// tries to resolve this path in the LLVM build directory.
|
||||
cfg.define("CMAKE_AR", sanitize_cc(&ar));
|
||||
}
|
||||
|
||||
if let Some(ranlib) = builder.ranlib(target) {
|
||||
if ranlib.is_absolute() {
|
||||
// LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
|
||||
// tries to resolve this path in the LLVM build directory.
|
||||
cfg.define("CMAKE_RANLIB", sanitize_cc(&ranlib));
|
||||
}
|
||||
if let Some(ranlib) = builder.ranlib(target)
|
||||
&& ranlib.is_absolute()
|
||||
{
|
||||
// LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
|
||||
// tries to resolve this path in the LLVM build directory.
|
||||
cfg.define("CMAKE_RANLIB", sanitize_cc(&ranlib));
|
||||
}
|
||||
|
||||
if let Some(ref flags) = builder.config.llvm_ldflags {
|
||||
|
|
@ -1038,13 +1036,14 @@ impl Step for Lld {
|
|||
// when doing PGO on CI, cmake or clang-cl don't automatically link clang's
|
||||
// profiler runtime in. In that case, we need to manually ask cmake to do it, to avoid
|
||||
// linking errors, much like LLVM's cmake setup does in that situation.
|
||||
if builder.config.llvm_profile_generate && target.is_msvc() {
|
||||
if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() {
|
||||
// Find clang's runtime library directory and push that as a search path to the
|
||||
// cmake linker flags.
|
||||
let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
|
||||
ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
|
||||
}
|
||||
if builder.config.llvm_profile_generate
|
||||
&& target.is_msvc()
|
||||
&& let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref()
|
||||
{
|
||||
// Find clang's runtime library directory and push that as a search path to the
|
||||
// cmake linker flags.
|
||||
let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
|
||||
ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
|
||||
}
|
||||
|
||||
// LLD is built as an LLVM tool, but is distributed outside of the `llvm-tools` component,
|
||||
|
|
|
|||
|
|
@ -154,10 +154,10 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#);
|
|||
let compiler = builder.compiler(builder.top_stage, builder.config.build);
|
||||
builder.ensure(Std::new(compiler, builder.config.build));
|
||||
|
||||
if let Some(opts) = args.cmd.shared_opts() {
|
||||
if opts.profiles.contains(&Profile::Doc) {
|
||||
builder.ensure(Rustdoc { compiler });
|
||||
}
|
||||
if let Some(opts) = args.cmd.shared_opts()
|
||||
&& opts.profiles.contains(&Profile::Doc)
|
||||
{
|
||||
builder.ensure(Rustdoc { compiler });
|
||||
}
|
||||
|
||||
let sysroot = builder.ensure(Sysroot::new(compiler));
|
||||
|
|
|
|||
|
|
@ -241,10 +241,10 @@ impl Step for Link {
|
|||
if run.builder.config.dry_run() {
|
||||
return;
|
||||
}
|
||||
if let [cmd] = &run.paths[..] {
|
||||
if cmd.assert_single_path().path.as_path().as_os_str() == "link" {
|
||||
run.builder.ensure(Link);
|
||||
}
|
||||
if let [cmd] = &run.paths[..]
|
||||
&& cmd.assert_single_path().path.as_path().as_os_str() == "link"
|
||||
{
|
||||
run.builder.ensure(Link);
|
||||
}
|
||||
}
|
||||
fn run(self, builder: &Builder<'_>) -> Self::Output {
|
||||
|
|
@ -457,10 +457,10 @@ impl Step for Hook {
|
|||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
if let [cmd] = &run.paths[..] {
|
||||
if cmd.assert_single_path().path.as_path().as_os_str() == "hook" {
|
||||
run.builder.ensure(Hook);
|
||||
}
|
||||
if let [cmd] = &run.paths[..]
|
||||
&& cmd.assert_single_path().path.as_path().as_os_str() == "hook"
|
||||
{
|
||||
run.builder.ensure(Hook);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -672,10 +672,10 @@ impl Step for Editor {
|
|||
if run.builder.config.dry_run() {
|
||||
return;
|
||||
}
|
||||
if let [cmd] = &run.paths[..] {
|
||||
if cmd.assert_single_path().path.as_path().as_os_str() == "editor" {
|
||||
run.builder.ensure(Editor);
|
||||
}
|
||||
if let [cmd] = &run.paths[..]
|
||||
&& cmd.assert_single_path().path.as_path().as_os_str() == "editor"
|
||||
{
|
||||
run.builder.ensure(Editor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1576,7 +1576,7 @@ impl Step for Compiletest {
|
|||
|
||||
if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
|
||||
eprintln!("\
|
||||
ERROR: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
|
||||
ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
|
||||
HELP: to test the compiler, use `--stage 1` instead
|
||||
HELP: to test the standard library, use `--stage 0 library/std` instead
|
||||
NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
|
||||
|
|
@ -1604,9 +1604,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
|||
// NOTE: Only stage 1 is special cased because we need the rustc_private artifacts to match the
|
||||
// running compiler in stage 2 when plugins run.
|
||||
let (stage, stage_id) = if suite == "ui-fulldeps" && compiler.stage == 1 {
|
||||
// At stage 0 (stage - 1) we are using the beta compiler. Using `self.target` can lead
|
||||
// finding an incorrect compiler path on cross-targets, as the stage 0 beta compiler is
|
||||
// always equal to `build.build` in the configuration.
|
||||
// At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead
|
||||
// finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to
|
||||
// `build.build` in the configuration.
|
||||
let build = builder.build.build;
|
||||
compiler = builder.compiler(compiler.stage - 1, build);
|
||||
let test_stage = compiler.stage + 1;
|
||||
|
|
@ -1692,7 +1692,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
|||
}
|
||||
|
||||
if mode == "rustdoc-json" {
|
||||
// Use the beta compiler for jsondocck
|
||||
// Use the stage0 compiler for jsondocck
|
||||
let json_compiler = compiler.with_stage(0);
|
||||
cmd.arg("--jsondocck-path")
|
||||
.arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
|
||||
|
|
@ -2417,10 +2417,10 @@ impl Step for ErrorIndex {
|
|||
}
|
||||
|
||||
fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
|
||||
if let Ok(contents) = fs::read_to_string(markdown) {
|
||||
if !contents.contains("```") {
|
||||
return true;
|
||||
}
|
||||
if let Ok(contents) = fs::read_to_string(markdown)
|
||||
&& !contents.contains("```")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
builder.verbose(|| println!("doc tests for: {}", markdown.display()));
|
||||
|
|
|
|||
|
|
@ -329,9 +329,9 @@ pub(crate) fn get_tool_rustc_compiler(
|
|||
return target_compiler;
|
||||
}
|
||||
|
||||
if builder.download_rustc() && target_compiler.stage > 0 {
|
||||
// We already have the stage N compiler, we don't need to cut the stage.
|
||||
return builder.compiler(target_compiler.stage, builder.config.build);
|
||||
if builder.download_rustc() && target_compiler.stage == 1 {
|
||||
// We shouldn't drop to stage0 compiler when using CI rustc.
|
||||
return builder.compiler(1, builder.config.build);
|
||||
}
|
||||
|
||||
// Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
|
||||
|
|
|
|||
|
|
@ -988,15 +988,15 @@ impl Builder<'_> {
|
|||
// requirement, but the `-L` library path is not propagated across
|
||||
// separate Cargo projects. We can add LLVM's library path to the
|
||||
// rustc args as a workaround.
|
||||
if mode == Mode::ToolRustc || mode == Mode::Codegen {
|
||||
if let Some(llvm_config) = self.llvm_config(target) {
|
||||
let llvm_libdir =
|
||||
command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout();
|
||||
if target.is_msvc() {
|
||||
rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}"));
|
||||
} else {
|
||||
rustflags.arg(&format!("-Clink-arg=-L{llvm_libdir}"));
|
||||
}
|
||||
if (mode == Mode::ToolRustc || mode == Mode::Codegen)
|
||||
&& let Some(llvm_config) = self.llvm_config(target)
|
||||
{
|
||||
let llvm_libdir =
|
||||
command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout();
|
||||
if target.is_msvc() {
|
||||
rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}"));
|
||||
} else {
|
||||
rustflags.arg(&format!("-Clink-arg=-L{llvm_libdir}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1231,12 +1231,11 @@ impl Builder<'_> {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(limit) = limit {
|
||||
if stage == 0
|
||||
|| self.config.default_codegen_backend(target).unwrap_or_default() == "llvm"
|
||||
{
|
||||
rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
|
||||
}
|
||||
if let Some(limit) = limit
|
||||
&& (stage == 0
|
||||
|| self.config.default_codegen_backend(target).unwrap_or_default() == "llvm")
|
||||
{
|
||||
rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ fn alias_and_path_for_library() {
|
|||
);
|
||||
assert_eq!(
|
||||
first(cache.all::<doc::Std>()),
|
||||
&[doc_std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0)]
|
||||
&[doc_std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1)]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -254,19 +254,6 @@ fn ci_rustc_if_unchanged_invalidate_on_compiler_changes() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ci_rustc_if_unchanged_invalidate_on_library_changes_in_ci() {
|
||||
git_test(|ctx| {
|
||||
prepare_rustc_checkout(ctx);
|
||||
ctx.create_upstream_merge(&["compiler/bar"]);
|
||||
// This change should invalidate download-ci-rustc
|
||||
ctx.create_nonupstream_merge(&["library/foo"]);
|
||||
|
||||
let config = parse_config_download_rustc_at(ctx.get_path(), "if-unchanged", true);
|
||||
assert_eq!(config.download_rustc_commit, None);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ci_rustc_if_unchanged_do_not_invalidate_on_library_changes_outside_ci() {
|
||||
git_test(|ctx| {
|
||||
|
|
@ -433,14 +420,14 @@ mod defaults {
|
|||
assert_eq!(first(cache.all::<doc::ErrorIndex>()), &[doc::ErrorIndex { target: a },]);
|
||||
assert_eq!(
|
||||
first(cache.all::<tool::ErrorIndex>()),
|
||||
&[tool::ErrorIndex { compiler: Compiler::new(0, a) }]
|
||||
&[tool::ErrorIndex { compiler: Compiler::new(1, a) }]
|
||||
);
|
||||
// docs should be built with the beta compiler, not with the stage0 artifacts.
|
||||
// docs should be built with the stage0 compiler, not with the stage0 artifacts.
|
||||
// recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
|
||||
// not the one it was built by.
|
||||
assert_eq!(
|
||||
first(cache.all::<tool::Rustdoc>()),
|
||||
&[tool::Rustdoc { compiler: Compiler::new(0, a) },]
|
||||
&[tool::Rustdoc { compiler: Compiler::new(1, a) },]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ use crate::utils::helpers::{self, exe, output, t};
|
|||
/// final output/compiler, which can be significantly affected by changes made to the bootstrap sources.
|
||||
#[rustfmt::skip] // We don't want rustfmt to oneline this list
|
||||
pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[
|
||||
":!library",
|
||||
":!src/tools",
|
||||
":!src/librustdoc",
|
||||
":!src/rustdoc-json-types",
|
||||
|
|
@ -1699,20 +1700,20 @@ impl Config {
|
|||
};
|
||||
// We want to be able to set string values without quotes,
|
||||
// like in `configure.py`. Try adding quotes around the right hand side
|
||||
if let Some((key, value)) = option.split_once('=') {
|
||||
if !value.contains('"') {
|
||||
match get_table(&format!(r#"{key}="{value}""#)) {
|
||||
Ok(v) => {
|
||||
override_toml.merge(
|
||||
None,
|
||||
&mut Default::default(),
|
||||
v,
|
||||
ReplaceOpt::ErrorOnDuplicate,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(e) => err = e,
|
||||
if let Some((key, value)) = option.split_once('=')
|
||||
&& !value.contains('"')
|
||||
{
|
||||
match get_table(&format!(r#"{key}="{value}""#)) {
|
||||
Ok(v) => {
|
||||
override_toml.merge(
|
||||
None,
|
||||
&mut Default::default(),
|
||||
v,
|
||||
ReplaceOpt::ErrorOnDuplicate,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(e) => err = e,
|
||||
}
|
||||
}
|
||||
eprintln!("failed to parse override `{option}`: `{err}");
|
||||
|
|
@ -2056,16 +2057,15 @@ impl Config {
|
|||
|| (matches!(debug_toml, Some(true))
|
||||
&& !matches!(rustc_debug_assertions_toml, Some(false)));
|
||||
|
||||
if debug_assertions_requested {
|
||||
if let Some(ref opt) = download_rustc {
|
||||
if opt.is_string_or_true() {
|
||||
eprintln!(
|
||||
"WARN: currently no CI rustc builds have rustc debug assertions \
|
||||
if debug_assertions_requested
|
||||
&& let Some(ref opt) = download_rustc
|
||||
&& opt.is_string_or_true()
|
||||
{
|
||||
eprintln!(
|
||||
"WARN: currently no CI rustc builds have rustc debug assertions \
|
||||
enabled. Please either set `rust.debug-assertions` to `false` if you \
|
||||
want to use download CI rustc or set `rust.download-rustc` to `false`."
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
config.download_rustc_commit = config.download_ci_rustc_commit(
|
||||
|
|
@ -2176,19 +2176,17 @@ impl Config {
|
|||
// We need to override `rust.channel` if it's manually specified when using the CI rustc.
|
||||
// This is because if the compiler uses a different channel than the one specified in bootstrap.toml,
|
||||
// tests may fail due to using a different channel than the one used by the compiler during tests.
|
||||
if let Some(commit) = &config.download_rustc_commit {
|
||||
if is_user_configured_rust_channel {
|
||||
println!(
|
||||
"WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
|
||||
);
|
||||
if let Some(commit) = &config.download_rustc_commit
|
||||
&& is_user_configured_rust_channel
|
||||
{
|
||||
println!(
|
||||
"WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
|
||||
);
|
||||
|
||||
let channel = config
|
||||
.read_file_by_commit(Path::new("src/ci/channel"), commit)
|
||||
.trim()
|
||||
.to_owned();
|
||||
let channel =
|
||||
config.read_file_by_commit(Path::new("src/ci/channel"), commit).trim().to_owned();
|
||||
|
||||
config.channel = channel;
|
||||
}
|
||||
config.channel = channel;
|
||||
}
|
||||
|
||||
if let Some(llvm) = toml.llvm {
|
||||
|
|
@ -2533,10 +2531,12 @@ impl Config {
|
|||
|| bench_stage.is_some();
|
||||
// See https://github.com/rust-lang/compiler-team/issues/326
|
||||
config.stage = match config.cmd {
|
||||
Subcommand::Check { .. } => flags.stage.or(check_stage).unwrap_or(0),
|
||||
Subcommand::Check { .. } | Subcommand::Clippy { .. } | Subcommand::Fix => {
|
||||
flags.stage.or(check_stage).unwrap_or(1)
|
||||
}
|
||||
// `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden.
|
||||
Subcommand::Doc { .. } => {
|
||||
flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 0 })
|
||||
flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 1 })
|
||||
}
|
||||
Subcommand::Build => {
|
||||
flags.stage.or(build_stage).unwrap_or(if download_rustc { 2 } else { 1 })
|
||||
|
|
@ -2551,8 +2551,6 @@ impl Config {
|
|||
// These are all bootstrap tools, which don't depend on the compiler.
|
||||
// The stage we pass shouldn't matter, but use 0 just in case.
|
||||
Subcommand::Clean { .. }
|
||||
| Subcommand::Clippy { .. }
|
||||
| Subcommand::Fix
|
||||
| Subcommand::Run { .. }
|
||||
| Subcommand::Setup { .. }
|
||||
| Subcommand::Format { .. }
|
||||
|
|
@ -2698,10 +2696,10 @@ impl Config {
|
|||
let bindir = &self.bindir;
|
||||
if bindir.is_absolute() {
|
||||
// Try to make it relative to the prefix.
|
||||
if let Some(prefix) = &self.prefix {
|
||||
if let Ok(stripped) = bindir.strip_prefix(prefix) {
|
||||
return stripped;
|
||||
}
|
||||
if let Some(prefix) = &self.prefix
|
||||
&& let Ok(stripped) = bindir.strip_prefix(prefix)
|
||||
{
|
||||
return stripped;
|
||||
}
|
||||
}
|
||||
bindir
|
||||
|
|
@ -3150,24 +3148,10 @@ impl Config {
|
|||
}
|
||||
};
|
||||
|
||||
// RUSTC_IF_UNCHANGED_ALLOWED_PATHS
|
||||
let mut allowed_paths = RUSTC_IF_UNCHANGED_ALLOWED_PATHS.to_vec();
|
||||
|
||||
// In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, allow
|
||||
// these changes to speed up the build process for library developers. This provides consistent
|
||||
// functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"`
|
||||
// options.
|
||||
//
|
||||
// If you update "library" logic here, update `builder::tests::ci_rustc_if_unchanged_logic` test
|
||||
// logic accordingly.
|
||||
if !self.is_running_on_ci {
|
||||
allowed_paths.push(":!library");
|
||||
}
|
||||
|
||||
let commit = if self.rust_info.is_managed_git_subrepository() {
|
||||
// Look for a version to compare to based on the current commit.
|
||||
// Only commits merged by bors will have CI artifacts.
|
||||
let freshness = self.check_path_modifications(&allowed_paths);
|
||||
let freshness = self.check_path_modifications(RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
|
||||
self.verbose(|| {
|
||||
eprintln!("rustc freshness: {freshness:?}");
|
||||
});
|
||||
|
|
@ -3493,19 +3477,19 @@ fn check_incompatible_options_for_ci_rustc(
|
|||
// We always build the in-tree compiler on cross targets, so we only care
|
||||
// about the host target here.
|
||||
let host_str = host.to_string();
|
||||
if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str)) {
|
||||
if current_cfg.profiler.is_some() {
|
||||
let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str));
|
||||
let ci_cfg = ci_target_toml.ok_or(format!(
|
||||
"Target specific config for '{host_str}' is not present for CI-rustc"
|
||||
))?;
|
||||
if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str))
|
||||
&& current_cfg.profiler.is_some()
|
||||
{
|
||||
let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str));
|
||||
let ci_cfg = ci_target_toml.ok_or(format!(
|
||||
"Target specific config for '{host_str}' is not present for CI-rustc"
|
||||
))?;
|
||||
|
||||
let profiler = &ci_cfg.profiler;
|
||||
err!(current_cfg.profiler, profiler, "build");
|
||||
let profiler = &ci_cfg.profiler;
|
||||
err!(current_cfg.profiler, profiler, "build");
|
||||
|
||||
let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins;
|
||||
err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build");
|
||||
}
|
||||
let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins;
|
||||
err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build");
|
||||
}
|
||||
|
||||
let (Some(current_rust_config), Some(ci_rust_config)) =
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ impl Config {
|
|||
}
|
||||
};
|
||||
|
||||
// For the beta compiler, put special effort into ensuring the checksums are valid.
|
||||
// For the stage0 compiler, put special effort into ensuring the checksums are valid.
|
||||
let checksum = if should_verify {
|
||||
let error = format!(
|
||||
"src/stage0 doesn't contain a checksum for {url}. \
|
||||
|
|
@ -709,10 +709,10 @@ download-rustc = false
|
|||
";
|
||||
}
|
||||
self.download_file(&format!("{base_url}/{url}"), &tarball, help_on_error);
|
||||
if let Some(sha256) = checksum {
|
||||
if !self.verify(&tarball, sha256) {
|
||||
panic!("failed to verify {}", tarball.display());
|
||||
}
|
||||
if let Some(sha256) = checksum
|
||||
&& !self.verify(&tarball, sha256)
|
||||
{
|
||||
panic!("failed to verify {}", tarball.display());
|
||||
}
|
||||
|
||||
self.unpack(&tarball, &bin_root, prefix);
|
||||
|
|
|
|||
|
|
@ -1451,23 +1451,23 @@ Executed at: {executed_at}"#,
|
|||
// Look for Wasmtime, and for its default options be sure to disable
|
||||
// its caching system since we're executing quite a lot of tests and
|
||||
// ideally shouldn't pollute the cache too much.
|
||||
if let Some(path) = finder.maybe_have("wasmtime") {
|
||||
if let Ok(mut path) = path.into_os_string().into_string() {
|
||||
path.push_str(" run -C cache=n --dir .");
|
||||
// Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
|
||||
// required for libtest to work on beta/stable channels.
|
||||
//
|
||||
// NB: with Wasmtime 20 this can change to `-S inherit-env` to
|
||||
// inherit the entire environment rather than just this single
|
||||
// environment variable.
|
||||
path.push_str(" --env RUSTC_BOOTSTRAP");
|
||||
if let Some(path) = finder.maybe_have("wasmtime")
|
||||
&& let Ok(mut path) = path.into_os_string().into_string()
|
||||
{
|
||||
path.push_str(" run -C cache=n --dir .");
|
||||
// Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
|
||||
// required for libtest to work on beta/stable channels.
|
||||
//
|
||||
// NB: with Wasmtime 20 this can change to `-S inherit-env` to
|
||||
// inherit the entire environment rather than just this single
|
||||
// environment variable.
|
||||
path.push_str(" --env RUSTC_BOOTSTRAP");
|
||||
|
||||
if target.contains("wasip2") {
|
||||
path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup");
|
||||
}
|
||||
|
||||
return Some(path);
|
||||
if target.contains("wasip2") {
|
||||
path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup");
|
||||
}
|
||||
|
||||
return Some(path);
|
||||
}
|
||||
|
||||
None
|
||||
|
|
@ -1637,12 +1637,12 @@ Executed at: {executed_at}"#,
|
|||
/// sha, version, etc.
|
||||
fn rust_version(&self) -> String {
|
||||
let mut version = self.rust_info().version(self, &self.version);
|
||||
if let Some(ref s) = self.config.description {
|
||||
if !s.is_empty() {
|
||||
version.push_str(" (");
|
||||
version.push_str(s);
|
||||
version.push(')');
|
||||
}
|
||||
if let Some(ref s) = self.config.description
|
||||
&& !s.is_empty()
|
||||
{
|
||||
version.push_str(" (");
|
||||
version.push_str(s);
|
||||
version.push(')');
|
||||
}
|
||||
version
|
||||
}
|
||||
|
|
@ -1760,14 +1760,14 @@ Executed at: {executed_at}"#,
|
|||
pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) {
|
||||
self.copy_link_internal(src, dst, false);
|
||||
|
||||
if file_type.could_have_split_debuginfo() {
|
||||
if let Some(dbg_file) = split_debuginfo(src) {
|
||||
self.copy_link_internal(
|
||||
&dbg_file,
|
||||
&dst.with_extension(dbg_file.extension().unwrap()),
|
||||
false,
|
||||
);
|
||||
}
|
||||
if file_type.could_have_split_debuginfo()
|
||||
&& let Some(dbg_file) = split_debuginfo(src)
|
||||
{
|
||||
self.copy_link_internal(
|
||||
&dbg_file,
|
||||
&dst.with_extension(dbg_file.extension().unwrap()),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1779,13 +1779,14 @@ Executed at: {executed_at}"#,
|
|||
if src == dst {
|
||||
return;
|
||||
}
|
||||
if let Err(e) = fs::remove_file(dst) {
|
||||
if cfg!(windows) && e.kind() != io::ErrorKind::NotFound {
|
||||
// workaround for https://github.com/rust-lang/rust/issues/127126
|
||||
// if removing the file fails, attempt to rename it instead.
|
||||
let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
|
||||
let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
|
||||
}
|
||||
if let Err(e) = fs::remove_file(dst)
|
||||
&& cfg!(windows)
|
||||
&& e.kind() != io::ErrorKind::NotFound
|
||||
{
|
||||
// workaround for https://github.com/rust-lang/rust/issues/127126
|
||||
// if removing the file fails, attempt to rename it instead.
|
||||
let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
|
||||
let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
|
||||
}
|
||||
let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display()));
|
||||
let mut src = src.to_path_buf();
|
||||
|
|
@ -1894,10 +1895,10 @@ Executed at: {executed_at}"#,
|
|||
chmod(&dst, file_type.perms());
|
||||
|
||||
// If this file can have debuginfo, look for split debuginfo and install it too.
|
||||
if file_type.could_have_split_debuginfo() {
|
||||
if let Some(dbg_file) = split_debuginfo(src) {
|
||||
self.install(&dbg_file, dstdir, FileType::Regular);
|
||||
}
|
||||
if file_type.could_have_split_debuginfo()
|
||||
&& let Some(dbg_file) = split_debuginfo(src)
|
||||
{
|
||||
self.install(&dbg_file, dstdir, FileType::Regular);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ pub fn find_recent_config_change_ids(current_id: usize) -> &'static [ChangeInfo]
|
|||
// an empty list (it may be due to switching from a recent branch to an
|
||||
// older one); otherwise, return the full list (assuming the user provided
|
||||
// the incorrect change-id by accident).
|
||||
if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) {
|
||||
if current_id > config.change_id {
|
||||
return &[];
|
||||
}
|
||||
if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id)
|
||||
&& current_id > config.change_id
|
||||
{
|
||||
return &[];
|
||||
}
|
||||
|
||||
CONFIG_CHANGE_HISTORY
|
||||
|
|
@ -411,4 +411,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
|||
severity: ChangeSeverity::Info,
|
||||
summary: "`./x run` now supports running in-tree `rustfmt`, e.g., `./x run rustfmt -- --check /path/to/file.rs`.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 119899,
|
||||
severity: ChangeSeverity::Warning,
|
||||
summary: "Stage0 library no longer matches the in-tree library, which means stage1 compiler now uses the beta library.",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::utils::load_env_var;
|
|||
#[derive(serde::Deserialize, Debug, Clone)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Job {
|
||||
/// Name of the job, e.g. mingw-check
|
||||
/// Name of the job, e.g. mingw-check-1
|
||||
pub name: String,
|
||||
/// GitHub runner on which the job should be executed
|
||||
pub os: String,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ try-job: dist-i686-msvc"#,
|
|||
fn pr_jobs() {
|
||||
let stdout = get_matrix("pull_request", "commit", "refs/heads/pr/1234");
|
||||
insta::assert_snapshot!(stdout, @r#"
|
||||
jobs=[{"name":"mingw-check","full_name":"PR - mingw-check","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-tidy","full_name":"PR - mingw-check-tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}]
|
||||
jobs=[{"name":"mingw-check-1","full_name":"PR - mingw-check-1","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-2","full_name":"PR - mingw-check-2","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-tidy","full_name":"PR - mingw-check-tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}]
|
||||
run_type=pr
|
||||
"#);
|
||||
}
|
||||
|
|
@ -51,6 +51,8 @@ fn get_matrix(event_name: &str, commit_msg: &str, branch_ref: &str) -> String {
|
|||
.env("GITHUB_EVENT_NAME", event_name)
|
||||
.env("COMMIT_MESSAGE", commit_msg)
|
||||
.env("GITHUB_REF", branch_ref)
|
||||
.env("GITHUB_RUN_ID", "123")
|
||||
.env("GITHUB_RUN_ATTEMPT", "1")
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
.expect("Failed to execute command");
|
||||
|
|
|
|||
|
|
@ -64,7 +64,9 @@ envs:
|
|||
# These jobs automatically inherit envs.pr, to avoid repeating
|
||||
# it in each job definition.
|
||||
pr:
|
||||
- name: mingw-check
|
||||
- name: mingw-check-1
|
||||
<<: *job-linux-4c
|
||||
- name: mingw-check-2
|
||||
<<: *job-linux-4c
|
||||
- name: mingw-check-tidy
|
||||
continue_on_error: true
|
||||
|
|
|
|||
|
|
@ -34,31 +34,23 @@ RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g
|
|||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/
|
||||
COPY host-x86_64/mingw-check-1/reuse-requirements.txt /tmp/
|
||||
RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt
|
||||
|
||||
COPY host-x86_64/mingw-check/check-default-config-profiles.sh /scripts/
|
||||
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
|
||||
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
|
||||
COPY host-x86_64/mingw-check-1/check-default-config-profiles.sh /scripts/
|
||||
COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
|
||||
COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/
|
||||
|
||||
# Check library crates on all tier 1 targets.
|
||||
# We disable optimized compiler built-ins because that requires a C toolchain for the target.
|
||||
# We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs.
|
||||
ENV SCRIPT \
|
||||
python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
|
||||
/scripts/check-default-config-profiles.sh && \
|
||||
python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
|
||||
python3 ../x.py check --target=x86_64-pc-windows-gnu --host=x86_64-pc-windows-gnu && \
|
||||
python3 ../x.py clippy ci && \
|
||||
python3 ../x.py build --stage 0 src/tools/build-manifest && \
|
||||
python3 ../x.py test --stage 0 src/tools/compiletest && \
|
||||
python3 ../x.py test --stage 0 core alloc std test proc_macro && \
|
||||
# Build both public and internal documentation.
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library && \
|
||||
mkdir -p /checkout/obj/staging/doc && \
|
||||
cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
|
||||
python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
|
||||
python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
|
||||
python3 ../x.py check --stage 1 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
|
||||
/scripts/validate-toolstate.sh && \
|
||||
/scripts/validate-error-codes.sh && \
|
||||
reuse --include-submodules lint && \
|
||||
37
src/ci/docker/host-x86_64/mingw-check-2/Dockerfile
Normal file
37
src/ci/docker/host-x86_64/mingw-check-2/Dockerfile
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
make \
|
||||
ninja-build \
|
||||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-pkg-resources \
|
||||
git \
|
||||
cmake \
|
||||
sudo \
|
||||
gdb \
|
||||
xz-utils \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
mingw-w64 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3"
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV SCRIPT \
|
||||
python3 ../x.py clippy ci && \
|
||||
python3 ../x.py test --stage 1 core alloc std test proc_macro && \
|
||||
# Build both public and internal documentation.
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library && \
|
||||
mkdir -p /checkout/obj/staging/doc && \
|
||||
cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library/test
|
||||
|
|
@ -34,12 +34,12 @@ COPY host-x86_64/mingw-check-tidy/eslint.version /tmp/
|
|||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/
|
||||
COPY host-x86_64/mingw-check-1/reuse-requirements.txt /tmp/
|
||||
RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt \
|
||||
&& pip3 install virtualenv
|
||||
|
||||
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
|
||||
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
|
||||
COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
|
||||
COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/
|
||||
|
||||
# NOTE: intentionally uses python2 for x.py so we can test it still works.
|
||||
# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
|
||||
|
|
|
|||
|
|
@ -29,5 +29,5 @@ RUN echo "optimize = false" >> /config/nopt-std-config.toml
|
|||
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
|
||||
--disable-optimize-tests \
|
||||
--set rust.test-compare-mode
|
||||
ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
|
||||
ENV SCRIPT python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std \
|
||||
&& python3 ../x.py --stage 2 test
|
||||
|
|
|
|||
|
|
@ -111,7 +111,9 @@ envs:
|
|||
# These jobs automatically inherit envs.pr, to avoid repeating
|
||||
# it in each job definition.
|
||||
pr:
|
||||
- name: mingw-check
|
||||
- name: mingw-check-1
|
||||
<<: *job-linux-4c
|
||||
- name: mingw-check-2
|
||||
<<: *job-linux-4c
|
||||
- name: mingw-check-tidy
|
||||
continue_on_error: true
|
||||
|
|
@ -125,7 +127,7 @@ pr:
|
|||
env:
|
||||
IMAGE: aarch64-gnu-llvm-19
|
||||
DOCKER_SCRIPT: stage_2_test_set1.sh
|
||||
<<: *job-aarch64-linux-8c
|
||||
<<: *job-aarch64-linux
|
||||
- name: aarch64-gnu-llvm-19-2
|
||||
env:
|
||||
IMAGE: aarch64-gnu-llvm-19
|
||||
|
|
@ -281,11 +283,14 @@ auto:
|
|||
env:
|
||||
IMAGE: i686-gnu-nopt
|
||||
DOCKER_SCRIPT: >-
|
||||
python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std &&
|
||||
python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std &&
|
||||
/scripts/stage_2_test_set2.sh
|
||||
<<: *job-linux-4c
|
||||
|
||||
- name: mingw-check
|
||||
- name: mingw-check-1
|
||||
<<: *job-linux-4c
|
||||
|
||||
- name: mingw-check-2
|
||||
<<: *job-linux-4c
|
||||
|
||||
- name: test-various
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
99e7c15e81385b38a8186b51edc4577d5d7b5bdd
|
||||
c68032fd4c442d275f4daa571ba19c076106b490
|
||||
|
|
|
|||
|
|
@ -45,13 +45,13 @@ compiler.
|
|||
|
||||
```mermaid
|
||||
graph TD
|
||||
s0c["stage0 compiler (1.63)"]:::downloaded -->|A| s0l("stage0 std (1.64)"):::with-s0c;
|
||||
s0c["stage0 compiler (1.86.0-beta.1)"]:::downloaded -->|A| s0l("stage0 std (1.86.0-beta.1)"):::downloaded;
|
||||
s0c & s0l --- stepb[ ]:::empty;
|
||||
stepb -->|B| s0ca["stage0 compiler artifacts (1.64)"]:::with-s0c;
|
||||
s0ca -->|copy| s1c["stage1 compiler (1.64)"]:::with-s0c;
|
||||
s1c -->|C| s1l("stage1 std (1.64)"):::with-s1c;
|
||||
stepb -->|B| s0ca["stage0 compiler artifacts (1.87.0-dev)"]:::with-s0c;
|
||||
s0ca -->|copy| s1c["stage1 compiler (1.87.0-dev)"]:::with-s0c;
|
||||
s1c -->|C| s1l("stage1 std (1.87.0-dev)"):::with-s1c;
|
||||
s1c & s1l --- stepd[ ]:::empty;
|
||||
stepd -->|D| s1ca["stage1 compiler artifacts (1.64)"]:::with-s1c;
|
||||
stepd -->|D| s1ca["stage1 compiler artifacts (1.87.0-dev)"]:::with-s1c;
|
||||
s1ca -->|copy| s2c["stage2 compiler"]:::with-s1c;
|
||||
|
||||
classDef empty width:0px,height:0px;
|
||||
|
|
@ -62,19 +62,21 @@ graph TD
|
|||
|
||||
### Stage 0: the pre-compiled compiler
|
||||
|
||||
The stage0 compiler is usually the current _beta_ `rustc` compiler and its
|
||||
The stage0 compiler is by default the very recent _beta_ `rustc` compiler and its
|
||||
associated dynamic libraries, which `./x.py` will download for you. (You can
|
||||
also configure `./x.py` to use something else.)
|
||||
also configure `./x.py` to change stage0 to something else.)
|
||||
|
||||
The stage0 compiler is then used only to compile [`src/bootstrap`],
|
||||
[`library/std`], and [`compiler/rustc`]. When assembling the libraries and
|
||||
binaries that will become the stage1 `rustc` compiler, the freshly compiled
|
||||
`std` and `rustc` are used. There are two concepts at play here: a compiler
|
||||
(with its set of dependencies) and its 'target' or 'object' libraries (`std` and
|
||||
`rustc`). Both are staged, but in a staggered manner.
|
||||
The precompiled stage0 compiler is then used only to compile [`src/bootstrap`] and [`compiler/rustc`]
|
||||
with precompiled stage0 std.
|
||||
|
||||
Note that to build the stage1 compiler we use the precompiled stage0 compiler and std.
|
||||
Therefore, to use a compiler with a std that is freshly built from the tree, you need to
|
||||
build the stage2 compiler.
|
||||
|
||||
There are two concepts at play here: a compiler (with its set of dependencies) and its
|
||||
'target' or 'object' libraries (`std` and `rustc`). Both are staged, but in a staggered manner.
|
||||
|
||||
[`compiler/rustc`]: https://github.com/rust-lang/rust/tree/master/compiler/rustc
|
||||
[`library/std`]: https://github.com/rust-lang/rust/tree/master/library/std
|
||||
[`src/bootstrap`]: https://github.com/rust-lang/rust/tree/master/src/bootstrap
|
||||
|
||||
### Stage 1: from current code, by an earlier compiler
|
||||
|
|
@ -84,16 +86,14 @@ The rustc source code is then compiled with the `stage0` compiler to produce the
|
|||
|
||||
### Stage 2: the truly current compiler
|
||||
|
||||
We then rebuild our `stage1` compiler with itself to produce the `stage2`
|
||||
We then rebuild the compiler using `stage1` compiler with in-tree std to produce the `stage2`
|
||||
compiler.
|
||||
|
||||
In theory, the `stage1` compiler is functionally identical to the `stage2`
|
||||
compiler, but in practice there are subtle differences. In particular, the
|
||||
`stage1` compiler itself was built by `stage0` and hence not by the source in
|
||||
your working directory. This means that the ABI generated by the `stage0`
|
||||
compiler may not match the ABI that would have been made by the `stage1`
|
||||
compiler, which can cause problems for dynamic libraries, tests, and tools using
|
||||
`rustc_private`.
|
||||
The `stage1` compiler itself was built by precompiled `stage0` compiler and std
|
||||
and hence not by the source in your working directory. This means that the ABI
|
||||
generated by the `stage0` compiler may not match the ABI that would have been made
|
||||
by the `stage1` compiler, which can cause problems for dynamic libraries, tests
|
||||
and tools using `rustc_private`.
|
||||
|
||||
Note that the `proc_macro` crate avoids this issue with a `C` FFI layer called
|
||||
`proc_macro::bridge`, allowing it to be used with `stage1`.
|
||||
|
|
@ -101,9 +101,10 @@ Note that the `proc_macro` crate avoids this issue with a `C` FFI layer called
|
|||
The `stage2` compiler is the one distributed with `rustup` and all other install
|
||||
methods. However, it takes a very long time to build because one must first
|
||||
build the new compiler with an older compiler and then use that to build the new
|
||||
compiler with itself. For development, you usually only want the `stage1`
|
||||
compiler, which you can build with `./x build library`. See [Building the
|
||||
compiler](../how-to-build-and-run.html#building-the-compiler).
|
||||
compiler with itself.
|
||||
|
||||
For development, you usually only want to use `--stage 1` flag to build things.
|
||||
See [Building the compiler](../how-to-build-and-run.html#building-the-compiler).
|
||||
|
||||
### Stage 3: the same-result test
|
||||
|
||||
|
|
@ -114,10 +115,11 @@ something has broken.
|
|||
### Building the stages
|
||||
|
||||
The script [`./x`] tries to be helpful and pick the stage you most likely meant
|
||||
for each subcommand. These defaults are as follows:
|
||||
for each subcommand. Here are some `x` commands with their default stages:
|
||||
|
||||
- `check`: `--stage 0`
|
||||
- `doc`: `--stage 0`
|
||||
- `check`: `--stage 1`
|
||||
- `clippy`: `--stage 1`
|
||||
- `doc`: `--stage 1`
|
||||
- `build`: `--stage 1`
|
||||
- `test`: `--stage 1`
|
||||
- `dist`: `--stage 2`
|
||||
|
|
@ -191,8 +193,8 @@ include, but are not limited to:
|
|||
without building `rustc` from source ('build with `stage0`, then test the
|
||||
artifacts'). If you're working on the standard library, this is normally the
|
||||
test command you want.
|
||||
- `./x build --stage 0` means to build with the beta `rustc`.
|
||||
- `./x doc --stage 0` means to document using the beta `rustdoc`.
|
||||
- `./x build --stage 0` means to build with the stage0 `rustc`.
|
||||
- `./x doc --stage 0` means to document using the stage0 `rustdoc`.
|
||||
|
||||
#### Examples of what *not* to do
|
||||
|
||||
|
|
@ -208,9 +210,6 @@ include, but are not limited to:
|
|||
|
||||
### Building vs. running
|
||||
|
||||
Note that `build --stage N compiler/rustc` **does not** build the stage N
|
||||
compiler: instead it builds the stage N+1 compiler _using_ the stage N compiler.
|
||||
|
||||
In short, _stage 0 uses the `stage0` compiler to create `stage0` artifacts which
|
||||
will later be uplifted to be the stage1 compiler_.
|
||||
|
||||
|
|
@ -268,23 +267,6 @@ However, when cross-compiling, `stage1` `std` will only run on the host. So the
|
|||
|
||||
(See in the table how `stage2` only builds non-host `std` targets).
|
||||
|
||||
### Why does only libstd use `cfg(bootstrap)`?
|
||||
|
||||
For docs on `cfg(bootstrap)` itself, see [Complications of
|
||||
Bootstrapping](#complications-of-bootstrapping).
|
||||
|
||||
The `rustc` generated by the `stage0` compiler is linked to the freshly-built
|
||||
`std`, which means that for the most part only `std` needs to be `cfg`-gated, so
|
||||
that `rustc` can use features added to `std` immediately after their addition,
|
||||
without need for them to get into the downloaded `beta` compiler.
|
||||
|
||||
Note this is different from any other Rust program: `stage1` `rustc` is built by
|
||||
the _beta_ compiler, but using the _master_ version of `libstd`!
|
||||
|
||||
The only time `rustc` uses `cfg(bootstrap)` is when it adds internal lints that
|
||||
use diagnostic items, or when it uses unstable library features that were
|
||||
recently changed.
|
||||
|
||||
### What is a 'sysroot'?
|
||||
|
||||
When you build a project with `cargo`, the build artifacts for dependencies are
|
||||
|
|
@ -459,7 +441,6 @@ compiler itself uses to run. These aren't actually used by artifacts the new
|
|||
compiler generates. This step also copies the `rustc` and `rustdoc` binaries we
|
||||
generated into `build/$HOST/stage/bin`.
|
||||
|
||||
The `stage1/bin/rustc` is a fully functional compiler, but it doesn't yet have
|
||||
any libraries to link built binaries or libraries to. The next 3 steps will
|
||||
provide those libraries for it; they are mostly equivalent to constructing the
|
||||
`stage1/bin` compiler so we don't go through them individually here.
|
||||
The `stage1/bin/rustc` is a fully functional compiler built with stage0 (precompiled) compiler and std.
|
||||
To use a compiler built entirely from source with the in-tree compiler and std, you need to build the
|
||||
stage2 compiler, which is compiled using the stage1 (in-tree) compiler and std.
|
||||
|
|
|
|||
|
|
@ -217,7 +217,6 @@ probably the best "go to" command for building a local compiler:
|
|||
This may *look* like it only builds the standard library, but that is not the case.
|
||||
What this command does is the following:
|
||||
|
||||
- Build `std` using the stage0 compiler
|
||||
- Build `rustc` using the stage0 compiler
|
||||
- This produces the stage1 compiler
|
||||
- Build `std` using the stage1 compiler
|
||||
|
|
@ -241,8 +240,7 @@ build. The **full** `rustc` build (what you get with `./x build
|
|||
--stage 2 compiler/rustc`) has quite a few more steps:
|
||||
|
||||
- Build `rustc` with the stage1 compiler.
|
||||
- The resulting compiler here is called the "stage2" compiler.
|
||||
- Build `std` with stage2 compiler.
|
||||
- The resulting compiler here is called the "stage2" compiler, which uses stage1 std from the previous command.
|
||||
- Build `librustdoc` and a bunch of other things with the stage2 compiler.
|
||||
|
||||
You almost never need to do this.
|
||||
|
|
@ -250,14 +248,14 @@ You almost never need to do this.
|
|||
### Build specific components
|
||||
|
||||
If you are working on the standard library, you probably don't need to build
|
||||
the compiler unless you are planning to use a recently added nightly feature.
|
||||
Instead, you can just build using the bootstrap compiler.
|
||||
every other default component. Instead, you can build a specific component by
|
||||
providing its name, like this:
|
||||
|
||||
```bash
|
||||
./x build --stage 0 library
|
||||
./x build --stage 1 library
|
||||
```
|
||||
|
||||
If you choose the `library` profile when running `x setup`, you can omit `--stage 0` (it's the
|
||||
If you choose the `library` profile when running `x setup`, you can omit `--stage 1` (it's the
|
||||
default).
|
||||
|
||||
## Creating a rustup toolchain
|
||||
|
|
@ -271,7 +269,6 @@ you will likely need to build at some point; for example, if you want
|
|||
to run the entire test suite).
|
||||
|
||||
```bash
|
||||
rustup toolchain link stage0 build/host/stage0-sysroot # beta compiler + stage0 std
|
||||
rustup toolchain link stage1 build/host/stage1
|
||||
rustup toolchain link stage2 build/host/stage2
|
||||
```
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ Look for existing targets to use as examples.
|
|||
After adding your target to the `rustc_target` crate you may want to add
|
||||
`core`, `std`, ... with support for your new target. In that case you will
|
||||
probably need access to some `target_*` cfg. Unfortunately when building with
|
||||
stage0 (the beta compiler), you'll get an error that the target cfg is
|
||||
stage0 (a precompiled compiler), you'll get an error that the target cfg is
|
||||
unexpected because stage0 doesn't know about the new target specification and
|
||||
we pass `--check-cfg` in order to tell it to check.
|
||||
|
||||
|
|
|
|||
|
|
@ -307,51 +307,15 @@ lets you use `cargo fmt`.
|
|||
[the section on vscode]: suggested.md#configuring-rust-analyzer-for-rustc
|
||||
[the section on rustup]: how-to-build-and-run.md?highlight=rustup#creating-a-rustup-toolchain
|
||||
|
||||
## Faster builds with `--keep-stage`.
|
||||
## Faster Builds with CI-rustc
|
||||
|
||||
Sometimes just checking whether the compiler builds is not enough. A common
|
||||
example is that you need to add a `debug!` statement to inspect the value of
|
||||
some state or better understand the problem. In that case, you don't really need
|
||||
a full build. By bypassing bootstrap's cache invalidation, you can often get
|
||||
these builds to complete very fast (e.g., around 30 seconds). The only catch is
|
||||
this requires a bit of fudging and may produce compilers that don't work (but
|
||||
that is easily detected and fixed).
|
||||
|
||||
The sequence of commands you want is as follows:
|
||||
|
||||
- Initial build: `./x build library`
|
||||
- As [documented previously], this will build a functional stage1 compiler as
|
||||
part of running all stage0 commands (which include building a `std`
|
||||
compatible with the stage1 compiler) as well as the first few steps of the
|
||||
"stage 1 actions" up to "stage1 (sysroot stage1) builds std".
|
||||
- Subsequent builds: `./x build library --keep-stage 1`
|
||||
- Note that we added the `--keep-stage 1` flag here
|
||||
|
||||
[documented previously]: ./how-to-build-and-run.md#building-the-compiler
|
||||
|
||||
As mentioned, the effect of `--keep-stage 1` is that we just _assume_ that the
|
||||
old standard library can be re-used. If you are editing the compiler, this is
|
||||
almost always true: you haven't changed the standard library, after all. But
|
||||
sometimes, it's not true: for example, if you are editing the "metadata" part of
|
||||
the compiler, which controls how the compiler encodes types and other states
|
||||
into the `rlib` files, or if you are editing things that wind up in the metadata
|
||||
(such as the definition of the MIR).
|
||||
|
||||
**The TL;DR is that you might get weird behavior from a compile when using
|
||||
`--keep-stage 1`** -- for example, strange [ICEs](../appendix/glossary.html#ice)
|
||||
or other panics. In that case, you should simply remove the `--keep-stage 1`
|
||||
from the command and rebuild. That ought to fix the problem.
|
||||
|
||||
You can also use `--keep-stage 1` when running tests. Something like this:
|
||||
|
||||
- Initial test run: `./x test tests/ui`
|
||||
- Subsequent test run: `./x test tests/ui --keep-stage 1`
|
||||
|
||||
### Iterating the standard library with `--keep-stage`
|
||||
|
||||
If you are making changes to the standard library, you can use `./x build
|
||||
--keep-stage 0 library` to iteratively rebuild the standard library without
|
||||
rebuilding the compiler.
|
||||
If you are not working on the compiler, you often don't need to build the compiler tree.
|
||||
For example, you can skip building the compiler and only build the `library` tree or the
|
||||
tools under `src/tools`. To achieve that, you have to enable this by setting the `download-rustc`
|
||||
option in your configuration. This tells bootstrap to use the latest nightly compiler for `stage > 0`
|
||||
steps, meaning it will have two precompiled compilers: stage0 compiler and `download-rustc` compiler
|
||||
for `stage > 0` steps. This way, it will never need to build the in-tree compiler. As a result, your
|
||||
build time will be significantly reduced by not building the in-tree compiler.
|
||||
|
||||
## Using incremental compilation
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ kinds of builds (sets of jobs).
|
|||
### Pull Request builds
|
||||
|
||||
After each push to a pull request, a set of `pr` jobs are executed. Currently,
|
||||
these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `mingw-check` and
|
||||
`mingw-check-tidy` jobs, all running on Linux. These execute a relatively short
|
||||
(~30 minutes) and lightweight test suite that should catch common issues. More
|
||||
these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `mingw-check-1`, `mingw-check-2`
|
||||
and `mingw-check-tidy` jobs, all running on Linux. These execute a relatively short
|
||||
(~40 minutes) and lightweight test suite that should catch common issues. More
|
||||
specifically, they run a set of lints, they try to perform a cross-compile check
|
||||
build to Windows mingw (without producing any artifacts) and they test the
|
||||
compiler using a *system* version of LLVM. Unfortunately, it would take too many
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ based on the ABI defined by Fortanix for the [Enclave Development Platform
|
|||
|
||||
[@jethrogb](https://github.com/jethrogb)
|
||||
[@raoulstrackx](https://github.com/raoulstrackx)
|
||||
[@mzohreva](https://github.com/mzohreva)
|
||||
[@aditijannu](https://github.com/aditijannu)
|
||||
|
||||
Further contacts:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# `no-steal-thir`
|
||||
|
||||
By default, to save on memory, the THIR body (obtained from the `tcx.thir_body` query) is stolen
|
||||
once no longer used. This is inconvenient for authors of rustc drivers who want to access the THIR.
|
||||
|
||||
This option disables the stealing. This has no observable effect on compiler behavior, only on
|
||||
memory usage.
|
||||
|
|
@ -119,6 +119,7 @@ pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
|
|||
|
||||
// Register normal generators for all floats.
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
register_float::<f16>(&mut tests, cfg);
|
||||
register_float::<f32>(&mut tests, cfg);
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ macro_rules! impl_float {
|
|||
|
||||
impl_float!(f32, u32; f64, u64);
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
impl_float!(f16, u16);
|
||||
|
||||
|
|
|
|||
|
|
@ -1606,7 +1606,7 @@ fn first_non_private<'tcx>(
|
|||
&& let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_use_def_id)
|
||||
&& let hir::ItemKind::Use(path, hir::UseKind::Single(_)) = item.kind
|
||||
{
|
||||
for res in &path.res {
|
||||
for res in path.res.present_items() {
|
||||
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -3014,7 +3014,7 @@ fn clean_use_statement<'tcx>(
|
|||
) -> Vec<Item> {
|
||||
let mut items = Vec::new();
|
||||
let hir::UsePath { segments, ref res, span } = *path;
|
||||
for &res in res {
|
||||
for res in res.present_items() {
|
||||
let path = hir::Path { segments, res, span };
|
||||
items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
hir::ItemKind::GlobalAsm { .. } => {}
|
||||
hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
|
||||
hir::ItemKind::Use(path, kind) => {
|
||||
for &res in &path.res {
|
||||
for res in path.res.present_items() {
|
||||
// Struct and variant constructors and proc macro stubs always show up alongside
|
||||
// their definitions, we've already processed them so just discard these.
|
||||
if should_ignore_res(res) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ walkdir = "2.3"
|
|||
filetime = "0.2.9"
|
||||
itertools = "0.12"
|
||||
pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] }
|
||||
askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] }
|
||||
askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] }
|
||||
|
||||
# UI test dependencies
|
||||
if_chain = "1.0"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ providing the `LateContext` (`cx`), our expression at hand, and
|
|||
the symbol of the trait in question:
|
||||
|
||||
```rust
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
@ -25,7 +25,7 @@ use rustc_span::symbol::sym;
|
|||
impl LateLintPass<'_> for CheckIteratorTraitLint {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
let implements_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
|
||||
implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
|
||||
implements_trait(cx, cx.typeck_results().expr_ty(expr), id, &[])
|
||||
});
|
||||
if implements_iterator {
|
||||
// [...]
|
||||
|
|
|
|||
|
|
@ -1026,7 +1026,7 @@ The order of associated items in traits.
|
|||
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
|
||||
reference.
|
||||
|
||||
**Default Value:** `target_pointer_width * 2`
|
||||
**Default Value:** `target_pointer_width`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
|
|
|
|||
|
|
@ -828,7 +828,7 @@ define_Conf! {
|
|||
trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(),
|
||||
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
|
||||
/// reference.
|
||||
#[default_text = "target_pointer_width * 2"]
|
||||
#[default_text = "target_pointer_width"]
|
||||
#[lints(trivially_copy_pass_by_ref)]
|
||||
trivial_copy_size_limit: Option<u64> = None,
|
||||
/// The maximum complexity a type can have
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::utils::{
|
||||
ClippyInfo, ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_args_split, run_with_output,
|
||||
ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, split_args_for_threads,
|
||||
walk_dir_no_dot_or_target,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{TokenKind, tokenize};
|
||||
|
|
@ -9,7 +10,6 @@ use std::io::{self, Read};
|
|||
use std::ops::ControlFlow;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command, Stdio};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub enum Error {
|
||||
Io(io::Error),
|
||||
|
|
@ -260,7 +260,7 @@ fn fmt_syms(update_mode: UpdateMode) {
|
|||
);
|
||||
}
|
||||
|
||||
fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) {
|
||||
fn run_rustfmt(update_mode: UpdateMode) {
|
||||
let mut rustfmt_path = String::from_utf8(run_with_output(
|
||||
"rustup which rustfmt",
|
||||
Command::new("rustup").args(["which", "rustfmt"]),
|
||||
|
|
@ -268,42 +268,19 @@ fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) {
|
|||
.expect("invalid rustfmt path");
|
||||
rustfmt_path.truncate(rustfmt_path.trim_end().len());
|
||||
|
||||
let mut cargo_path = String::from_utf8(run_with_output(
|
||||
"rustup which cargo",
|
||||
Command::new("rustup").args(["which", "cargo"]),
|
||||
))
|
||||
.expect("invalid cargo path");
|
||||
cargo_path.truncate(cargo_path.trim_end().len());
|
||||
let args: Vec<_> = walk_dir_no_dot_or_target()
|
||||
.filter_map(|e| {
|
||||
let e = expect_action(e, ErrAction::Read, ".");
|
||||
e.path()
|
||||
.as_os_str()
|
||||
.as_encoded_bytes()
|
||||
.ends_with(b".rs")
|
||||
.then(|| e.into_path().into_os_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Start all format jobs first before waiting on the results.
|
||||
let mut children = Vec::with_capacity(16);
|
||||
for &path in &[
|
||||
".",
|
||||
"clippy_config",
|
||||
"clippy_dev",
|
||||
"clippy_lints",
|
||||
"clippy_lints_internal",
|
||||
"clippy_utils",
|
||||
"rustc_tools_util",
|
||||
"lintcheck",
|
||||
] {
|
||||
let mut cmd = Command::new(&cargo_path);
|
||||
cmd.current_dir(clippy.path.join(path))
|
||||
.args(["fmt"])
|
||||
.env("RUSTFMT", &rustfmt_path)
|
||||
.stdout(Stdio::null())
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::piped());
|
||||
if update_mode.is_check() {
|
||||
cmd.arg("--check");
|
||||
}
|
||||
match cmd.spawn() {
|
||||
Ok(x) => children.push(("cargo fmt", x)),
|
||||
Err(ref e) => panic_action(&e, ErrAction::Run, "cargo fmt".as_ref()),
|
||||
}
|
||||
}
|
||||
|
||||
run_with_args_split(
|
||||
let mut children: Vec<_> = split_args_for_threads(
|
||||
32,
|
||||
|| {
|
||||
let mut cmd = Command::new(&rustfmt_path);
|
||||
if update_mode.is_check() {
|
||||
|
|
@ -312,66 +289,44 @@ fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) {
|
|||
cmd.stdout(Stdio::null())
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::piped())
|
||||
.args(["--config", "show_parse_errors=false"]);
|
||||
.args(["--unstable-features", "--skip-children"]);
|
||||
cmd
|
||||
},
|
||||
|cmd| match cmd.spawn() {
|
||||
Ok(x) => children.push(("rustfmt", x)),
|
||||
Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()),
|
||||
},
|
||||
WalkDir::new("tests")
|
||||
.into_iter()
|
||||
.filter_entry(|p| p.path().file_name().is_none_or(|x| x != "skip_rustfmt"))
|
||||
.filter_map(|e| {
|
||||
let e = e.expect("error reading `tests`");
|
||||
e.path()
|
||||
.as_os_str()
|
||||
.as_encoded_bytes()
|
||||
.ends_with(b".rs")
|
||||
.then(|| e.into_path().into_os_string())
|
||||
}),
|
||||
);
|
||||
args.iter(),
|
||||
)
|
||||
.map(|mut cmd| expect_action(cmd.spawn(), ErrAction::Run, "rustfmt"))
|
||||
.collect();
|
||||
|
||||
for (name, child) in &mut children {
|
||||
match child.wait() {
|
||||
Ok(status) => match (update_mode, status.exit_ok()) {
|
||||
(UpdateMode::Check | UpdateMode::Change, Ok(())) => {},
|
||||
(UpdateMode::Check, Err(_)) => {
|
||||
let mut s = String::new();
|
||||
if let Some(mut stderr) = child.stderr.take()
|
||||
&& stderr.read_to_string(&mut s).is_ok()
|
||||
{
|
||||
eprintln!("{s}");
|
||||
}
|
||||
eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
|
||||
process::exit(1);
|
||||
},
|
||||
(UpdateMode::Change, Err(e)) => {
|
||||
let mut s = String::new();
|
||||
if let Some(mut stderr) = child.stderr.take()
|
||||
&& stderr.read_to_string(&mut s).is_ok()
|
||||
{
|
||||
eprintln!("{s}");
|
||||
}
|
||||
panic_action(&e, ErrAction::Run, name.as_ref());
|
||||
},
|
||||
for child in &mut children {
|
||||
let status = expect_action(child.wait(), ErrAction::Run, "rustfmt");
|
||||
match (update_mode, status.exit_ok()) {
|
||||
(UpdateMode::Check | UpdateMode::Change, Ok(())) => {},
|
||||
(UpdateMode::Check, Err(_)) => {
|
||||
let mut s = String::new();
|
||||
if let Some(mut stderr) = child.stderr.take()
|
||||
&& stderr.read_to_string(&mut s).is_ok()
|
||||
{
|
||||
eprintln!("{s}");
|
||||
}
|
||||
eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
|
||||
process::exit(1);
|
||||
},
|
||||
(UpdateMode::Change, e) => {
|
||||
let mut s = String::new();
|
||||
if let Some(mut stderr) = child.stderr.take()
|
||||
&& stderr.read_to_string(&mut s).is_ok()
|
||||
{
|
||||
eprintln!("{s}");
|
||||
}
|
||||
expect_action(e, ErrAction::Run, "rustfmt");
|
||||
},
|
||||
Err(ref e) => panic_action(e, ErrAction::Run, name.as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the "main" function of cargo dev fmt
|
||||
pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) {
|
||||
if clippy.has_intellij_hook {
|
||||
eprintln!(
|
||||
"error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\
|
||||
Not formatting because that would format the local repo as well!\n\
|
||||
Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`."
|
||||
);
|
||||
return;
|
||||
}
|
||||
run_rustfmt(clippy, update_mode);
|
||||
pub fn run(update_mode: UpdateMode) {
|
||||
run_rustfmt(update_mode);
|
||||
fmt_syms(update_mode);
|
||||
if let Err(e) = fmt_conf(update_mode.is_check()) {
|
||||
e.display();
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn main() {
|
|||
allow_staged,
|
||||
allow_no_vcs,
|
||||
} => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
|
||||
DevCommand::Fmt { check } => fmt::run(&clippy, utils::UpdateMode::from_check(check)),
|
||||
DevCommand::Fmt { check } => fmt::run(utils::UpdateMode::from_check(check)),
|
||||
DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)),
|
||||
DevCommand::NewLint {
|
||||
pass,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints};
|
||||
use crate::utils::{
|
||||
FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists,
|
||||
try_rename_dir, try_rename_file,
|
||||
ErrAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists,
|
||||
delete_file_if_exists, expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target,
|
||||
};
|
||||
use rustc_lexer::TokenKind;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
/// Runs the `rename_lint` command.
|
||||
///
|
||||
|
|
@ -133,17 +132,10 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
|
|||
}
|
||||
|
||||
let mut update_fn = file_update_fn(old_name, new_name, mod_edit);
|
||||
for file in WalkDir::new(".").into_iter().filter_entry(|e| {
|
||||
// Skip traversing some of the larger directories.
|
||||
e.path()
|
||||
.as_os_str()
|
||||
.as_encoded_bytes()
|
||||
.get(2..)
|
||||
.is_none_or(|x| x != "target".as_bytes() && x != ".git".as_bytes())
|
||||
}) {
|
||||
let file = file.expect("error reading clippy directory");
|
||||
if file.path().as_os_str().as_encoded_bytes().ends_with(b".rs") {
|
||||
updater.update_file(file.path(), &mut update_fn);
|
||||
for e in walk_dir_no_dot_or_target() {
|
||||
let e = expect_action(e, ErrAction::Read, ".");
|
||||
if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") {
|
||||
updater.update_file(e.path(), &mut update_fn);
|
||||
}
|
||||
}
|
||||
generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::utils::{
|
||||
ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_action, update_text_region_fn,
|
||||
ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashSet;
|
||||
|
|
@ -201,10 +201,7 @@ pub fn find_lint_decls() -> Vec<Lint> {
|
|||
/// Reads the source files from the given root directory
|
||||
fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirEntry, String)> {
|
||||
WalkDir::new(src_root).into_iter().filter_map(move |e| {
|
||||
let e = match e {
|
||||
Ok(e) => e,
|
||||
Err(ref e) => panic_action(e, ErrAction::Read, src_root),
|
||||
};
|
||||
let e = expect_action(e, ErrAction::Read, src_root);
|
||||
let path = e.path().as_os_str().as_encoded_bytes();
|
||||
if let Some(path) = path.strip_suffix(b".rs")
|
||||
&& let Some(path) = path.get("clippy_lints/src/".len()..)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
use core::fmt::{self, Display};
|
||||
use core::num::NonZero;
|
||||
use core::ops::Range;
|
||||
use core::slice;
|
||||
use core::str::FromStr;
|
||||
use rustc_lexer::{self as lexer, FrontmatterAllowed};
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io::{self, Read as _, Seek as _, SeekFrom, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, ExitStatus, Stdio};
|
||||
use std::{env, thread};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
||||
|
|
@ -45,6 +47,14 @@ pub fn panic_action(err: &impl Display, action: ErrAction, path: &Path) -> ! {
|
|||
panic!("error {} `{}`: {}", action.as_str(), path.display(), *err)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn expect_action<T>(res: Result<T, impl Display>, action: ErrAction, path: impl AsRef<Path>) -> T {
|
||||
match res {
|
||||
Ok(x) => x,
|
||||
Err(ref e) => panic_action(e, action, path.as_ref()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around `std::fs::File` which panics with a path on failure.
|
||||
pub struct File<'a> {
|
||||
pub inner: fs::File,
|
||||
|
|
@ -55,9 +65,9 @@ impl<'a> File<'a> {
|
|||
#[track_caller]
|
||||
pub fn open(path: &'a (impl AsRef<Path> + ?Sized), options: &mut OpenOptions) -> Self {
|
||||
let path = path.as_ref();
|
||||
match options.open(path) {
|
||||
Ok(inner) => Self { inner, path },
|
||||
Err(e) => panic_action(&e, ErrAction::Open, path),
|
||||
Self {
|
||||
inner: expect_action(options.open(path), ErrAction::Open, path),
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,10 +94,7 @@ impl<'a> File<'a> {
|
|||
/// Read the entire contents of a file to the given buffer.
|
||||
#[track_caller]
|
||||
pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String {
|
||||
match self.inner.read_to_string(dst) {
|
||||
Ok(_) => {},
|
||||
Err(e) => panic_action(&e, ErrAction::Read, self.path),
|
||||
}
|
||||
expect_action(self.inner.read_to_string(dst), ErrAction::Read, self.path);
|
||||
dst
|
||||
}
|
||||
|
||||
|
|
@ -107,9 +114,7 @@ impl<'a> File<'a> {
|
|||
},
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
if let Err(e) = res {
|
||||
panic_action(&e, ErrAction::Write, self.path);
|
||||
}
|
||||
expect_action(res, ErrAction::Write, self.path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -660,47 +665,91 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool {
|
|||
}
|
||||
|
||||
pub fn write_file(path: &Path, contents: &str) {
|
||||
fs::write(path, contents).unwrap_or_else(|e| panic_action(&e, ErrAction::Write, path));
|
||||
expect_action(fs::write(path, contents), ErrAction::Write, path);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn run_with_output(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) -> Vec<u8> {
|
||||
fn f(path: &Path, cmd: &mut Command) -> Vec<u8> {
|
||||
match cmd
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
{
|
||||
Ok(x) => match x.status.exit_ok() {
|
||||
Ok(()) => x.stdout,
|
||||
Err(ref e) => panic_action(e, ErrAction::Run, path),
|
||||
},
|
||||
Err(ref e) => panic_action(e, ErrAction::Run, path),
|
||||
}
|
||||
let output = expect_action(
|
||||
cmd.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.output(),
|
||||
ErrAction::Run,
|
||||
path,
|
||||
);
|
||||
expect_action(output.status.exit_ok(), ErrAction::Run, path);
|
||||
output.stdout
|
||||
}
|
||||
f(path.as_ref(), cmd)
|
||||
}
|
||||
|
||||
pub fn run_with_args_split(
|
||||
mut make_cmd: impl FnMut() -> Command,
|
||||
mut run_cmd: impl FnMut(&mut Command),
|
||||
args: impl Iterator<Item: AsRef<OsStr>>,
|
||||
) {
|
||||
let mut cmd = make_cmd();
|
||||
let mut len = 0;
|
||||
for arg in args {
|
||||
len += arg.as_ref().len();
|
||||
cmd.arg(arg);
|
||||
// Very conservative limit
|
||||
if len > 10000 {
|
||||
run_cmd(&mut cmd);
|
||||
cmd = make_cmd();
|
||||
len = 0;
|
||||
/// Splits an argument list across multiple `Command` invocations.
|
||||
///
|
||||
/// The argument list will be split into a number of batches based on
|
||||
/// `thread::available_parallelism`, with `min_batch_size` setting a lower bound on the size of each
|
||||
/// batch.
|
||||
///
|
||||
/// If the size of the arguments would exceed the system limit additional batches will be created.
|
||||
pub fn split_args_for_threads(
|
||||
min_batch_size: usize,
|
||||
make_cmd: impl FnMut() -> Command,
|
||||
args: impl ExactSizeIterator<Item: AsRef<OsStr>>,
|
||||
) -> impl Iterator<Item = Command> {
|
||||
struct Iter<F, I> {
|
||||
make_cmd: F,
|
||||
args: I,
|
||||
min_batch_size: usize,
|
||||
batch_size: usize,
|
||||
thread_count: usize,
|
||||
}
|
||||
impl<F, I> Iterator for Iter<F, I>
|
||||
where
|
||||
F: FnMut() -> Command,
|
||||
I: ExactSizeIterator<Item: AsRef<OsStr>>,
|
||||
{
|
||||
type Item = Command;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.thread_count > 1 {
|
||||
self.thread_count -= 1;
|
||||
}
|
||||
let mut cmd = (self.make_cmd)();
|
||||
let mut cmd_len = 0usize;
|
||||
for arg in self.args.by_ref().take(self.batch_size) {
|
||||
cmd.arg(arg.as_ref());
|
||||
// `+ 8` to account for the `argv` pointer on unix.
|
||||
// Windows is complicated since the arguments are first converted to UTF-16ish,
|
||||
// but this needs to account for the space between arguments and whatever additional
|
||||
// is needed to escape within an argument.
|
||||
cmd_len += arg.as_ref().len() + 8;
|
||||
cmd_len += 8;
|
||||
|
||||
// Windows has a command length limit of 32767. For unix systems this is more
|
||||
// complicated since the limit includes environment variables and room needs to be
|
||||
// left to edit them once the program starts, but the total size comes from
|
||||
// `getconf ARG_MAX`.
|
||||
//
|
||||
// For simplicity we use 30000 here under a few assumptions.
|
||||
// * Individual arguments aren't super long (the final argument is still added)
|
||||
// * `ARG_MAX` is set to a reasonable amount. Basically every system will be configured way above
|
||||
// what windows supports, but POSIX only requires `4096`.
|
||||
if cmd_len > 30000 {
|
||||
self.batch_size = self.args.len().div_ceil(self.thread_count).max(self.min_batch_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
(cmd_len != 0).then_some(cmd)
|
||||
}
|
||||
}
|
||||
if len != 0 {
|
||||
run_cmd(&mut cmd);
|
||||
let thread_count = thread::available_parallelism().map_or(1, NonZero::get);
|
||||
let batch_size = args.len().div_ceil(thread_count).max(min_batch_size);
|
||||
Iter {
|
||||
make_cmd,
|
||||
args,
|
||||
min_batch_size,
|
||||
batch_size,
|
||||
thread_count,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -720,3 +769,12 @@ pub fn delete_dir_if_exists(path: &Path) {
|
|||
Err(ref e) => panic_action(e, ErrAction::Delete, path),
|
||||
}
|
||||
}
|
||||
|
||||
/// Walks all items excluding top-level dot files/directories and any target directories.
|
||||
pub fn walk_dir_no_dot_or_target() -> impl Iterator<Item = ::walkdir::Result<::walkdir::DirEntry>> {
|
||||
WalkDir::new(".").into_iter().filter_entry(|e| {
|
||||
e.path()
|
||||
.file_name()
|
||||
.is_none_or(|x| x != "target" && x.as_encoded_bytes().first().copied() != Some(b'.'))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use clippy_utils::macros::{MacroCall, macro_backtrace};
|
|||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Node};
|
||||
use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, SyntaxContext, sym};
|
||||
|
|
@ -60,6 +60,8 @@ impl LateLintPass<'_> for DbgMacro {
|
|||
if cur_syntax_ctxt != self.prev_ctxt &&
|
||||
let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) &&
|
||||
!macro_call.span.in_external_macro(cx.sess().source_map()) &&
|
||||
// avoids exprs generated by the desugaring of coroutines
|
||||
!is_coroutine_desugar(expr) &&
|
||||
self.checked_dbg_call_site.insert(macro_call.span) &&
|
||||
// allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
|
||||
!(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
|
||||
|
|
@ -73,50 +75,51 @@ impl LateLintPass<'_> for DbgMacro {
|
|||
"the `dbg!` macro is intended as a debugging tool",
|
||||
|diag| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
|
||||
// dbg!()
|
||||
ExprKind::Block(..) => {
|
||||
// If the `dbg!` macro is a "free" statement and not contained within other expressions,
|
||||
// remove the whole statement.
|
||||
if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
|
||||
&& let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
|
||||
{
|
||||
(macro_call.span.to(semi_span), String::new())
|
||||
} else {
|
||||
(macro_call.span, String::from("()"))
|
||||
}
|
||||
},
|
||||
// dbg!(1)
|
||||
ExprKind::Match(val, ..) => (
|
||||
macro_call.span,
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string(),
|
||||
),
|
||||
// dbg!(2, 3)
|
||||
ExprKind::Tup(
|
||||
[
|
||||
Expr {
|
||||
kind: ExprKind::Match(first, ..),
|
||||
..
|
||||
},
|
||||
..,
|
||||
Expr {
|
||||
kind: ExprKind::Match(last, ..),
|
||||
..
|
||||
},
|
||||
],
|
||||
) => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
"..",
|
||||
&mut applicability,
|
||||
);
|
||||
(macro_call.span, format!("({snippet})"))
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (sugg_span, suggestion) =
|
||||
match is_async_move_desugar(expr).unwrap_or(expr).peel_drop_temps().kind {
|
||||
// dbg!()
|
||||
ExprKind::Block(..) => {
|
||||
// If the `dbg!` macro is a "free" statement and not contained within other expressions,
|
||||
// remove the whole statement.
|
||||
if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
|
||||
&& let Some(semi_span) =
|
||||
cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
|
||||
{
|
||||
(macro_call.span.to(semi_span), String::new())
|
||||
} else {
|
||||
(macro_call.span, String::from("()"))
|
||||
}
|
||||
},
|
||||
// dbg!(1)
|
||||
ExprKind::Match(val, ..) => (
|
||||
macro_call.span,
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string(),
|
||||
),
|
||||
// dbg!(2, 3)
|
||||
ExprKind::Tup(
|
||||
[
|
||||
Expr {
|
||||
kind: ExprKind::Match(first, ..),
|
||||
..
|
||||
},
|
||||
..,
|
||||
Expr {
|
||||
kind: ExprKind::Match(last, ..),
|
||||
..
|
||||
},
|
||||
],
|
||||
) => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
"..",
|
||||
&mut applicability,
|
||||
);
|
||||
(macro_call.span, format!("({snippet})"))
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
diag.span_suggestion(
|
||||
sugg_span,
|
||||
|
|
@ -134,6 +137,35 @@ impl LateLintPass<'_> for DbgMacro {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_coroutine_desugar(expr: &Expr<'_>) -> bool {
|
||||
matches!(
|
||||
expr.kind,
|
||||
ExprKind::Closure(Closure {
|
||||
kind: ClosureKind::Coroutine(CoroutineKind::Desugared(..)) | ClosureKind::CoroutineClosure(..),
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
if let ExprKind::Block(block, _) = expr.kind
|
||||
&& let [
|
||||
Stmt {
|
||||
kind:
|
||||
StmtKind::Let(LetStmt {
|
||||
source: LocalSource::AsyncFn,
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
] = block.stmts
|
||||
{
|
||||
return block.expr;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<MacroCall> {
|
||||
macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
RefOp::Method { mutbl, is_ufcs }
|
||||
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
|
||||
// Allow explicit deref in method chains. e.g. `foo.deref().bar()`
|
||||
&& (is_ufcs || !in_postfix_position(cx, expr)) =>
|
||||
&& (is_ufcs || !is_in_method_chain(cx, expr)) =>
|
||||
{
|
||||
let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
|
||||
self.state = Some((
|
||||
|
|
@ -728,7 +728,13 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
|
||||
fn is_in_method_chain<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
|
||||
if let ExprKind::MethodCall(_, recv, _, _) = e.kind
|
||||
&& matches!(recv.kind, ExprKind::MethodCall(..))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(parent) = get_parent_expr(cx, e)
|
||||
&& parent.span.eq_ctxt(e.span)
|
||||
{
|
||||
|
|
@ -986,6 +992,15 @@ fn report<'tcx>(
|
|||
);
|
||||
},
|
||||
State::DerefedBorrow(state) => {
|
||||
// Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context,
|
||||
// as this may make rustc trigger its `dangerous_implicit_autorefs` lint.
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind
|
||||
&& let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind
|
||||
&& cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let (snip, snip_is_macro) =
|
||||
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
|
|||
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
|
||||
for res in &path.res {
|
||||
self.check_res_emit(cx, res, item.span);
|
||||
if let Some(res) = path.res.type_ns {
|
||||
self.check_res_emit(cx, &res, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
|||
use itertools::Itertools;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{BytePos, Span};
|
||||
use std::cmp::Ordering;
|
||||
use rustc_span::BytePos;
|
||||
use std::ops::Range;
|
||||
|
||||
use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS};
|
||||
use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS, Fragments};
|
||||
|
||||
fn map_container_to_text(c: &super::Container) -> &'static str {
|
||||
match c {
|
||||
|
|
@ -19,29 +18,27 @@ fn map_container_to_text(c: &super::Container) -> &'static str {
|
|||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
doc: &str,
|
||||
range: Range<usize>,
|
||||
mut span: Span,
|
||||
cooked_range: Range<usize>,
|
||||
fragments: &Fragments<'_>,
|
||||
containers: &[super::Container],
|
||||
) {
|
||||
if doc[range.clone()].contains('\t') {
|
||||
// We don't do tab stops correctly.
|
||||
return;
|
||||
}
|
||||
|
||||
// Blockquote
|
||||
let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count();
|
||||
// Get blockquotes
|
||||
let ccount = doc[cooked_range.clone()].chars().filter(|c| *c == '>').count();
|
||||
let blockquote_level = containers
|
||||
.iter()
|
||||
.filter(|c| matches!(c, super::Container::Blockquote))
|
||||
.count();
|
||||
if ccount < blockquote_level {
|
||||
|
||||
if ccount < blockquote_level
|
||||
&& let Some(mut span) = fragments.span(cx, cooked_range.clone())
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DOC_LAZY_CONTINUATION,
|
||||
span,
|
||||
"doc quote line without `>` marker",
|
||||
|diag| {
|
||||
let mut doc_start_range = &doc[range];
|
||||
let mut doc_start_range = &doc[cooked_range];
|
||||
let mut suggested = String::new();
|
||||
for c in containers {
|
||||
let text = map_container_to_text(c);
|
||||
|
|
@ -78,7 +75,7 @@ pub(super) fn check(
|
|||
}
|
||||
|
||||
// List
|
||||
let leading_spaces = doc[range].chars().filter(|c| *c == ' ').count();
|
||||
let leading_spaces = doc[cooked_range.clone()].chars().filter(|c| *c == ' ').count();
|
||||
let list_indentation = containers
|
||||
.iter()
|
||||
.map(|c| {
|
||||
|
|
@ -89,36 +86,41 @@ pub(super) fn check(
|
|||
}
|
||||
})
|
||||
.sum();
|
||||
match leading_spaces.cmp(&list_indentation) {
|
||||
Ordering::Less => span_lint_and_then(
|
||||
cx,
|
||||
DOC_LAZY_CONTINUATION,
|
||||
span,
|
||||
"doc list item without indentation",
|
||||
|diag| {
|
||||
// simpler suggestion style for indentation
|
||||
let indent = list_indentation - leading_spaces;
|
||||
diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"indent this line",
|
||||
std::iter::repeat_n(" ", indent).join(""),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.help("if this is supposed to be its own paragraph, add a blank line");
|
||||
},
|
||||
),
|
||||
Ordering::Greater => {
|
||||
let sugg = std::iter::repeat_n(" ", list_indentation).join("");
|
||||
span_lint_and_sugg(
|
||||
|
||||
if leading_spaces != list_indentation
|
||||
&& let Some(span) = fragments.span(cx, cooked_range.clone())
|
||||
{
|
||||
if leading_spaces < list_indentation {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DOC_OVERINDENTED_LIST_ITEMS,
|
||||
DOC_LAZY_CONTINUATION,
|
||||
span,
|
||||
"doc list item overindented",
|
||||
format!("try using `{sugg}` ({list_indentation} spaces)"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
"doc list item without indentation",
|
||||
|diag| {
|
||||
// simpler suggestion style for indentation
|
||||
let indent = list_indentation - leading_spaces;
|
||||
diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"indent this line",
|
||||
std::iter::repeat_n(" ", indent).join(""),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.help("if this is supposed to be its own paragraph, add a blank line");
|
||||
},
|
||||
);
|
||||
},
|
||||
Ordering::Equal => {},
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let sugg = std::iter::repeat_n(" ", list_indentation).join("");
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DOC_OVERINDENTED_LIST_ITEMS,
|
||||
span,
|
||||
"doc list item overindented",
|
||||
format!("try using `{sugg}` ({list_indentation} spaces)"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,15 @@ use rustc_lint::LateContext;
|
|||
use rustc_span::{BytePos, Pos, Span};
|
||||
use url::Url;
|
||||
|
||||
use crate::doc::DOC_MARKDOWN;
|
||||
use crate::doc::{DOC_MARKDOWN, Fragments};
|
||||
use std::ops::Range;
|
||||
|
||||
pub fn check(
|
||||
cx: &LateContext<'_>,
|
||||
valid_idents: &FxHashSet<String>,
|
||||
text: &str,
|
||||
span: Span,
|
||||
fragments: &Fragments<'_>,
|
||||
fragment_range: Range<usize>,
|
||||
code_level: isize,
|
||||
blockquote_level: isize,
|
||||
) {
|
||||
|
|
@ -64,20 +66,31 @@ pub fn check(
|
|||
close_parens += 1;
|
||||
}
|
||||
|
||||
// Adjust for the current word
|
||||
let offset = word.as_ptr() as usize - text.as_ptr() as usize;
|
||||
let span = Span::new(
|
||||
span.lo() + BytePos::from_usize(offset),
|
||||
span.lo() + BytePos::from_usize(offset + word.len()),
|
||||
span.ctxt(),
|
||||
span.parent(),
|
||||
);
|
||||
// We'll use this offset to calculate the span to lint.
|
||||
let fragment_offset = word.as_ptr() as usize - text.as_ptr() as usize;
|
||||
|
||||
check_word(cx, word, span, code_level, blockquote_level);
|
||||
// Adjust for the current word
|
||||
check_word(
|
||||
cx,
|
||||
word,
|
||||
fragments,
|
||||
&fragment_range,
|
||||
fragment_offset,
|
||||
code_level,
|
||||
blockquote_level,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, blockquote_level: isize) {
|
||||
fn check_word(
|
||||
cx: &LateContext<'_>,
|
||||
word: &str,
|
||||
fragments: &Fragments<'_>,
|
||||
range: &Range<usize>,
|
||||
fragment_offset: usize,
|
||||
code_level: isize,
|
||||
blockquote_level: isize,
|
||||
) {
|
||||
/// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
|
||||
/// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
|
||||
/// letter (`NASA` is ok).
|
||||
|
|
@ -117,6 +130,16 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
|
|||
// try to get around the fact that `foo::bar` parses as a valid URL
|
||||
&& !url.cannot_be_a_base()
|
||||
{
|
||||
let Some(fragment_span) = fragments.span(cx, range.clone()) else {
|
||||
return;
|
||||
};
|
||||
let span = Span::new(
|
||||
fragment_span.lo() + BytePos::from_usize(fragment_offset),
|
||||
fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()),
|
||||
fragment_span.ctxt(),
|
||||
fragment_span.parent(),
|
||||
);
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
|
|
@ -137,6 +160,17 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
|
|||
}
|
||||
|
||||
if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") {
|
||||
let Some(fragment_span) = fragments.span(cx, range.clone()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let span = Span::new(
|
||||
fragment_span.lo() + BytePos::from_usize(fragment_offset),
|
||||
fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()),
|
||||
fragment_span.ctxt(),
|
||||
fragment_span.parent(),
|
||||
);
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{is_entrypoint_fn, is_trait_impl_item};
|
||||
use pulldown_cmark::Event::{
|
||||
Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
|
||||
|
|
@ -730,7 +729,10 @@ struct Fragments<'a> {
|
|||
}
|
||||
|
||||
impl Fragments<'_> {
|
||||
fn span(self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
|
||||
/// get the span for the markdown range. Note that this function is not cheap, use it with
|
||||
/// caution.
|
||||
#[must_use]
|
||||
fn span(&self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
|
||||
source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments)
|
||||
}
|
||||
}
|
||||
|
|
@ -1068,9 +1070,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
|||
);
|
||||
} else {
|
||||
for (text, range, assoc_code_level) in text_to_check {
|
||||
if let Some(span) = fragments.span(cx, range) {
|
||||
markdown::check(cx, valid_idents, &text, span, assoc_code_level, blockquote_level);
|
||||
}
|
||||
markdown::check(cx, valid_idents, &text, &fragments, range, assoc_code_level, blockquote_level);
|
||||
}
|
||||
}
|
||||
text_to_check = Vec::new();
|
||||
|
|
@ -1081,26 +1081,27 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
|||
| TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
|
||||
SoftBreak | HardBreak => {
|
||||
if !containers.is_empty()
|
||||
&& let Some((next_event, next_range)) = events.peek()
|
||||
&& let Some(next_span) = fragments.span(cx, next_range.clone())
|
||||
&& let Some(span) = fragments.span(cx, range.clone())
|
||||
&& !in_footnote_definition
|
||||
// Tabs aren't handled correctly vvvv
|
||||
&& !doc[range.clone()].contains('\t')
|
||||
&& let Some((next_event, next_range)) = events.peek()
|
||||
&& !matches!(next_event, End(_))
|
||||
{
|
||||
lazy_continuation::check(
|
||||
cx,
|
||||
doc,
|
||||
range.end..next_range.start,
|
||||
Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
|
||||
&fragments,
|
||||
&containers[..],
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(span) = fragments.span(cx, range.clone())
|
||||
|
||||
if event == HardBreak
|
||||
&& !doc[range.clone()].trim().starts_with('\\')
|
||||
&& let Some(span) = fragments.span(cx, range.clone())
|
||||
&& !span.from_expansion()
|
||||
&& let Some(snippet) = snippet_opt(cx, span)
|
||||
&& !snippet.trim().starts_with('\\')
|
||||
&& event == HardBreak {
|
||||
{
|
||||
collected_breaks.push(span);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
|||
// so lint on the `use` statement directly.
|
||||
if let ItemKind::Use(path, kind @ (UseKind::Single(_) | UseKind::Glob)) = item.kind
|
||||
&& !item.span.in_external_macro(cx.sess().source_map())
|
||||
&& let Some(def_id) = path.res[0].opt_def_id()
|
||||
// use `present_items` because it could be in either type_ns or value_ns
|
||||
&& let Some(res) = path.res.present_items().next()
|
||||
&& let Some(def_id) = res.opt_def_id()
|
||||
&& self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
|
||||
{
|
||||
let module = if is_integer_module(cx, def_id) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,13 @@ pub(super) fn check<'tcx>(
|
|||
)[..],
|
||||
);
|
||||
}
|
||||
|
||||
// If the return type requires adjustments, we need to add a `.map` after the iterator
|
||||
let inner_ret_adjust = cx.typeck_results().expr_adjustments(inner_ret);
|
||||
if !inner_ret_adjust.is_empty() {
|
||||
snippet.push_str(".map(|v| v as _)");
|
||||
}
|
||||
|
||||
// Extends to `last_stmt` to include semicolon in case of `return None;`
|
||||
let lint_span = span.to(last_stmt.span).to(last_ret.span);
|
||||
span_lint_and_then(
|
||||
|
|
|
|||
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