mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-08 07:57:40 +00:00
Auto merge of #85014 - Dylan-DPC:rollup-jzpbkdu, r=Dylan-DPC
Rollup of 11 pull requests Successful merges: - #84409 (Ensure TLS destructors run before thread joins in SGX) - #84500 (Add --run flag to compiletest) - #84728 (Add test for suggestion to borrow unsized function parameters) - #84734 (Add `needs-unwind` and beginning of support for testing `panic=abort` std to compiletest) - #84755 (Allow using `core::` in intra-doc links within core itself) - #84871 (Disallows `#![feature(no_coverage)]` on stable and beta (using standard crate-level gating)) - #84872 (Wire up tidy dependency checks for cg_clif) - #84896 (Handle incorrect placement of parentheses in trait bounds more gracefully) - #84905 (CTFE engine: rename copy → copy_intrinsic, move to intrinsics.rs) - #84953 (Remove unneeded call to with_default_session_globals in rustdoc highlight) - #84987 (small nits) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1773f14a24
@ -15,20 +15,12 @@ pub fn expand_deriving_eq(
|
|||||||
item: &Annotatable,
|
item: &Annotatable,
|
||||||
push: &mut dyn FnMut(Annotatable),
|
push: &mut dyn FnMut(Annotatable),
|
||||||
) {
|
) {
|
||||||
|
let span = cx.with_def_site_ctxt(span);
|
||||||
let inline = cx.meta_word(span, sym::inline);
|
let inline = cx.meta_word(span, sym::inline);
|
||||||
let no_coverage_ident =
|
|
||||||
rustc_ast::attr::mk_nested_word_item(Ident::new(sym::no_coverage, span));
|
|
||||||
let no_coverage_feature =
|
|
||||||
rustc_ast::attr::mk_list_item(Ident::new(sym::feature, span), vec![no_coverage_ident]);
|
|
||||||
let no_coverage = cx.meta_word(span, sym::no_coverage);
|
|
||||||
let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
|
let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
|
||||||
let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
|
let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
|
||||||
let attrs = vec![
|
let no_coverage = cx.meta_word(span, sym::no_coverage);
|
||||||
cx.attribute(inline),
|
let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
|
||||||
cx.attribute(no_coverage_feature),
|
|
||||||
cx.attribute(no_coverage),
|
|
||||||
cx.attribute(doc),
|
|
||||||
];
|
|
||||||
let trait_def = TraitDef {
|
let trait_def = TraitDef {
|
||||||
span,
|
span,
|
||||||
attributes: Vec::new(),
|
attributes: Vec::new(),
|
||||||
|
@ -273,13 +273,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
template!(List: "address, memory, thread"),
|
template!(List: "address, memory, thread"),
|
||||||
experimental!(no_sanitize)
|
experimental!(no_sanitize)
|
||||||
),
|
),
|
||||||
ungated!(
|
gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)),
|
||||||
// Not exclusively gated at the crate level (though crate-level is
|
|
||||||
// supported). The feature can alternatively be enabled on individual
|
|
||||||
// functions.
|
|
||||||
no_coverage, AssumedUsed,
|
|
||||||
template!(Word),
|
|
||||||
),
|
|
||||||
|
|
||||||
// FIXME: #14408 assume docs are used since rustdoc looks at them.
|
// FIXME: #14408 assume docs are used since rustdoc looks at them.
|
||||||
ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
|
ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
|
||||||
|
@ -2398,9 +2398,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
self.tcx.associated_item(def_id).ident
|
self.tcx.associated_item(def_id).ident
|
||||||
),
|
),
|
||||||
infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
|
infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
|
||||||
infer::BoundRegionInCoherence(name) => {
|
|
||||||
format!(" for lifetime parameter `{}` in coherence check", name)
|
|
||||||
}
|
|
||||||
infer::UpvarRegion(ref upvar_id, _) => {
|
infer::UpvarRegion(ref upvar_id, _) => {
|
||||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
||||||
format!(" for capture of `{}` by closure", var_name)
|
format!(" for capture of `{}` by closure", var_name)
|
||||||
|
@ -453,8 +453,6 @@ pub enum RegionVariableOrigin {
|
|||||||
|
|
||||||
UpvarRegion(ty::UpvarId, Span),
|
UpvarRegion(ty::UpvarId, Span),
|
||||||
|
|
||||||
BoundRegionInCoherence(Symbol),
|
|
||||||
|
|
||||||
/// This origin is used for the inference variables that we create
|
/// This origin is used for the inference variables that we create
|
||||||
/// during NLL region processing.
|
/// during NLL region processing.
|
||||||
Nll(NllRegionVariableOrigin),
|
Nll(NllRegionVariableOrigin),
|
||||||
@ -1749,7 +1747,6 @@ impl RegionVariableOrigin {
|
|||||||
| EarlyBoundRegion(a, ..)
|
| EarlyBoundRegion(a, ..)
|
||||||
| LateBoundRegion(a, ..)
|
| LateBoundRegion(a, ..)
|
||||||
| UpvarRegion(_, a) => a,
|
| UpvarRegion(_, a) => a,
|
||||||
BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
|
|
||||||
Nll(..) => bug!("NLL variable used with `span`"),
|
Nll(..) => bug!("NLL variable used with `span`"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
self.write_scalar(result, dest)?;
|
self.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
sym::copy => {
|
sym::copy => {
|
||||||
self.copy(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
|
self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
|
||||||
}
|
}
|
||||||
sym::offset => {
|
sym::offset => {
|
||||||
let ptr = self.read_scalar(&args[0])?.check_init()?;
|
let ptr = self.read_scalar(&args[0])?.check_init()?;
|
||||||
@ -530,4 +530,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
)?;
|
)?;
|
||||||
Ok(offset_ptr)
|
Ok(offset_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.
|
||||||
|
pub(crate) fn copy_intrinsic(
|
||||||
|
&mut self,
|
||||||
|
src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||||
|
dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||||
|
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
||||||
|
nonoverlapping: bool,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
|
||||||
|
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
|
||||||
|
let (size, align) = (layout.size, layout.align.abi);
|
||||||
|
let size = size.checked_mul(count, self).ok_or_else(|| {
|
||||||
|
err_ub_format!(
|
||||||
|
"overflow computing total size of `{}`",
|
||||||
|
if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Make sure we check both pointers for an access of the total size and aligment,
|
||||||
|
// *even if* the total size is 0.
|
||||||
|
let src =
|
||||||
|
self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
|
||||||
|
|
||||||
|
let dst =
|
||||||
|
self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
|
||||||
|
|
||||||
|
if let (Some(src), Some(dst)) = (src, dst) {
|
||||||
|
self.memory.copy(src, dst, size, nonoverlapping)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
//!
|
//!
|
||||||
//! The main entry point is the `step` method.
|
//! The main entry point is the `step` method.
|
||||||
|
|
||||||
use crate::interpret::OpTy;
|
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||||
use rustc_target::abi::LayoutOf;
|
use rustc_target::abi::LayoutOf;
|
||||||
@ -119,7 +118,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
let src = self.eval_operand(src, None)?;
|
let src = self.eval_operand(src, None)?;
|
||||||
let dst = self.eval_operand(dst, None)?;
|
let dst = self.eval_operand(dst, None)?;
|
||||||
let count = self.eval_operand(count, None)?;
|
let count = self.eval_operand(count, None)?;
|
||||||
self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
|
self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statements we do not track.
|
// Statements we do not track.
|
||||||
@ -149,37 +148,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn copy(
|
|
||||||
&mut self,
|
|
||||||
src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
|
||||||
dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
|
||||||
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
|
|
||||||
nonoverlapping: bool,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
|
|
||||||
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
|
|
||||||
let (size, align) = (layout.size, layout.align.abi);
|
|
||||||
let size = size.checked_mul(count, self).ok_or_else(|| {
|
|
||||||
err_ub_format!(
|
|
||||||
"overflow computing total size of `{}`",
|
|
||||||
if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Make sure we check both pointers for an access of the total size and aligment,
|
|
||||||
// *even if* the total size is 0.
|
|
||||||
let src =
|
|
||||||
self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
|
|
||||||
|
|
||||||
let dst =
|
|
||||||
self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
|
|
||||||
|
|
||||||
if let (Some(src), Some(dst)) = (src, dst) {
|
|
||||||
self.memory.copy(src, dst, size, nonoverlapping)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate an assignment statement.
|
/// Evaluate an assignment statement.
|
||||||
///
|
///
|
||||||
/// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
|
/// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
|
||||||
|
@ -470,7 +470,7 @@ impl<'a> Parser<'a> {
|
|||||||
/// Is a `dyn B0 + ... + Bn` type allowed here?
|
/// Is a `dyn B0 + ... + Bn` type allowed here?
|
||||||
fn is_explicit_dyn_type(&mut self) -> bool {
|
fn is_explicit_dyn_type(&mut self) -> bool {
|
||||||
self.check_keyword(kw::Dyn)
|
self.check_keyword(kw::Dyn)
|
||||||
&& (self.token.uninterpolated_span().rust_2018()
|
&& (!self.token.uninterpolated_span().rust_2015()
|
||||||
|| self.look_ahead(1, |t| {
|
|| self.look_ahead(1, |t| {
|
||||||
t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
|
t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
|
||||||
}))
|
}))
|
||||||
@ -539,7 +539,21 @@ impl<'a> Parser<'a> {
|
|||||||
) -> PResult<'a, GenericBounds> {
|
) -> PResult<'a, GenericBounds> {
|
||||||
let mut bounds = Vec::new();
|
let mut bounds = Vec::new();
|
||||||
let mut negative_bounds = Vec::new();
|
let mut negative_bounds = Vec::new();
|
||||||
while self.can_begin_bound() {
|
|
||||||
|
while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
|
||||||
|
if self.token.is_keyword(kw::Dyn) {
|
||||||
|
// Account for `&dyn Trait + dyn Other`.
|
||||||
|
self.struct_span_err(self.token.span, "invalid `dyn` keyword")
|
||||||
|
.help("`dyn` is only needed at the start of a trait `+`-separated list")
|
||||||
|
.span_suggestion(
|
||||||
|
self.token.span,
|
||||||
|
"remove this keyword",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
self.bump();
|
||||||
|
}
|
||||||
match self.parse_generic_bound()? {
|
match self.parse_generic_bound()? {
|
||||||
Ok(bound) => bounds.push(bound),
|
Ok(bound) => bounds.push(bound),
|
||||||
Err(neg_sp) => negative_bounds.push(neg_sp),
|
Err(neg_sp) => negative_bounds.push(neg_sp),
|
||||||
@ -721,7 +735,26 @@ impl<'a> Parser<'a> {
|
|||||||
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||||
let path = self.parse_path(PathStyle::Type)?;
|
let path = self.parse_path(PathStyle::Type)?;
|
||||||
if has_parens {
|
if has_parens {
|
||||||
|
if self.token.is_like_plus() {
|
||||||
|
// Someone has written something like `&dyn (Trait + Other)`. The correct code
|
||||||
|
// would be `&(dyn Trait + Other)`, but we don't have access to the appropriate
|
||||||
|
// span to suggest that. When written as `&dyn Trait + Other`, an appropriate
|
||||||
|
// suggestion is given.
|
||||||
|
let bounds = vec![];
|
||||||
|
self.parse_remaining_bounds(bounds, true)?;
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
|
let sp = vec![lo, self.prev_token.span];
|
||||||
|
let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
|
||||||
|
self.struct_span_err(sp, "incorrect braces around trait bounds")
|
||||||
|
.multipart_suggestion(
|
||||||
|
"remove the parentheses",
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
} else {
|
||||||
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let modifier = modifiers.to_trait_bound_modifier();
|
let modifier = modifiers.to_trait_bound_modifier();
|
||||||
|
@ -1044,8 +1044,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the global caches can be used.
|
/// Returns `true` if the global caches can be used.
|
||||||
/// Do note that if the type itself is not in the
|
|
||||||
/// global tcx, the local caches will be used.
|
|
||||||
fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
|
fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
|
||||||
// If there are any inference variables in the `ParamEnv`, then we
|
// If there are any inference variables in the `ParamEnv`, then we
|
||||||
// always use a cache local to this particular scope. Otherwise, we
|
// always use a cache local to this particular scope. Otherwise, we
|
||||||
|
@ -2661,8 +2661,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
let mut inline_span = None;
|
let mut inline_span = None;
|
||||||
let mut link_ordinal_span = None;
|
let mut link_ordinal_span = None;
|
||||||
let mut no_sanitize_span = None;
|
let mut no_sanitize_span = None;
|
||||||
let mut no_coverage_feature_enabled = false;
|
|
||||||
let mut no_coverage_attr = None;
|
|
||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
if tcx.sess.check_name(attr, sym::cold) {
|
if tcx.sess.check_name(attr, sym::cold) {
|
||||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
|
||||||
@ -2726,15 +2724,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
|
||||||
} else if tcx.sess.check_name(attr, sym::no_mangle) {
|
} else if tcx.sess.check_name(attr, sym::no_mangle) {
|
||||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||||
} else if attr.has_name(sym::feature) {
|
|
||||||
if let Some(list) = attr.meta_item_list() {
|
|
||||||
if list.iter().any(|nested_meta_item| nested_meta_item.has_name(sym::no_coverage)) {
|
|
||||||
tcx.sess.mark_attr_used(attr);
|
|
||||||
no_coverage_feature_enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if tcx.sess.check_name(attr, sym::no_coverage) {
|
} else if tcx.sess.check_name(attr, sym::no_coverage) {
|
||||||
no_coverage_attr = Some(attr);
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
|
||||||
} else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
|
} else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
|
||||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||||
} else if tcx.sess.check_name(attr, sym::used) {
|
} else if tcx.sess.check_name(attr, sym::used) {
|
||||||
@ -2945,23 +2936,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(no_coverage_attr) = no_coverage_attr {
|
|
||||||
if tcx.sess.features_untracked().no_coverage || no_coverage_feature_enabled {
|
|
||||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE
|
|
||||||
} else {
|
|
||||||
let mut err = feature_err(
|
|
||||||
&tcx.sess.parse_sess,
|
|
||||||
sym::no_coverage,
|
|
||||||
no_coverage_attr.span,
|
|
||||||
"the `#[no_coverage]` attribute is an experimental feature",
|
|
||||||
);
|
|
||||||
if tcx.sess.parse_sess.unstable_features.is_nightly_build() {
|
|
||||||
err.help("or, alternatively, add `#[feature(no_coverage)]` to the function");
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||||
if !attr.has_name(sym::inline) {
|
if !attr.has_name(sym::inline) {
|
||||||
return ia;
|
return ia;
|
||||||
|
@ -274,8 +274,7 @@ pub trait Eq: PartialEq<Self> {
|
|||||||
//
|
//
|
||||||
// This should never be implemented by hand.
|
// This should never be implemented by hand.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg_attr(not(bootstrap), feature(no_coverage))]
|
#[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605
|
||||||
#[cfg_attr(not(bootstrap), no_coverage)]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn assert_receiver_is_total_eq(&self) {}
|
fn assert_receiver_is_total_eq(&self) {}
|
||||||
@ -284,7 +283,7 @@ pub trait Eq: PartialEq<Self> {
|
|||||||
/// Derive macro generating an impl of the trait `Eq`.
|
/// Derive macro generating an impl of the trait `Eq`.
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||||
#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)]
|
#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)]
|
||||||
pub macro Eq($item:item) {
|
pub macro Eq($item:item) {
|
||||||
/* compiler built-in */
|
/* compiler built-in */
|
||||||
}
|
}
|
||||||
|
@ -723,7 +723,7 @@ extern "rust-intrinsic" {
|
|||||||
/// macro, which panics when it is executed, it is *undefined behavior* to
|
/// macro, which panics when it is executed, it is *undefined behavior* to
|
||||||
/// reach code marked with this function.
|
/// reach code marked with this function.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`](crate::hint::unreachable_unchecked).
|
/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`].
|
||||||
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
|
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
|
||||||
pub fn unreachable() -> !;
|
pub fn unreachable() -> !;
|
||||||
|
|
||||||
@ -768,13 +768,13 @@ extern "rust-intrinsic" {
|
|||||||
/// More specifically, this is the offset in bytes between successive
|
/// More specifically, this is the offset in bytes between successive
|
||||||
/// items of the same type, including alignment padding.
|
/// items of the same type, including alignment padding.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::mem::size_of`](crate::mem::size_of).
|
/// The stabilized version of this intrinsic is [`core::mem::size_of`].
|
||||||
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
|
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
|
||||||
pub fn size_of<T>() -> usize;
|
pub fn size_of<T>() -> usize;
|
||||||
|
|
||||||
/// The minimum alignment of a type.
|
/// The minimum alignment of a type.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::mem::align_of`](crate::mem::align_of).
|
/// The stabilized version of this intrinsic is [`core::mem::align_of`].
|
||||||
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
|
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
|
||||||
pub fn min_align_of<T>() -> usize;
|
pub fn min_align_of<T>() -> usize;
|
||||||
/// The preferred alignment of a type.
|
/// The preferred alignment of a type.
|
||||||
@ -790,13 +790,13 @@ extern "rust-intrinsic" {
|
|||||||
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
|
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
|
||||||
/// The required alignment of the referenced value.
|
/// The required alignment of the referenced value.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::mem::align_of_val`](crate::mem::align_of_val).
|
/// The stabilized version of this intrinsic is [`core::mem::align_of_val`].
|
||||||
#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
|
#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
|
||||||
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
|
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
|
||||||
|
|
||||||
/// Gets a static string slice containing the name of a type.
|
/// Gets a static string slice containing the name of a type.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::any::type_name`](crate::any::type_name).
|
/// The stabilized version of this intrinsic is [`core::any::type_name`].
|
||||||
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
|
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
|
||||||
pub fn type_name<T: ?Sized>() -> &'static str;
|
pub fn type_name<T: ?Sized>() -> &'static str;
|
||||||
|
|
||||||
@ -804,7 +804,7 @@ extern "rust-intrinsic" {
|
|||||||
/// function will return the same value for a type regardless of whichever
|
/// function will return the same value for a type regardless of whichever
|
||||||
/// crate it is invoked in.
|
/// crate it is invoked in.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::any::TypeId::of`](crate::any::TypeId::of).
|
/// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
|
||||||
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
|
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
|
||||||
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
||||||
|
|
||||||
@ -829,7 +829,7 @@ extern "rust-intrinsic" {
|
|||||||
|
|
||||||
/// Gets a reference to a static `Location` indicating where it was called.
|
/// Gets a reference to a static `Location` indicating where it was called.
|
||||||
///
|
///
|
||||||
/// Consider using [`core::panic::Location::caller`](crate::panic::Location::caller) instead.
|
/// Consider using [`core::panic::Location::caller`] instead.
|
||||||
#[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
|
#[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
|
||||||
pub fn caller_location() -> &'static crate::panic::Location<'static>;
|
pub fn caller_location() -> &'static crate::panic::Location<'static>;
|
||||||
|
|
||||||
@ -1158,11 +1158,11 @@ extern "rust-intrinsic" {
|
|||||||
|
|
||||||
/// Performs a volatile load from the `src` pointer.
|
/// Performs a volatile load from the `src` pointer.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::ptr::read_volatile`](crate::ptr::read_volatile).
|
/// The stabilized version of this intrinsic is [`core::ptr::read_volatile`].
|
||||||
pub fn volatile_load<T>(src: *const T) -> T;
|
pub fn volatile_load<T>(src: *const T) -> T;
|
||||||
/// Performs a volatile store to the `dst` pointer.
|
/// Performs a volatile store to the `dst` pointer.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::ptr::write_volatile`](crate::ptr::write_volatile).
|
/// The stabilized version of this intrinsic is [`core::ptr::write_volatile`].
|
||||||
pub fn volatile_store<T>(dst: *mut T, val: T);
|
pub fn volatile_store<T>(dst: *mut T, val: T);
|
||||||
|
|
||||||
/// Performs a volatile load from the `src` pointer
|
/// Performs a volatile load from the `src` pointer
|
||||||
@ -1703,7 +1703,7 @@ extern "rust-intrinsic" {
|
|||||||
/// Returns the value of the discriminant for the variant in 'v';
|
/// Returns the value of the discriminant for the variant in 'v';
|
||||||
/// if `T` has no discriminant, returns `0`.
|
/// if `T` has no discriminant, returns `0`.
|
||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is [`core::mem::discriminant`](crate::mem::discriminant).
|
/// The stabilized version of this intrinsic is [`core::mem::discriminant`].
|
||||||
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
||||||
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
|
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
|
||||||
|
|
||||||
|
@ -166,9 +166,14 @@
|
|||||||
#![feature(const_caller_location)]
|
#![feature(const_caller_location)]
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(no_niche)] // rust-lang/rust#68303
|
#![feature(no_niche)] // rust-lang/rust#68303
|
||||||
|
#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605
|
||||||
#![feature(int_error_matching)]
|
#![feature(int_error_matching)]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
|
// allow using `core::` in intra-doc links
|
||||||
|
#[allow(unused_extern_crates)]
|
||||||
|
extern crate self as core;
|
||||||
|
|
||||||
#[prelude_import]
|
#[prelude_import]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
@ -62,10 +62,12 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
|
|||||||
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
|
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
|
||||||
// FIXME: how to support TLS in library mode?
|
// FIXME: how to support TLS in library mode?
|
||||||
let tls = Box::new(tls::Tls::new());
|
let tls = Box::new(tls::Tls::new());
|
||||||
let _tls_guard = unsafe { tls.activate() };
|
let tls_guard = unsafe { tls.activate() };
|
||||||
|
|
||||||
if secondary {
|
if secondary {
|
||||||
super::thread::Thread::entry();
|
let join_notifier = super::thread::Thread::entry();
|
||||||
|
drop(tls_guard);
|
||||||
|
drop(join_notifier);
|
||||||
|
|
||||||
EntryReturn(0, 0)
|
EntryReturn(0, 0)
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,26 +9,37 @@ pub struct Thread(task_queue::JoinHandle);
|
|||||||
|
|
||||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
pub use self::task_queue::JoinNotifier;
|
||||||
|
|
||||||
mod task_queue {
|
mod task_queue {
|
||||||
use crate::sync::mpsc;
|
use super::wait_notify;
|
||||||
use crate::sync::{Mutex, MutexGuard, Once};
|
use crate::sync::{Mutex, MutexGuard, Once};
|
||||||
|
|
||||||
pub type JoinHandle = mpsc::Receiver<()>;
|
pub type JoinHandle = wait_notify::Waiter;
|
||||||
|
|
||||||
|
pub struct JoinNotifier(Option<wait_notify::Notifier>);
|
||||||
|
|
||||||
|
impl Drop for JoinNotifier {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.take().unwrap().notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct Task {
|
pub(super) struct Task {
|
||||||
p: Box<dyn FnOnce()>,
|
p: Box<dyn FnOnce()>,
|
||||||
done: mpsc::Sender<()>,
|
done: JoinNotifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) {
|
pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) {
|
||||||
let (done, recv) = mpsc::channel();
|
let (done, recv) = wait_notify::new();
|
||||||
|
let done = JoinNotifier(Some(done));
|
||||||
(Task { p, done }, recv)
|
(Task { p, done }, recv)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn run(self) {
|
pub(super) fn run(self) -> JoinNotifier {
|
||||||
(self.p)();
|
(self.p)();
|
||||||
let _ = self.done.send(());
|
self.done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +58,48 @@ mod task_queue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This module provides a synchronization primitive that does not use thread
|
||||||
|
/// local variables. This is needed for signaling that a thread has finished
|
||||||
|
/// execution. The signal is sent once all TLS destructors have finished at
|
||||||
|
/// which point no new thread locals should be created.
|
||||||
|
pub mod wait_notify {
|
||||||
|
use super::super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
|
||||||
|
use crate::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Notifier(Arc<SpinMutex<WaitVariable<bool>>>);
|
||||||
|
|
||||||
|
impl Notifier {
|
||||||
|
/// Notify the waiter. The waiter is either notified right away (if
|
||||||
|
/// currently blocked in `Waiter::wait()`) or later when it calls the
|
||||||
|
/// `Waiter::wait()` method.
|
||||||
|
pub fn notify(self) {
|
||||||
|
let mut guard = self.0.lock();
|
||||||
|
*guard.lock_var_mut() = true;
|
||||||
|
let _ = WaitQueue::notify_one(guard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Waiter(Arc<SpinMutex<WaitVariable<bool>>>);
|
||||||
|
|
||||||
|
impl Waiter {
|
||||||
|
/// Wait for a notification. If `Notifier::notify()` has already been
|
||||||
|
/// called, this will return immediately, otherwise the current thread
|
||||||
|
/// is blocked until notified.
|
||||||
|
pub fn wait(self) {
|
||||||
|
let guard = self.0.lock();
|
||||||
|
if *guard.lock_var() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WaitQueue::wait(guard, || {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> (Notifier, Waiter) {
|
||||||
|
let inner = Arc::new(SpinMutex::new(WaitVariable::new(false)));
|
||||||
|
(Notifier(inner.clone()), Waiter(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Thread {
|
impl Thread {
|
||||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||||
pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||||
@ -57,7 +110,7 @@ impl Thread {
|
|||||||
Ok(Thread(handle))
|
Ok(Thread(handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn entry() {
|
pub(super) fn entry() -> JoinNotifier {
|
||||||
let mut pending_tasks = task_queue::lock();
|
let mut pending_tasks = task_queue::lock();
|
||||||
let task = rtunwrap!(Some, pending_tasks.pop());
|
let task = rtunwrap!(Some, pending_tasks.pop());
|
||||||
drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
|
drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
|
||||||
@ -78,7 +131,7 @@ impl Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(self) {
|
pub fn join(self) {
|
||||||
let _ = self.0.recv();
|
self.0.wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::cell::{Cell, UnsafeCell};
|
use crate::cell::{Cell, UnsafeCell};
|
||||||
|
use crate::sync::atomic::{AtomicU8, Ordering};
|
||||||
use crate::sync::mpsc::{channel, Sender};
|
use crate::sync::mpsc::{channel, Sender};
|
||||||
use crate::thread::{self, LocalKey};
|
use crate::thread::{self, LocalKey};
|
||||||
use crate::thread_local;
|
use crate::thread_local;
|
||||||
@ -207,3 +208,110 @@ fn dtors_in_dtors_in_dtors_const_init() {
|
|||||||
});
|
});
|
||||||
rx.recv().unwrap();
|
rx.recv().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test tests that TLS destructors have run before the thread joins. The
|
||||||
|
// test has no false positives (meaning: if the test fails, there's actually
|
||||||
|
// an ordering problem). It may have false negatives, where the test passes but
|
||||||
|
// join is not guaranteed to be after the TLS destructors. However, false
|
||||||
|
// negatives should be exceedingly rare due to judicious use of
|
||||||
|
// thread::yield_now and running the test several times.
|
||||||
|
#[test]
|
||||||
|
fn join_orders_after_tls_destructors() {
|
||||||
|
// We emulate a synchronous MPSC rendezvous channel using only atomics and
|
||||||
|
// thread::yield_now. We can't use std::mpsc as the implementation itself
|
||||||
|
// may rely on thread locals.
|
||||||
|
//
|
||||||
|
// The basic state machine for an SPSC rendezvous channel is:
|
||||||
|
// FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS
|
||||||
|
// where the first transition is done by the “receiving” thread and the 2nd
|
||||||
|
// transition is done by the “sending” thread.
|
||||||
|
//
|
||||||
|
// We add an additional state `THREAD2_LAUNCHED` between `FRESH` and
|
||||||
|
// `THREAD1_WAITING` to block until all threads are actually running.
|
||||||
|
//
|
||||||
|
// A thread that joins on the “receiving” thread completion should never
|
||||||
|
// observe the channel in the `THREAD1_WAITING` state. If this does occur,
|
||||||
|
// we switch to the “poison” state `THREAD2_JOINED` and panic all around.
|
||||||
|
// (This is equivalent to “sending” from an alternate producer thread.)
|
||||||
|
const FRESH: u8 = 0;
|
||||||
|
const THREAD2_LAUNCHED: u8 = 1;
|
||||||
|
const THREAD1_WAITING: u8 = 2;
|
||||||
|
const MAIN_THREAD_RENDEZVOUS: u8 = 3;
|
||||||
|
const THREAD2_JOINED: u8 = 4;
|
||||||
|
static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH);
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
SYNC_STATE.store(FRESH, Ordering::SeqCst);
|
||||||
|
|
||||||
|
let jh = thread::Builder::new()
|
||||||
|
.name("thread1".into())
|
||||||
|
.spawn(move || {
|
||||||
|
struct TlDrop;
|
||||||
|
|
||||||
|
impl Drop for TlDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst);
|
||||||
|
loop {
|
||||||
|
match sync_state {
|
||||||
|
THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(),
|
||||||
|
MAIN_THREAD_RENDEZVOUS => break,
|
||||||
|
THREAD2_JOINED => panic!(
|
||||||
|
"Thread 1 still running after thread 2 joined on thread 1"
|
||||||
|
),
|
||||||
|
v => unreachable!("sync state: {}", v),
|
||||||
|
}
|
||||||
|
sync_state = SYNC_STATE.load(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static TL_DROP: TlDrop = TlDrop;
|
||||||
|
}
|
||||||
|
|
||||||
|
TL_DROP.with(|_| {});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match SYNC_STATE.load(Ordering::SeqCst) {
|
||||||
|
FRESH => thread::yield_now(),
|
||||||
|
THREAD2_LAUNCHED => break,
|
||||||
|
v => unreachable!("sync state: {}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let jh2 = thread::Builder::new()
|
||||||
|
.name("thread2".into())
|
||||||
|
.spawn(move || {
|
||||||
|
assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH);
|
||||||
|
jh.join().unwrap();
|
||||||
|
match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) {
|
||||||
|
MAIN_THREAD_RENDEZVOUS => return,
|
||||||
|
THREAD2_LAUNCHED | THREAD1_WAITING => {
|
||||||
|
panic!("Thread 2 running after thread 1 join before main thread rendezvous")
|
||||||
|
}
|
||||||
|
v => unreachable!("sync state: {:?}", v),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match SYNC_STATE.compare_exchange_weak(
|
||||||
|
THREAD1_WAITING,
|
||||||
|
MAIN_THREAD_RENDEZVOUS,
|
||||||
|
Ordering::SeqCst,
|
||||||
|
Ordering::SeqCst,
|
||||||
|
) {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(FRESH) => thread::yield_now(),
|
||||||
|
Err(THREAD2_LAUNCHED) => thread::yield_now(),
|
||||||
|
Err(THREAD2_JOINED) => {
|
||||||
|
panic!("Main thread rendezvous after thread 2 joined thread 1")
|
||||||
|
}
|
||||||
|
v => unreachable!("sync state: {:?}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jh2.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -489,6 +489,7 @@ mod dist {
|
|||||||
compare_mode: None,
|
compare_mode: None,
|
||||||
rustfix_coverage: false,
|
rustfix_coverage: false,
|
||||||
pass: None,
|
pass: None,
|
||||||
|
run: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let build = Build::new(config);
|
let build = Build::new(config);
|
||||||
@ -529,6 +530,7 @@ mod dist {
|
|||||||
compare_mode: None,
|
compare_mode: None,
|
||||||
rustfix_coverage: false,
|
rustfix_coverage: false,
|
||||||
pass: None,
|
pass: None,
|
||||||
|
run: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let build = Build::new(config);
|
let build = Build::new(config);
|
||||||
@ -584,6 +586,7 @@ mod dist {
|
|||||||
compare_mode: None,
|
compare_mode: None,
|
||||||
rustfix_coverage: false,
|
rustfix_coverage: false,
|
||||||
pass: None,
|
pass: None,
|
||||||
|
run: None,
|
||||||
};
|
};
|
||||||
// Make sure rustfmt binary not being found isn't an error.
|
// Make sure rustfmt binary not being found isn't an error.
|
||||||
config.channel = "beta".to_string();
|
config.channel = "beta".to_string();
|
||||||
|
@ -103,6 +103,7 @@ pub enum Subcommand {
|
|||||||
bless: bool,
|
bless: bool,
|
||||||
compare_mode: Option<String>,
|
compare_mode: Option<String>,
|
||||||
pass: Option<String>,
|
pass: Option<String>,
|
||||||
|
run: Option<String>,
|
||||||
test_args: Vec<String>,
|
test_args: Vec<String>,
|
||||||
rustc_args: Vec<String>,
|
rustc_args: Vec<String>,
|
||||||
fail_fast: bool,
|
fail_fast: bool,
|
||||||
@ -222,8 +223,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
|||||||
VALUE overrides the skip-rebuild option in config.toml.",
|
VALUE overrides the skip-rebuild option in config.toml.",
|
||||||
"VALUE",
|
"VALUE",
|
||||||
);
|
);
|
||||||
opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT");
|
opts.optopt("", "rust-profile-generate", "generate PGO profile with rustc build", "FORMAT");
|
||||||
opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT");
|
opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "FORMAT");
|
||||||
|
|
||||||
// We can't use getopt to parse the options until we have completed specifying which
|
// We can't use getopt to parse the options until we have completed specifying which
|
||||||
// options are valid, but under the current implementation, some options are conditional on
|
// options are valid, but under the current implementation, some options are conditional on
|
||||||
@ -293,6 +294,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
|||||||
"force {check,build,run}-pass tests to this mode.",
|
"force {check,build,run}-pass tests to this mode.",
|
||||||
"check | build | run",
|
"check | build | run",
|
||||||
);
|
);
|
||||||
|
opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never");
|
||||||
opts.optflag(
|
opts.optflag(
|
||||||
"",
|
"",
|
||||||
"rustfix-coverage",
|
"rustfix-coverage",
|
||||||
@ -556,6 +558,7 @@ Arguments:
|
|||||||
bless: matches.opt_present("bless"),
|
bless: matches.opt_present("bless"),
|
||||||
compare_mode: matches.opt_str("compare-mode"),
|
compare_mode: matches.opt_str("compare-mode"),
|
||||||
pass: matches.opt_str("pass"),
|
pass: matches.opt_str("pass"),
|
||||||
|
run: matches.opt_str("run"),
|
||||||
test_args: matches.opt_strs("test-args"),
|
test_args: matches.opt_strs("test-args"),
|
||||||
rustc_args: matches.opt_strs("rustc-args"),
|
rustc_args: matches.opt_strs("rustc-args"),
|
||||||
fail_fast: !matches.opt_present("no-fail-fast"),
|
fail_fast: !matches.opt_present("no-fail-fast"),
|
||||||
@ -742,6 +745,13 @@ impl Subcommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run(&self) -> Option<&str> {
|
||||||
|
match *self {
|
||||||
|
Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn open(&self) -> bool {
|
pub fn open(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Subcommand::Doc { open, .. } => open,
|
Subcommand::Doc { open, .. } => open,
|
||||||
|
@ -1240,6 +1240,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the
|
|||||||
cmd.arg(pass);
|
cmd.arg(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref run) = builder.config.cmd.run() {
|
||||||
|
cmd.arg("--run");
|
||||||
|
cmd.arg(run);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ref nodejs) = builder.config.nodejs {
|
if let Some(ref nodejs) = builder.config.nodejs {
|
||||||
cmd.arg("--nodejs").arg(nodejs);
|
cmd.arg("--nodejs").arg(nodejs);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ use std::iter::Peekable;
|
|||||||
use rustc_lexer::{LiteralKind, TokenKind};
|
use rustc_lexer::{LiteralKind, TokenKind};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::with_default_session_globals;
|
|
||||||
|
|
||||||
use super::format::Buffer;
|
use super::format::Buffer;
|
||||||
|
|
||||||
@ -238,7 +237,6 @@ impl<'a> Classifier<'a> {
|
|||||||
/// possibly giving it an HTML span with a class specifying what flavor of
|
/// possibly giving it an HTML span with a class specifying what flavor of
|
||||||
/// token is used.
|
/// token is used.
|
||||||
fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
|
fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
|
||||||
with_default_session_globals(|| {
|
|
||||||
loop {
|
loop {
|
||||||
if self
|
if self
|
||||||
.tokens
|
.tokens
|
||||||
@ -259,7 +257,6 @@ impl<'a> Classifier<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Single step of highlighting. This will classify `token`, but maybe also
|
/// Single step of highlighting. This will classify `token`, but maybe also
|
||||||
|
@ -2,6 +2,7 @@ use super::write_code;
|
|||||||
use crate::html::format::Buffer;
|
use crate::html::format::Buffer;
|
||||||
use expect_test::expect_file;
|
use expect_test::expect_file;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
|
use rustc_span::with_default_session_globals;
|
||||||
|
|
||||||
const STYLE: &str = r#"
|
const STYLE: &str = r#"
|
||||||
<style>
|
<style>
|
||||||
@ -17,6 +18,7 @@ const STYLE: &str = r#"
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_html_highlighting() {
|
fn test_html_highlighting() {
|
||||||
|
with_default_session_globals(|| {
|
||||||
let src = include_str!("fixtures/sample.rs");
|
let src = include_str!("fixtures/sample.rs");
|
||||||
let html = {
|
let html = {
|
||||||
let mut out = Buffer::new();
|
let mut out = Buffer::new();
|
||||||
@ -24,14 +26,17 @@ fn test_html_highlighting() {
|
|||||||
format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
|
format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
|
||||||
};
|
};
|
||||||
expect_file!["fixtures/sample.html"].assert_eq(&html);
|
expect_file!["fixtures/sample.html"].assert_eq(&html);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dos_backline() {
|
fn test_dos_backline() {
|
||||||
|
with_default_session_globals(|| {
|
||||||
let src = "pub fn foo() {\r\n\
|
let src = "pub fn foo() {\r\n\
|
||||||
println!(\"foo\");\r\n\
|
println!(\"foo\");\r\n\
|
||||||
}\r\n";
|
}\r\n";
|
||||||
let mut html = Buffer::new();
|
let mut html = Buffer::new();
|
||||||
write_code(&mut html, src, Edition::Edition2018);
|
write_code(&mut html, src, Edition::Edition2018);
|
||||||
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
|
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
// == Test [gdb|lldb]-[command|check] are parsed correctly ===
|
// == Test [gdb|lldb]-[command|check] are parsed correctly ===
|
||||||
// should-fail
|
// should-fail
|
||||||
|
// needs-run-enabled
|
||||||
// compile-flags:-g
|
// compile-flags:-g
|
||||||
|
|
||||||
// === GDB TESTS ===================================================================================
|
// === GDB TESTS ===================================================================================
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
1| |// Enables `no_coverage` on individual functions
|
|
||||||
2| |
|
|
||||||
3| |#[feature(no_coverage)]
|
|
||||||
4| |#[no_coverage]
|
|
||||||
5| |fn do_not_add_coverage_1() {
|
|
||||||
6| | println!("called but not covered");
|
|
||||||
7| |}
|
|
||||||
8| |
|
|
||||||
9| |#[no_coverage]
|
|
||||||
10| |#[feature(no_coverage)]
|
|
||||||
11| |fn do_not_add_coverage_2() {
|
|
||||||
12| | println!("called but not covered");
|
|
||||||
13| |}
|
|
||||||
14| |
|
|
||||||
15| 1|fn main() {
|
|
||||||
16| 1| do_not_add_coverage_1();
|
|
||||||
17| 1| do_not_add_coverage_2();
|
|
||||||
18| 1|}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
// Enables `no_coverage` on individual functions
|
|
||||||
|
|
||||||
#[feature(no_coverage)]
|
|
||||||
#[no_coverage]
|
|
||||||
fn do_not_add_coverage_1() {
|
|
||||||
println!("called but not covered");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_coverage]
|
|
||||||
#[feature(no_coverage)]
|
|
||||||
fn do_not_add_coverage_2() {
|
|
||||||
println!("called but not covered");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
do_not_add_coverage_1();
|
|
||||||
do_not_add_coverage_2();
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
// build-pass
|
// build-pass
|
||||||
// compile-flags: -C panic=unwind
|
// compile-flags: -C panic=unwind
|
||||||
|
// needs-unwind
|
||||||
// ignore-emscripten no panic_unwind implementation
|
// ignore-emscripten no panic_unwind implementation
|
||||||
// ignore-wasm32 no panic_unwind implementation
|
// ignore-wasm32 no panic_unwind implementation
|
||||||
// ignore-wasm64 no panic_unwind implementation
|
// ignore-wasm64 no panic_unwind implementation
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#[no_coverage]
|
#[derive(PartialEq, Eq)] // ensure deriving `Eq` does not enable `feature(no_coverage)`
|
||||||
#[feature(no_coverage)] // does not have to be enabled before `#[no_coverage]`
|
struct Foo {
|
||||||
fn no_coverage_is_enabled_on_this_function() {}
|
a: u8,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
|
#[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
|
||||||
fn requires_feature_no_coverage() {}
|
fn requires_feature_no_coverage() -> bool {
|
||||||
|
let bar = Foo { a: 0, b: 0 };
|
||||||
|
bar == Foo { a: 0, b: 0 }
|
||||||
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
error[E0658]: the `#[no_coverage]` attribute is an experimental feature
|
error[E0658]: the `#[no_coverage]` attribute is an experimental feature
|
||||||
--> $DIR/feature-gate-no_coverage.rs:7:1
|
--> $DIR/feature-gate-no_coverage.rs:9:1
|
||||||
|
|
|
|
||||||
LL | #[no_coverage]
|
LL | #[no_coverage]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
|
= note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
|
||||||
= help: add `#![feature(no_coverage)]` to the crate attributes to enable
|
= help: add `#![feature(no_coverage)]` to the crate attributes to enable
|
||||||
= help: or, alternatively, add `#[feature(no_coverage)]` to the function
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ mod rusti {
|
|||||||
target_os = "dragonfly",
|
target_os = "dragonfly",
|
||||||
target_os = "emscripten",
|
target_os = "emscripten",
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "macos",
|
target_os = "macos",
|
||||||
target_os = "netbsd",
|
target_os = "netbsd",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// run-pass
|
// run-pass
|
||||||
// compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
|
// compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
|
||||||
// ignore-windows - this will probably only work on unixish systems
|
// ignore-windows - this will probably only work on unixish systems
|
||||||
|
// ignore-fuchsia - missing __libc_start_main for some reason (#84733)
|
||||||
|
|
||||||
#[link(name = "some-random-non-existent-library", kind = "static")]
|
#[link(name = "some-random-non-existent-library", kind = "static")]
|
||||||
extern "C" {}
|
extern "C" {}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
// run-fail
|
// run-fail
|
||||||
// revisions: foo bar
|
// revisions: foo bar
|
||||||
// should-fail
|
// should-fail
|
||||||
|
// needs-run-enabled
|
||||||
//[foo] error-pattern:bar
|
//[foo] error-pattern:bar
|
||||||
//[bar] error-pattern:foo
|
//[bar] error-pattern:foo
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// aux-build:weak-lang-items.rs
|
// aux-build:weak-lang-items.rs
|
||||||
// error-pattern: `#[panic_handler]` function required, but not found
|
// error-pattern: `#[panic_handler]` function required, but not found
|
||||||
// error-pattern: language item required, but not found: `eh_personality`
|
// error-pattern: language item required, but not found: `eh_personality`
|
||||||
|
// needs-unwind since it affects the error output
|
||||||
// ignore-emscripten compiled with panic=abort, personality not required
|
// ignore-emscripten compiled with panic=abort, personality not required
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0259]: the name `core` is defined multiple times
|
error[E0259]: the name `core` is defined multiple times
|
||||||
--> $DIR/weak-lang-item.rs:8:1
|
--> $DIR/weak-lang-item.rs:9:1
|
||||||
|
|
|
|
||||||
LL | extern crate core;
|
LL | extern crate core;
|
||||||
| ^^^^^^^^^^^^^^^^^^ `core` reimported here
|
| ^^^^^^^^^^^^^^^^^^ `core` reimported here
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// build-fail
|
// build-fail
|
||||||
// compile-flags:-C panic=abort -C prefer-dynamic
|
// compile-flags:-C panic=abort -C prefer-dynamic
|
||||||
|
// needs-unwind
|
||||||
// ignore-musl - no dylibs here
|
// ignore-musl - no dylibs here
|
||||||
// ignore-emscripten
|
// ignore-emscripten
|
||||||
// ignore-sgx no dynamic lib support
|
// ignore-sgx no dynamic lib support
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
// compile-flags:-C lto -C panic=unwind
|
// compile-flags:-C lto -C panic=unwind
|
||||||
|
// needs-unwind
|
||||||
// no-prefer-dynamic
|
// no-prefer-dynamic
|
||||||
// ignore-emscripten no processes
|
// ignore-emscripten no processes
|
||||||
// ignore-sgx no processes
|
// ignore-sgx no processes
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// build-fail
|
// build-fail
|
||||||
|
// needs-unwind
|
||||||
// aux-build:panic-runtime-unwind.rs
|
// aux-build:panic-runtime-unwind.rs
|
||||||
// aux-build:panic-runtime-abort.rs
|
// aux-build:panic-runtime-abort.rs
|
||||||
// aux-build:wants-panic-runtime-unwind.rs
|
// aux-build:wants-panic-runtime-unwind.rs
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// build-fail
|
// build-fail
|
||||||
|
// needs-unwind
|
||||||
// error-pattern:is incompatible with this crate's strategy of `unwind`
|
// error-pattern:is incompatible with this crate's strategy of `unwind`
|
||||||
// aux-build:panic-runtime-abort.rs
|
// aux-build:panic-runtime-abort.rs
|
||||||
// aux-build:panic-runtime-lang-items.rs
|
// aux-build:panic-runtime-lang-items.rs
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// build-fail
|
// build-fail
|
||||||
|
// needs-unwind
|
||||||
// error-pattern:is incompatible with this crate's strategy of `unwind`
|
// error-pattern:is incompatible with this crate's strategy of `unwind`
|
||||||
// aux-build:panic-runtime-abort.rs
|
// aux-build:panic-runtime-abort.rs
|
||||||
// aux-build:wants-panic-runtime-abort.rs
|
// aux-build:wants-panic-runtime-abort.rs
|
||||||
|
17
src/test/ui/parser/trait-object-delimiters.rs
Normal file
17
src/test/ui/parser/trait-object-delimiters.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// edition:2018
|
||||||
|
|
||||||
|
fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
|
||||||
|
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||||
|
|
||||||
|
fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
|
||||||
|
|
||||||
|
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
|
||||||
|
//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
|
||||||
|
//~| ERROR at least one trait is required for an object type
|
||||||
|
|
||||||
|
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
|
||||||
|
|
||||||
|
fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} //~ ERROR invalid `dyn` keyword
|
||||||
|
//~^ ERROR only auto traits can be used as additional traits in a trait object
|
||||||
|
|
||||||
|
fn main() {}
|
77
src/test/ui/parser/trait-object-delimiters.stderr
Normal file
77
src/test/ui/parser/trait-object-delimiters.stderr
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
error: ambiguous `+` in a type
|
||||||
|
--> $DIR/trait-object-delimiters.rs:3:13
|
||||||
|
|
|
||||||
|
LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)`
|
||||||
|
|
||||||
|
error: incorrect braces around trait bounds
|
||||||
|
--> $DIR/trait-object-delimiters.rs:6:17
|
||||||
|
|
|
||||||
|
LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove the parentheses
|
||||||
|
|
|
||||||
|
LL | fn foo2(_: &dyn Drop + AsRef<str>) {}
|
||||||
|
| -- --
|
||||||
|
|
||||||
|
error: expected parameter name, found `{`
|
||||||
|
--> $DIR/trait-object-delimiters.rs:8:17
|
||||||
|
|
|
||||||
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
||||||
|
| ^ expected parameter name
|
||||||
|
|
||||||
|
error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
|
||||||
|
--> $DIR/trait-object-delimiters.rs:8:17
|
||||||
|
|
|
||||||
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
||||||
|
| -^ expected one of 8 possible tokens
|
||||||
|
| |
|
||||||
|
| help: missing `,`
|
||||||
|
|
||||||
|
error: expected identifier, found `<`
|
||||||
|
--> $DIR/trait-object-delimiters.rs:12:17
|
||||||
|
|
|
||||||
|
LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
|
||||||
|
| ^ expected identifier
|
||||||
|
|
||||||
|
error: invalid `dyn` keyword
|
||||||
|
--> $DIR/trait-object-delimiters.rs:14:25
|
||||||
|
|
|
||||||
|
LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
|
||||||
|
| ^^^ help: remove this keyword
|
||||||
|
|
|
||||||
|
= help: `dyn` is only needed at the start of a trait `+`-separated list
|
||||||
|
|
||||||
|
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||||
|
--> $DIR/trait-object-delimiters.rs:3:24
|
||||||
|
|
|
||||||
|
LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
|
||||||
|
| ---- ^^^^^^^^^^ additional non-auto trait
|
||||||
|
| |
|
||||||
|
| first non-auto trait
|
||||||
|
|
|
||||||
|
= help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
|
||||||
|
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||||
|
|
||||||
|
error[E0224]: at least one trait is required for an object type
|
||||||
|
--> $DIR/trait-object-delimiters.rs:8:13
|
||||||
|
|
|
||||||
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||||
|
--> $DIR/trait-object-delimiters.rs:14:29
|
||||||
|
|
|
||||||
|
LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
|
||||||
|
| ---- ^^^^^^^^^^ additional non-auto trait
|
||||||
|
| |
|
||||||
|
| first non-auto trait
|
||||||
|
|
|
||||||
|
= help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
|
||||||
|
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0224, E0225.
|
||||||
|
For more information about an error, try `rustc --explain E0224`.
|
@ -35,6 +35,7 @@ struct Outer {
|
|||||||
target_os = "dragonfly",
|
target_os = "dragonfly",
|
||||||
target_os = "emscripten",
|
target_os = "emscripten",
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "macos",
|
target_os = "macos",
|
||||||
target_os = "netbsd",
|
target_os = "netbsd",
|
||||||
|
23
src/test/ui/suggestions/unsized-function-parameter.fixed
Normal file
23
src/test/ui/suggestions/unsized-function-parameter.fixed
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_variables)]
|
||||||
|
|
||||||
|
fn foo1(bar: &str) {}
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
//~| HELP the trait `Sized` is not implemented for `str`
|
||||||
|
//~| HELP unsized fn params are gated as an unstable feature
|
||||||
|
//~| HELP function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
||||||
|
fn foo2(_bar: &str) {}
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
//~| HELP the trait `Sized` is not implemented for `str`
|
||||||
|
//~| HELP unsized fn params are gated as an unstable feature
|
||||||
|
//~| HELP function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
||||||
|
fn foo3(_: &str) {}
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
//~| HELP the trait `Sized` is not implemented for `str`
|
||||||
|
//~| HELP unsized fn params are gated as an unstable feature
|
||||||
|
//~| HELP function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
||||||
|
fn main() {}
|
23
src/test/ui/suggestions/unsized-function-parameter.rs
Normal file
23
src/test/ui/suggestions/unsized-function-parameter.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(dead_code, unused_variables)]
|
||||||
|
|
||||||
|
fn foo1(bar: str) {}
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
//~| HELP the trait `Sized` is not implemented for `str`
|
||||||
|
//~| HELP unsized fn params are gated as an unstable feature
|
||||||
|
//~| HELP function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
||||||
|
fn foo2(_bar: str) {}
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
//~| HELP the trait `Sized` is not implemented for `str`
|
||||||
|
//~| HELP unsized fn params are gated as an unstable feature
|
||||||
|
//~| HELP function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
||||||
|
fn foo3(_: str) {}
|
||||||
|
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||||
|
//~| HELP the trait `Sized` is not implemented for `str`
|
||||||
|
//~| HELP unsized fn params are gated as an unstable feature
|
||||||
|
//~| HELP function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
||||||
|
fn main() {}
|
42
src/test/ui/suggestions/unsized-function-parameter.stderr
Normal file
42
src/test/ui/suggestions/unsized-function-parameter.stderr
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-function-parameter.rs:5:9
|
||||||
|
|
|
||||||
|
LL | fn foo1(bar: str) {}
|
||||||
|
| ^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `str`
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo1(bar: &str) {}
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-function-parameter.rs:11:9
|
||||||
|
|
|
||||||
|
LL | fn foo2(_bar: str) {}
|
||||||
|
| ^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `str`
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo2(_bar: &str) {}
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||||
|
--> $DIR/unsized-function-parameter.rs:17:9
|
||||||
|
|
|
||||||
|
LL | fn foo3(_: str) {}
|
||||||
|
| ^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `str`
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn foo3(_: &str) {}
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -1,6 +1,6 @@
|
|||||||
// error-pattern:building tests with panic=abort is not supported
|
// error-pattern:building tests with panic=abort is not supported
|
||||||
// no-prefer-dynamic
|
// no-prefer-dynamic
|
||||||
// compile-flags: --test -Cpanic=abort
|
// compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no
|
||||||
// run-flags: --test-threads=1
|
// run-flags: --test-threads=1
|
||||||
|
|
||||||
// ignore-wasm no panic or subprocess support
|
// ignore-wasm no panic or subprocess support
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// run-pass
|
// run-pass
|
||||||
|
// needs-unwind
|
||||||
// ignore-windows target requires uwtable
|
// ignore-windows target requires uwtable
|
||||||
// ignore-wasm32-bare no proper panic=unwind support
|
// ignore-wasm32-bare no proper panic=unwind support
|
||||||
// compile-flags: -C panic=unwind -C force-unwind-tables=n
|
// compile-flags: -C panic=unwind -C force-unwind-tables=n
|
||||||
|
@ -27,6 +27,7 @@ pub fn main() {
|
|||||||
target_os = "dragonfly",
|
target_os = "dragonfly",
|
||||||
target_os = "emscripten",
|
target_os = "emscripten",
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "macos",
|
target_os = "macos",
|
||||||
target_os = "netbsd",
|
target_os = "netbsd",
|
||||||
|
@ -171,6 +171,12 @@ impl fmt::Display for Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum PanicStrategy {
|
||||||
|
Unwind,
|
||||||
|
Abort,
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration for compiletest
|
/// Configuration for compiletest
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -249,6 +255,9 @@ pub struct Config {
|
|||||||
/// Force the pass mode of a check/build/run-pass test to this mode.
|
/// Force the pass mode of a check/build/run-pass test to this mode.
|
||||||
pub force_pass_mode: Option<PassMode>,
|
pub force_pass_mode: Option<PassMode>,
|
||||||
|
|
||||||
|
/// Explicitly enable or disable running.
|
||||||
|
pub run: Option<bool>,
|
||||||
|
|
||||||
/// Write out a parseable log of tests that were run
|
/// Write out a parseable log of tests that were run
|
||||||
pub logfile: Option<PathBuf>,
|
pub logfile: Option<PathBuf>,
|
||||||
|
|
||||||
@ -262,6 +271,10 @@ pub struct Config {
|
|||||||
/// Flags to pass to the compiler when building for the target
|
/// Flags to pass to the compiler when building for the target
|
||||||
pub target_rustcflags: Option<String>,
|
pub target_rustcflags: Option<String>,
|
||||||
|
|
||||||
|
/// What panic strategy the target is built with. Unwind supports Abort, but
|
||||||
|
/// not vice versa.
|
||||||
|
pub target_panic: PanicStrategy,
|
||||||
|
|
||||||
/// Target system to be tested
|
/// Target system to be tested
|
||||||
pub target: String,
|
pub target: String,
|
||||||
|
|
||||||
@ -348,6 +361,15 @@ pub struct Config {
|
|||||||
pub npm: Option<String>,
|
pub npm: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn run_enabled(&self) -> bool {
|
||||||
|
self.run.unwrap_or_else(|| {
|
||||||
|
// Auto-detect whether to run based on the platform.
|
||||||
|
!self.target.ends_with("-fuchsia")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TestPaths {
|
pub struct TestPaths {
|
||||||
pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs
|
pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs
|
||||||
|
@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
|
|
||||||
use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode};
|
use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PanicStrategy, PassMode};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::{extract_cdb_version, extract_gdb_version};
|
use crate::{extract_cdb_version, extract_gdb_version};
|
||||||
|
|
||||||
@ -85,6 +85,10 @@ impl EarlyProps {
|
|||||||
props.ignore = true;
|
props.ignore = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled") {
|
||||||
|
props.ignore = true;
|
||||||
|
}
|
||||||
|
|
||||||
if !rustc_has_sanitizer_support
|
if !rustc_has_sanitizer_support
|
||||||
&& config.parse_name_directive(ln, "needs-sanitizer-support")
|
&& config.parse_name_directive(ln, "needs-sanitizer-support")
|
||||||
{
|
{
|
||||||
@ -111,6 +115,12 @@ impl EarlyProps {
|
|||||||
props.ignore = true;
|
props.ignore = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.target_panic == PanicStrategy::Abort
|
||||||
|
&& config.parse_name_directive(ln, "needs-unwind")
|
||||||
|
{
|
||||||
|
props.ignore = true;
|
||||||
|
}
|
||||||
|
|
||||||
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
|
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
|
||||||
props.ignore = true;
|
props.ignore = true;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
|
use crate::common::{
|
||||||
|
expected_output_path, output_base_dir, output_relative_path, PanicStrategy, UI_EXTENSIONS,
|
||||||
|
};
|
||||||
use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
|
use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
|
||||||
use crate::util::logv;
|
use crate::util::logv;
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
@ -87,6 +89,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||||||
"force {check,build,run}-pass tests to this mode.",
|
"force {check,build,run}-pass tests to this mode.",
|
||||||
"check | build | run",
|
"check | build | run",
|
||||||
)
|
)
|
||||||
|
.optopt("", "run", "whether to execute run-* tests", "auto | always | never")
|
||||||
.optflag("", "ignored", "run tests marked as ignored")
|
.optflag("", "ignored", "run tests marked as ignored")
|
||||||
.optflag("", "exact", "filters match exactly")
|
.optflag("", "exact", "filters match exactly")
|
||||||
.optopt(
|
.optopt(
|
||||||
@ -96,8 +99,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||||||
(eg. emulator, valgrind)",
|
(eg. emulator, valgrind)",
|
||||||
"PROGRAM",
|
"PROGRAM",
|
||||||
)
|
)
|
||||||
.optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
|
.optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
|
||||||
.optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
|
.optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
|
||||||
|
.optopt("", "target-panic", "what panic strategy the target supports", "unwind | abort")
|
||||||
.optflag("", "verbose", "run tests verbosely, showing all output")
|
.optflag("", "verbose", "run tests verbosely, showing all output")
|
||||||
.optflag(
|
.optflag(
|
||||||
"",
|
"",
|
||||||
@ -234,10 +238,21 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||||||
mode.parse::<PassMode>()
|
mode.parse::<PassMode>()
|
||||||
.unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
|
.unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
|
||||||
}),
|
}),
|
||||||
|
run: matches.opt_str("run").and_then(|mode| match mode.as_str() {
|
||||||
|
"auto" => None,
|
||||||
|
"always" => Some(true),
|
||||||
|
"never" => Some(false),
|
||||||
|
_ => panic!("unknown `--run` option `{}` given", mode),
|
||||||
|
}),
|
||||||
logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
|
logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
|
||||||
runtool: matches.opt_str("runtool"),
|
runtool: matches.opt_str("runtool"),
|
||||||
host_rustcflags: matches.opt_str("host-rustcflags"),
|
host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")),
|
||||||
target_rustcflags: matches.opt_str("target-rustcflags"),
|
target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")),
|
||||||
|
target_panic: match matches.opt_str("target-panic").as_deref() {
|
||||||
|
Some("unwind") | None => PanicStrategy::Unwind,
|
||||||
|
Some("abort") => PanicStrategy::Abort,
|
||||||
|
_ => panic!("unknown `--target-panic` option `{}` given", mode),
|
||||||
|
},
|
||||||
target,
|
target,
|
||||||
host: opt_str2(matches.opt_str("host")),
|
host: opt_str2(matches.opt_str("host")),
|
||||||
cdb,
|
cdb,
|
||||||
|
@ -259,6 +259,7 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
|
|||||||
pub fn compute_stamp_hash(config: &Config) -> String {
|
pub fn compute_stamp_hash(config: &Config) -> String {
|
||||||
let mut hash = DefaultHasher::new();
|
let mut hash = DefaultHasher::new();
|
||||||
config.stage_id.hash(&mut hash);
|
config.stage_id.hash(&mut hash);
|
||||||
|
config.run.hash(&mut hash);
|
||||||
|
|
||||||
match config.debugger {
|
match config.debugger {
|
||||||
Some(Debugger::Cdb) => {
|
Some(Debugger::Cdb) => {
|
||||||
@ -317,6 +318,7 @@ enum TestOutput {
|
|||||||
enum WillExecute {
|
enum WillExecute {
|
||||||
Yes,
|
Yes,
|
||||||
No,
|
No,
|
||||||
|
Disabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should `--emit metadata` be used?
|
/// Should `--emit metadata` be used?
|
||||||
@ -357,14 +359,17 @@ impl<'test> TestCx<'test> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
|
fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
|
||||||
match self.config.mode {
|
let test_should_run = match self.config.mode {
|
||||||
Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => {
|
Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true,
|
||||||
WillExecute::Yes
|
MirOpt if pm == Some(PassMode::Run) => true,
|
||||||
}
|
Ui | MirOpt => false,
|
||||||
MirOpt if pm == Some(PassMode::Run) => WillExecute::Yes,
|
|
||||||
Ui | MirOpt => WillExecute::No,
|
|
||||||
mode => panic!("unimplemented for mode {:?}", mode),
|
mode => panic!("unimplemented for mode {:?}", mode),
|
||||||
|
};
|
||||||
|
if test_should_run { self.run_if_enabled() } else { WillExecute::No }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_if_enabled(&self) -> WillExecute {
|
||||||
|
if self.config.run_enabled() { WillExecute::Yes } else { WillExecute::Disabled }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
|
fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
|
||||||
@ -439,12 +444,17 @@ impl<'test> TestCx<'test> {
|
|||||||
|
|
||||||
fn run_rfail_test(&self) {
|
fn run_rfail_test(&self) {
|
||||||
let pm = self.pass_mode();
|
let pm = self.pass_mode();
|
||||||
let proc_res = self.compile_test(WillExecute::Yes, self.should_emit_metadata(pm));
|
let should_run = self.run_if_enabled();
|
||||||
|
let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm));
|
||||||
|
|
||||||
if !proc_res.status.success() {
|
if !proc_res.status.success() {
|
||||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let WillExecute::Disabled = should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let proc_res = self.exec_compiled_test();
|
let proc_res = self.exec_compiled_test();
|
||||||
|
|
||||||
// The value our Makefile configures valgrind to return on failure
|
// The value our Makefile configures valgrind to return on failure
|
||||||
@ -483,12 +493,17 @@ impl<'test> TestCx<'test> {
|
|||||||
|
|
||||||
fn run_rpass_test(&self) {
|
fn run_rpass_test(&self) {
|
||||||
let emit_metadata = self.should_emit_metadata(self.pass_mode());
|
let emit_metadata = self.should_emit_metadata(self.pass_mode());
|
||||||
let proc_res = self.compile_test(WillExecute::Yes, emit_metadata);
|
let should_run = self.run_if_enabled();
|
||||||
|
let proc_res = self.compile_test(should_run, emit_metadata);
|
||||||
|
|
||||||
if !proc_res.status.success() {
|
if !proc_res.status.success() {
|
||||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let WillExecute::Disabled = should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(#41968): Move this check to tidy?
|
// FIXME(#41968): Move this check to tidy?
|
||||||
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
|
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
|
||||||
assert!(
|
assert!(
|
||||||
@ -510,12 +525,17 @@ impl<'test> TestCx<'test> {
|
|||||||
return self.run_rpass_test();
|
return self.run_rpass_test();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut proc_res = self.compile_test(WillExecute::Yes, EmitMetadata::No);
|
let should_run = self.run_if_enabled();
|
||||||
|
let mut proc_res = self.compile_test(should_run, EmitMetadata::No);
|
||||||
|
|
||||||
if !proc_res.status.success() {
|
if !proc_res.status.success() {
|
||||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let WillExecute::Disabled = should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let mut new_config = self.config.clone();
|
let mut new_config = self.config.clone();
|
||||||
new_config.runtool = new_config.valgrind_path.clone();
|
new_config.runtool = new_config.valgrind_path.clone();
|
||||||
let new_cx = TestCx { config: &new_config, ..*self };
|
let new_cx = TestCx { config: &new_config, ..*self };
|
||||||
@ -732,10 +752,14 @@ impl<'test> TestCx<'test> {
|
|||||||
|
|
||||||
fn run_debuginfo_cdb_test_no_opt(&self) {
|
fn run_debuginfo_cdb_test_no_opt(&self) {
|
||||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||||
let compile_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
|
let should_run = self.run_if_enabled();
|
||||||
|
let compile_result = self.compile_test(should_run, EmitMetadata::No);
|
||||||
if !compile_result.status.success() {
|
if !compile_result.status.success() {
|
||||||
self.fatal_proc_rec("compilation failed!", &compile_result);
|
self.fatal_proc_rec("compilation failed!", &compile_result);
|
||||||
}
|
}
|
||||||
|
if let WillExecute::Disabled = should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let exe_file = self.make_exe_name();
|
let exe_file = self.make_exe_name();
|
||||||
|
|
||||||
@ -826,10 +850,14 @@ impl<'test> TestCx<'test> {
|
|||||||
let mut cmds = commands.join("\n");
|
let mut cmds = commands.join("\n");
|
||||||
|
|
||||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||||
let compiler_run_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
|
let should_run = self.run_if_enabled();
|
||||||
|
let compiler_run_result = self.compile_test(should_run, EmitMetadata::No);
|
||||||
if !compiler_run_result.status.success() {
|
if !compiler_run_result.status.success() {
|
||||||
self.fatal_proc_rec("compilation failed!", &compiler_run_result);
|
self.fatal_proc_rec("compilation failed!", &compiler_run_result);
|
||||||
}
|
}
|
||||||
|
if let WillExecute::Disabled = should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let exe_file = self.make_exe_name();
|
let exe_file = self.make_exe_name();
|
||||||
|
|
||||||
@ -1044,10 +1072,14 @@ impl<'test> TestCx<'test> {
|
|||||||
|
|
||||||
fn run_debuginfo_lldb_test_no_opt(&self) {
|
fn run_debuginfo_lldb_test_no_opt(&self) {
|
||||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||||
let compile_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
|
let should_run = self.run_if_enabled();
|
||||||
|
let compile_result = self.compile_test(should_run, EmitMetadata::No);
|
||||||
if !compile_result.status.success() {
|
if !compile_result.status.success() {
|
||||||
self.fatal_proc_rec("compilation failed!", &compile_result);
|
self.fatal_proc_rec("compilation failed!", &compile_result);
|
||||||
}
|
}
|
||||||
|
if let WillExecute::Disabled = should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let exe_file = self.make_exe_name();
|
let exe_file = self.make_exe_name();
|
||||||
|
|
||||||
@ -1531,7 +1563,9 @@ impl<'test> TestCx<'test> {
|
|||||||
// Only use `make_exe_name` when the test ends up being executed.
|
// Only use `make_exe_name` when the test ends up being executed.
|
||||||
let output_file = match will_execute {
|
let output_file = match will_execute {
|
||||||
WillExecute::Yes => TargetLocation::ThisFile(self.make_exe_name()),
|
WillExecute::Yes => TargetLocation::ThisFile(self.make_exe_name()),
|
||||||
WillExecute::No => TargetLocation::ThisDirectory(self.output_base_dir()),
|
WillExecute::No | WillExecute::Disabled => {
|
||||||
|
TargetLocation::ThisDirectory(self.output_base_dir())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let allow_unused = match self.config.mode {
|
let allow_unused = match self.config.mode {
|
||||||
|
@ -44,12 +44,29 @@ const EXCEPTIONS: &[(&str, &str)] = &[
|
|||||||
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
|
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
|
||||||
|
("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-jit", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("libloading", "ISC"),
|
||||||
|
("mach", "BSD-2-Clause"),
|
||||||
|
("regalloc", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
|
||||||
|
];
|
||||||
|
|
||||||
/// These are the root crates that are part of the runtime. The licenses for
|
/// These are the root crates that are part of the runtime. The licenses for
|
||||||
/// these and all their dependencies *must not* be in the exception list.
|
/// these and all their dependencies *must not* be in the exception list.
|
||||||
const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
|
const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
|
||||||
|
|
||||||
/// Crates whose dependencies must be explicitly permitted.
|
/// Crates whose dependencies must be explicitly permitted.
|
||||||
const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_middle", "rustc_codegen_llvm"];
|
const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_llvm"];
|
||||||
|
|
||||||
/// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
|
/// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
|
||||||
///
|
///
|
||||||
@ -72,7 +89,10 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"chalk-derive",
|
"chalk-derive",
|
||||||
|
"chalk-engine",
|
||||||
"chalk-ir",
|
"chalk-ir",
|
||||||
|
"chalk-solve",
|
||||||
|
"chrono",
|
||||||
"cmake",
|
"cmake",
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"cpuid-bool",
|
"cpuid-bool",
|
||||||
@ -92,6 +112,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"expect-test",
|
"expect-test",
|
||||||
"fake-simd",
|
"fake-simd",
|
||||||
"filetime",
|
"filetime",
|
||||||
|
"fixedbitset",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fortanix-sgx-abi",
|
"fortanix-sgx-abi",
|
||||||
"fuchsia-zircon",
|
"fuchsia-zircon",
|
||||||
@ -107,6 +128,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"indexmap",
|
"indexmap",
|
||||||
"instant",
|
"instant",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"itoa",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"kernel32-sys",
|
"kernel32-sys",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -114,6 +136,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"libz-sys",
|
"libz-sys",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"log",
|
"log",
|
||||||
|
"matchers",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
"md-5",
|
"md-5",
|
||||||
"measureme",
|
"measureme",
|
||||||
@ -123,6 +146,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"memoffset",
|
"memoffset",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
"object",
|
"object",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
@ -130,6 +155,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"perf-event-open-sys",
|
"perf-event-open-sys",
|
||||||
|
"petgraph",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"polonius-engine",
|
"polonius-engine",
|
||||||
@ -147,22 +173,28 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"rand_xorshift",
|
"rand_xorshift",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"regex",
|
"regex",
|
||||||
|
"regex-automata",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
|
"rls-data",
|
||||||
|
"rls-span",
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustc-rayon",
|
"rustc-rayon",
|
||||||
"rustc-rayon-core",
|
"rustc-rayon-core",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
|
"ryu",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"semver",
|
"semver",
|
||||||
"semver-parser",
|
"semver-parser",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
"sha2",
|
"sha2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
"sharded-slab",
|
||||||
"snap",
|
"snap",
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"stacker",
|
"stacker",
|
||||||
@ -172,9 +204,15 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"termcolor",
|
"termcolor",
|
||||||
"termize",
|
"termize",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
|
"time",
|
||||||
|
"tinyvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
|
"tracing-serde",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"tracing-tree",
|
||||||
"typenum",
|
"typenum",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
"unicode-script",
|
"unicode-script",
|
||||||
@ -193,6 +231,59 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
|
|||||||
"yansi-term",
|
"yansi-term",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
|
||||||
|
"anyhow",
|
||||||
|
"ar",
|
||||||
|
"autocfg",
|
||||||
|
"bitflags",
|
||||||
|
"byteorder",
|
||||||
|
"cfg-if",
|
||||||
|
"cranelift-bforest",
|
||||||
|
"cranelift-codegen",
|
||||||
|
"cranelift-codegen-meta",
|
||||||
|
"cranelift-codegen-shared",
|
||||||
|
"cranelift-entity",
|
||||||
|
"cranelift-frontend",
|
||||||
|
"cranelift-jit",
|
||||||
|
"cranelift-module",
|
||||||
|
"cranelift-native",
|
||||||
|
"cranelift-object",
|
||||||
|
"crc32fast",
|
||||||
|
"errno",
|
||||||
|
"errno-dragonfly",
|
||||||
|
"gcc",
|
||||||
|
"gimli",
|
||||||
|
"hashbrown",
|
||||||
|
"indexmap",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
"log",
|
||||||
|
"mach",
|
||||||
|
"object",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regalloc",
|
||||||
|
"region",
|
||||||
|
"rustc-hash",
|
||||||
|
"smallvec",
|
||||||
|
"syn",
|
||||||
|
"target-lexicon",
|
||||||
|
"thiserror",
|
||||||
|
"thiserror-impl",
|
||||||
|
"unicode-xid",
|
||||||
|
"winapi",
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
];
|
||||||
|
|
||||||
|
const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
|
||||||
|
// These two crates take quite a long time to build, so don't allow two versions of them
|
||||||
|
// to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
|
||||||
|
// under control.
|
||||||
|
"cargo",
|
||||||
|
"rustc-ap-rustc_ast",
|
||||||
|
];
|
||||||
|
|
||||||
/// Dependency checks.
|
/// Dependency checks.
|
||||||
///
|
///
|
||||||
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
|
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
|
||||||
@ -203,17 +294,39 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
|||||||
.manifest_path(root.join("Cargo.toml"))
|
.manifest_path(root.join("Cargo.toml"))
|
||||||
.features(cargo_metadata::CargoOpt::AllFeatures);
|
.features(cargo_metadata::CargoOpt::AllFeatures);
|
||||||
let metadata = t!(cmd.exec());
|
let metadata = t!(cmd.exec());
|
||||||
check_exceptions(&metadata, bad);
|
let runtime_ids = compute_runtime_crates(&metadata);
|
||||||
check_dependencies(&metadata, bad);
|
check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
|
||||||
check_crate_duplicate(&metadata, bad);
|
check_dependencies(&metadata, PERMITTED_DEPENDENCIES, RESTRICTED_DEPENDENCY_CRATES, bad);
|
||||||
|
check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad);
|
||||||
|
|
||||||
|
// Check rustc_codegen_cranelift independently as it has it's own workspace.
|
||||||
|
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||||
|
cmd.cargo_path(cargo)
|
||||||
|
.manifest_path(root.join("compiler/rustc_codegen_cranelift/Cargo.toml"))
|
||||||
|
.features(cargo_metadata::CargoOpt::AllFeatures);
|
||||||
|
let metadata = t!(cmd.exec());
|
||||||
|
let runtime_ids = HashSet::new();
|
||||||
|
check_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
|
||||||
|
check_dependencies(
|
||||||
|
&metadata,
|
||||||
|
PERMITTED_CRANELIFT_DEPENDENCIES,
|
||||||
|
&["rustc_codegen_cranelift"],
|
||||||
|
bad,
|
||||||
|
);
|
||||||
|
check_crate_duplicate(&metadata, &[], bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that all licenses are in the valid list in `LICENSES`.
|
/// Check that all licenses are in the valid list in `LICENSES`.
|
||||||
///
|
///
|
||||||
/// Packages listed in `EXCEPTIONS` are allowed for tools.
|
/// Packages listed in `EXCEPTIONS` are allowed for tools.
|
||||||
fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
|
fn check_exceptions(
|
||||||
|
metadata: &Metadata,
|
||||||
|
exceptions: &[(&str, &str)],
|
||||||
|
runtime_ids: HashSet<&PackageId>,
|
||||||
|
bad: &mut bool,
|
||||||
|
) {
|
||||||
// Validate the EXCEPTIONS list hasn't changed.
|
// Validate the EXCEPTIONS list hasn't changed.
|
||||||
for (name, license) in EXCEPTIONS {
|
for (name, license) in exceptions {
|
||||||
// Check that the package actually exists.
|
// Check that the package actually exists.
|
||||||
if !metadata.packages.iter().any(|p| p.name == *name) {
|
if !metadata.packages.iter().any(|p| p.name == *name) {
|
||||||
tidy_error!(
|
tidy_error!(
|
||||||
@ -225,13 +338,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
|
|||||||
}
|
}
|
||||||
// Check that the license hasn't changed.
|
// Check that the license hasn't changed.
|
||||||
for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
|
for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
|
||||||
if pkg.name == "fuchsia-cprng" {
|
|
||||||
// This package doesn't declare a license expression. Manual
|
|
||||||
// inspection of the license file is necessary, which appears
|
|
||||||
// to be BSD-3-Clause.
|
|
||||||
assert!(pkg.license.is_none());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
match &pkg.license {
|
match &pkg.license {
|
||||||
None => {
|
None => {
|
||||||
tidy_error!(
|
tidy_error!(
|
||||||
@ -242,14 +348,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
|
|||||||
}
|
}
|
||||||
Some(pkg_license) => {
|
Some(pkg_license) => {
|
||||||
if pkg_license.as_str() != *license {
|
if pkg_license.as_str() != *license {
|
||||||
if *name == "crossbeam-queue"
|
|
||||||
&& *license == "MIT/Apache-2.0 AND BSD-2-Clause"
|
|
||||||
{
|
|
||||||
// We have two versions of crossbeam-queue and both
|
|
||||||
// are fine.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("dependency exception `{}` license has changed", name);
|
println!("dependency exception `{}` license has changed", name);
|
||||||
println!(" previously `{}` now `{}`", license, pkg_license);
|
println!(" previously `{}` now `{}`", license, pkg_license);
|
||||||
println!(" update EXCEPTIONS for the new license");
|
println!(" update EXCEPTIONS for the new license");
|
||||||
@ -260,8 +358,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let exception_names: Vec<_> = EXCEPTIONS.iter().map(|(name, _license)| *name).collect();
|
let exception_names: Vec<_> = exceptions.iter().map(|(name, _license)| *name).collect();
|
||||||
let runtime_ids = compute_runtime_crates(metadata);
|
|
||||||
|
|
||||||
// Check if any package does not have a valid license.
|
// Check if any package does not have a valid license.
|
||||||
for pkg in &metadata.packages {
|
for pkg in &metadata.packages {
|
||||||
@ -296,9 +393,14 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
|
|||||||
/// `true` if a check failed.
|
/// `true` if a check failed.
|
||||||
///
|
///
|
||||||
/// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`.
|
/// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`.
|
||||||
fn check_dependencies(metadata: &Metadata, bad: &mut bool) {
|
fn check_dependencies(
|
||||||
|
metadata: &Metadata,
|
||||||
|
permitted_dependencies: &[&'static str],
|
||||||
|
restricted_dependency_crates: &[&'static str],
|
||||||
|
bad: &mut bool,
|
||||||
|
) {
|
||||||
// Check that the PERMITTED_DEPENDENCIES does not have unused entries.
|
// Check that the PERMITTED_DEPENDENCIES does not have unused entries.
|
||||||
for name in PERMITTED_DEPENDENCIES {
|
for name in permitted_dependencies {
|
||||||
if !metadata.packages.iter().any(|p| p.name == *name) {
|
if !metadata.packages.iter().any(|p| p.name == *name) {
|
||||||
tidy_error!(
|
tidy_error!(
|
||||||
bad,
|
bad,
|
||||||
@ -309,12 +411,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get the list in a convenient form.
|
// Get the list in a convenient form.
|
||||||
let permitted_dependencies: HashSet<_> = PERMITTED_DEPENDENCIES.iter().cloned().collect();
|
let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
|
||||||
|
|
||||||
// Check dependencies.
|
// Check dependencies.
|
||||||
let mut visited = BTreeSet::new();
|
let mut visited = BTreeSet::new();
|
||||||
let mut unapproved = BTreeSet::new();
|
let mut unapproved = BTreeSet::new();
|
||||||
for &krate in RESTRICTED_DEPENDENCY_CRATES.iter() {
|
for &krate in restricted_dependency_crates.iter() {
|
||||||
let pkg = pkg_from_name(metadata, krate);
|
let pkg = pkg_from_name(metadata, krate);
|
||||||
let mut bad =
|
let mut bad =
|
||||||
check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
|
check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
|
||||||
@ -367,16 +469,12 @@ fn check_crate_dependencies<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prevents multiple versions of some expensive crates.
|
/// Prevents multiple versions of some expensive crates.
|
||||||
fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
|
fn check_crate_duplicate(
|
||||||
const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
|
metadata: &Metadata,
|
||||||
// These two crates take quite a long time to build, so don't allow two versions of them
|
forbidden_to_have_duplicates: &[&str],
|
||||||
// to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
|
bad: &mut bool,
|
||||||
// under control.
|
) {
|
||||||
"cargo",
|
for &name in forbidden_to_have_duplicates {
|
||||||
"rustc-ap-rustc_ast",
|
|
||||||
];
|
|
||||||
|
|
||||||
for &name in FORBIDDEN_TO_HAVE_DUPLICATES {
|
|
||||||
let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
|
let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
|
||||||
match matches.len() {
|
match matches.len() {
|
||||||
0 => {
|
0 => {
|
||||||
@ -456,16 +554,7 @@ fn normal_deps_of_r<'a>(
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|n| &n.id == pkg_id)
|
.find(|n| &n.id == pkg_id)
|
||||||
.unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
|
.unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
|
||||||
// Don't care about dev-dependencies.
|
for dep in &node.deps {
|
||||||
// Build dependencies *shouldn't* matter unless they do some kind of
|
|
||||||
// codegen. For now we'll assume they don't.
|
|
||||||
let deps = node.deps.iter().filter(|node_dep| {
|
|
||||||
node_dep
|
|
||||||
.dep_kinds
|
|
||||||
.iter()
|
|
||||||
.any(|kind_info| kind_info.kind == cargo_metadata::DependencyKind::Normal)
|
|
||||||
});
|
|
||||||
for dep in deps {
|
|
||||||
normal_deps_of_r(resolve, &dep.pkg, result);
|
normal_deps_of_r(resolve, &dep.pkg, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user