diff options
| author | bors <bors@rust-lang.org> | 2021-05-07 01:16:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-05-07 01:16:08 +0000 |
| commit | 1773f14a24c49356b384e45ebb45643bc9bef2c4 (patch) | |
| tree | e6ad409e4410a72f43101974b5a824e15fba28a5 | |
| parent | 777bb2f6129e71a88ba030251eb370ef12fe28af (diff) | |
| parent | 01e9d09d3bbb35a1fbb0a2a353cfcf90a4feb050 (diff) | |
| download | rust-1773f14a24c49356b384e45ebb45643bc9bef2c4.tar.gz rust-1773f14a24c49356b384e45ebb45643bc9bef2c4.zip | |
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
50 files changed, 763 insertions, 258 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 5a4e7fd9d07..54ab88dc3ff 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -15,20 +15,12 @@ pub fn expand_deriving_eq( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { + let span = cx.with_def_site_ctxt(span); 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 doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); - let attrs = vec![ - cx.attribute(inline), - cx.attribute(no_coverage_feature), - cx.attribute(no_coverage), - cx.attribute(doc), - ]; + let no_coverage = cx.meta_word(span, sym::no_coverage); + let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)]; let trait_def = TraitDef { span, attributes: Vec::new(), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5474fea9c78..a8719be84c2 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -273,13 +273,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(List: "address, memory, thread"), experimental!(no_sanitize) ), - ungated!( - // 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), - ), + gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)), // FIXME: #14408 assume docs are used since rustdoc looks at them. ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a91bd9ce2ff..1cafb2fe1a2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2398,9 +2398,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.associated_item(def_id).ident ), infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), - infer::BoundRegionInCoherence(name) => { - format!(" for lifetime parameter `{}` in coherence check", name) - } infer::UpvarRegion(ref upvar_id, _) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); format!(" for capture of `{}` by closure", var_name) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index eaec6b46bcd..f39431f2494 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -453,8 +453,6 @@ pub enum RegionVariableOrigin { UpvarRegion(ty::UpvarId, Span), - BoundRegionInCoherence(Symbol), - /// This origin is used for the inference variables that we create /// during NLL region processing. Nll(NllRegionVariableOrigin), @@ -1749,7 +1747,6 @@ impl RegionVariableOrigin { | EarlyBoundRegion(a, ..) | LateBoundRegion(a, ..) | UpvarRegion(_, a) => a, - BoundRegionInCoherence(_) => rustc_span::DUMMY_SP, Nll(..) => bug!("NLL variable used with `span`"), } } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index dea1b113315..292306f6cde 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -323,7 +323,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_scalar(result, dest)?; } 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 => { 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) } + + /// 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(()) + } } diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs index 6084f67abd7..5a10ffe6d61 100644 --- a/compiler/rustc_mir/src/interpret/step.rs +++ b/compiler/rustc_mir/src/interpret/step.rs @@ -2,7 +2,6 @@ //! //! The main entry point is the `step` method. -use crate::interpret::OpTy; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; 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 dst = self.eval_operand(dst, 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. @@ -149,37 +148,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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. /// /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 0f7b8ebd376..d537741c749 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -470,7 +470,7 @@ impl<'a> Parser<'a> { /// Is a `dyn B0 + ... + Bn` type allowed here? fn is_explicit_dyn_type(&mut self) -> bool { self.check_keyword(kw::Dyn) - && (self.token.uninterpolated_span().rust_2018() + && (!self.token.uninterpolated_span().rust_2015() || self.look_ahead(1, |t| { t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t) })) @@ -539,7 +539,21 @@ impl<'a> Parser<'a> { ) -> PResult<'a, GenericBounds> { let mut 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()? { Ok(bound) => bounds.push(bound), 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 path = self.parse_path(PathStyle::Type)?; if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; + 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))?; + 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(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 727285e4927..08d452900c8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1044,8 +1044,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } /// 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 { // If there are any inference variables in the `ParamEnv`, then we // always use a cache local to this particular scope. Otherwise, we diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 190c9d35934..0528f8812f9 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2661,8 +2661,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { let mut inline_span = None; let mut link_ordinal_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() { if tcx.sess.check_name(attr, sym::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; } else if tcx.sess.check_name(attr, sym::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) { - no_coverage_attr = Some(attr); + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } 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| { if !attr.has_name(sym::inline) { return ia; diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0a3e5789e8b..f8b16b6f927 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -274,8 +274,7 @@ pub trait Eq: PartialEq<Self> { // // This should never be implemented by hand. #[doc(hidden)] - #[cfg_attr(not(bootstrap), feature(no_coverage))] - #[cfg_attr(not(bootstrap), no_coverage)] + #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605 #[inline] #[stable(feature = "rust1", since = "1.0.0")] 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`. #[rustc_builtin_macro] #[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) { /* compiler built-in */ } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d7dd7ee02c1..0034de9ad1b 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -723,7 +723,7 @@ extern "rust-intrinsic" { /// macro, which panics when it is executed, it is *undefined behavior* to /// 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")] pub fn unreachable() -> !; @@ -768,13 +768,13 @@ extern "rust-intrinsic" { /// More specifically, this is the offset in bytes between successive /// 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")] pub fn size_of<T>() -> usize; /// 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")] pub fn min_align_of<T>() -> usize; /// The preferred alignment of a type. @@ -790,13 +790,13 @@ extern "rust-intrinsic" { pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; /// 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")] pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; /// 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")] 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 /// 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")] 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. /// - /// 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")] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -1158,11 +1158,11 @@ extern "rust-intrinsic" { /// 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; /// 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); /// 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'; /// 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")] pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0e2c140c367..07bf47b9c6f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -166,9 +166,14 @@ #![feature(const_caller_location)] #![feature(slice_ptr_get)] #![feature(no_niche)] // rust-lang/rust#68303 +#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605 #![feature(int_error_matching)] #![deny(unsafe_op_in_unsafe_fn)] +// allow using `core::` in intra-doc links +#[allow(unused_extern_crates)] +extern crate self as core; + #[prelude_import] #[allow(unused)] use prelude::v1::*; diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs index a5e45303476..f9536c4203d 100644 --- a/library/std/src/sys/sgx/abi/mod.rs +++ b/library/std/src/sys/sgx/abi/mod.rs @@ -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 { // FIXME: how to support TLS in library mode? let tls = Box::new(tls::Tls::new()); - let _tls_guard = unsafe { tls.activate() }; + let tls_guard = unsafe { tls.activate() }; if secondary { - super::thread::Thread::entry(); + let join_notifier = super::thread::Thread::entry(); + drop(tls_guard); + drop(join_notifier); EntryReturn(0, 0) } else { diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index 55ef460cc90..67e2e8b59d3 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -9,26 +9,37 @@ pub struct Thread(task_queue::JoinHandle); pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub use self::task_queue::JoinNotifier; + mod task_queue { - use crate::sync::mpsc; + use super::wait_notify; 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 { p: Box<dyn FnOnce()>, - done: mpsc::Sender<()>, + done: JoinNotifier, } impl Task { 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) } - pub(super) fn run(self) { + pub(super) fn run(self) -> JoinNotifier { (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 { // unsafe: see thread::Builder::spawn_unchecked for safety requirements pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { @@ -57,7 +110,7 @@ impl Thread { Ok(Thread(handle)) } - pub(super) fn entry() { + pub(super) fn entry() -> JoinNotifier { let mut pending_tasks = task_queue::lock(); let task = rtunwrap!(Some, pending_tasks.pop()); 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) { - let _ = self.0.recv(); + self.0.wait(); } } diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs index 80e6798d847..f33d6129619 100644 --- a/library/std/src/thread/local/tests.rs +++ b/library/std/src/thread/local/tests.rs @@ -1,4 +1,5 @@ use crate::cell::{Cell, UnsafeCell}; +use crate::sync::atomic::{AtomicU8, Ordering}; use crate::sync::mpsc::{channel, Sender}; use crate::thread::{self, LocalKey}; use crate::thread_local; @@ -207,3 +208,110 @@ fn dtors_in_dtors_in_dtors_const_init() { }); 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(); + } +} diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index a881512e988..4d7c207e3ab 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -489,6 +489,7 @@ mod dist { compare_mode: None, rustfix_coverage: false, pass: None, + run: None, }; let build = Build::new(config); @@ -529,6 +530,7 @@ mod dist { compare_mode: None, rustfix_coverage: false, pass: None, + run: None, }; let build = Build::new(config); @@ -584,6 +586,7 @@ mod dist { compare_mode: None, rustfix_coverage: false, pass: None, + run: None, }; // Make sure rustfmt binary not being found isn't an error. config.channel = "beta".to_string(); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 6044899c237..d961e067db3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -103,6 +103,7 @@ pub enum Subcommand { bless: bool, compare_mode: Option<String>, pass: Option<String>, + run: Option<String>, test_args: Vec<String>, rustc_args: Vec<String>, 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", ); - opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT"); - opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT"); + opts.optopt("", "rust-profile-generate", "generate PGO profile with rustc build", "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 // 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.", "check | build | run", ); + opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never"); opts.optflag( "", "rustfix-coverage", @@ -556,6 +558,7 @@ Arguments: bless: matches.opt_present("bless"), compare_mode: matches.opt_str("compare-mode"), pass: matches.opt_str("pass"), + run: matches.opt_str("run"), test_args: matches.opt_strs("test-args"), rustc_args: matches.opt_strs("rustc-args"), 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 { match *self { Subcommand::Doc { open, .. } => open, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index db443756de3..fbce2f03da0 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -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); } + if let Some(ref run) = builder.config.cmd.run() { + cmd.arg("--run"); + cmd.arg(run); + } + if let Some(ref nodejs) = builder.config.nodejs { cmd.arg("--nodejs").arg(nodejs); } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 7130a6bc1e8..f631f627fc2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -13,7 +13,6 @@ use std::iter::Peekable; use rustc_lexer::{LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; -use rustc_span::with_default_session_globals; use super::format::Buffer; @@ -238,28 +237,26 @@ impl<'a> Classifier<'a> { /// possibly giving it an HTML span with a class specifying what flavor of /// token is used. fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) { - with_default_session_globals(|| { - loop { - if self - .tokens - .peek() - .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident)) - .unwrap_or(false) - { - let tokens = self.get_full_ident_path(); - for (token, start, end) in tokens { - let text = &self.src[start..end]; - self.advance(token, text, sink); - self.byte_pos += text.len() as u32; - } - } - if let Some((token, text)) = self.next() { + loop { + if self + .tokens + .peek() + .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident)) + .unwrap_or(false) + { + let tokens = self.get_full_ident_path(); + for (token, start, end) in tokens { + let text = &self.src[start..end]; self.advance(token, text, sink); - } else { - break; + self.byte_pos += text.len() as u32; } } - }) + if let Some((token, text)) = self.next() { + self.advance(token, text, sink); + } else { + break; + } + } } /// Single step of highlighting. This will classify `token`, but maybe also diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 305cf61091d..a0da2c963d1 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -2,6 +2,7 @@ use super::write_code; use crate::html::format::Buffer; use expect_test::expect_file; use rustc_span::edition::Edition; +use rustc_span::with_default_session_globals; const STYLE: &str = r#" <style> @@ -17,21 +18,25 @@ const STYLE: &str = r#" #[test] fn test_html_highlighting() { - let src = include_str!("fixtures/sample.rs"); - let html = { - let mut out = Buffer::new(); - write_code(&mut out, src, Edition::Edition2018); - format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner()) - }; - expect_file!["fixtures/sample.html"].assert_eq(&html); + with_default_session_globals(|| { + let src = include_str!("fixtures/sample.rs"); + let html = { + let mut out = Buffer::new(); + write_code(&mut out, src, Edition::Edition2018); + format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner()) + }; + expect_file!["fixtures/sample.html"].assert_eq(&html); + }); } #[test] fn test_dos_backline() { - let src = "pub fn foo() {\r\n\ + with_default_session_globals(|| { + let src = "pub fn foo() {\r\n\ println!(\"foo\");\r\n\ }\r\n"; - let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018); - expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner()); + let mut html = Buffer::new(); + write_code(&mut html, src, Edition::Edition2018); + expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner()); + }); } diff --git a/src/test/debuginfo/should-fail.rs b/src/test/debuginfo/should-fail.rs index 1e0d22cbce4..eef6d99d2a9 100644 --- a/src/test/debuginfo/should-fail.rs +++ b/src/test/debuginfo/should-fail.rs @@ -2,6 +2,7 @@ // == Test [gdb|lldb]-[command|check] are parsed correctly === // should-fail +// needs-run-enabled // compile-flags:-g // === GDB TESTS =================================================================================== diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt deleted file mode 100644 index 16eaf7c858c..00000000000 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt +++ /dev/null @@ -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|} - diff --git a/src/test/run-make-fulldeps/coverage/no_cov_func.rs b/src/test/run-make-fulldeps/coverage/no_cov_func.rs deleted file mode 100644 index e19a2c4a872..00000000000 --- a/src/test/run-make-fulldeps/coverage/no_cov_func.rs +++ /dev/null @@ -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(); -} diff --git a/src/test/ui/cfg/cfg-panic.rs b/src/test/ui/cfg/cfg-panic.rs index dbb5932a9bb..d2113e4f5ec 100644 --- a/src/test/ui/cfg/cfg-panic.rs +++ b/src/test/ui/cfg/cfg-panic.rs @@ -1,5 +1,6 @@ // build-pass // compile-flags: -C panic=unwind +// needs-unwind // ignore-emscripten no panic_unwind implementation // ignore-wasm32 no panic_unwind implementation // ignore-wasm64 no panic_unwind implementation diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.rs b/src/test/ui/feature-gates/feature-gate-no_coverage.rs index c6b79f9a431..fd4c6f76059 100644 --- a/src/test/ui/feature-gates/feature-gate-no_coverage.rs +++ b/src/test/ui/feature-gates/feature-gate-no_coverage.rs @@ -1,8 +1,13 @@ #![crate_type = "lib"] -#[no_coverage] -#[feature(no_coverage)] // does not have to be enabled before `#[no_coverage]` -fn no_coverage_is_enabled_on_this_function() {} +#[derive(PartialEq, Eq)] // ensure deriving `Eq` does not enable `feature(no_coverage)` +struct Foo { + a: u8, + b: u32, +} #[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 } +} diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.stderr b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr index 04627be4aaf..f7167e0b771 100644 --- a/src/test/ui/feature-gates/feature-gate-no_coverage.stderr +++ b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr @@ -1,12 +1,11 @@ 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] | ^^^^^^^^^^^^^^ | = 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: or, alternatively, add `#[feature(no_coverage)]` to the function error: aborting due to previous error diff --git a/src/test/ui/intrinsics/intrinsic-alignment.rs b/src/test/ui/intrinsics/intrinsic-alignment.rs index 592409ba89f..5a27ea8783a 100644 --- a/src/test/ui/intrinsics/intrinsic-alignment.rs +++ b/src/test/ui/intrinsics/intrinsic-alignment.rs @@ -14,6 +14,7 @@ mod rusti { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "macos", target_os = "netbsd", diff --git a/src/test/ui/issues/issue-70093.rs b/src/test/ui/issues/issue-70093.rs index 95ab86ebcb1..fbe68fb9379 100644 --- a/src/test/ui/issues/issue-70093.rs +++ b/src/test/ui/issues/issue-70093.rs @@ -1,6 +1,7 @@ // run-pass // compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes // 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")] extern "C" {} diff --git a/src/test/ui/meta/revision-bad.rs b/src/test/ui/meta/revision-bad.rs index 01f1518c1c6..37ddbe99a9f 100644 --- a/src/test/ui/meta/revision-bad.rs +++ b/src/test/ui/meta/revision-bad.rs @@ -4,6 +4,7 @@ // run-fail // revisions: foo bar // should-fail +// needs-run-enabled //[foo] error-pattern:bar //[bar] error-pattern:foo diff --git a/src/test/ui/panic-handler/weak-lang-item.rs b/src/test/ui/panic-handler/weak-lang-item.rs index 3fa3822831b..df31e614cf8 100644 --- a/src/test/ui/panic-handler/weak-lang-item.rs +++ b/src/test/ui/panic-handler/weak-lang-item.rs @@ -1,6 +1,7 @@ // aux-build:weak-lang-items.rs // error-pattern: `#[panic_handler]` function required, but not found // 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 #![no_std] diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr index 68e3e21df3e..1f14b20e451 100644 --- a/src/test/ui/panic-handler/weak-lang-item.stderr +++ b/src/test/ui/panic-handler/weak-lang-item.stderr @@ -1,5 +1,5 @@ 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; | ^^^^^^^^^^^^^^^^^^ `core` reimported here diff --git a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs index f8368ff6900..58a90a592c4 100644 --- a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs +++ b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs @@ -1,5 +1,6 @@ // build-fail // compile-flags:-C panic=abort -C prefer-dynamic +// needs-unwind // ignore-musl - no dylibs here // ignore-emscripten // ignore-sgx no dynamic lib support diff --git a/src/test/ui/panic-runtime/lto-unwind.rs b/src/test/ui/panic-runtime/lto-unwind.rs index 6f39b76526b..24048ebe008 100644 --- a/src/test/ui/panic-runtime/lto-unwind.rs +++ b/src/test/ui/panic-runtime/lto-unwind.rs @@ -2,6 +2,7 @@ #![allow(unused_variables)] // compile-flags:-C lto -C panic=unwind +// needs-unwind // no-prefer-dynamic // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs index 1848c986e36..622535a75af 100644 --- a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs +++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs @@ -1,4 +1,5 @@ // build-fail +// needs-unwind // aux-build:panic-runtime-unwind.rs // aux-build:panic-runtime-abort.rs // aux-build:wants-panic-runtime-unwind.rs diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs index 894a5eb38b8..c48caaf0790 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs +++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs @@ -1,4 +1,5 @@ // build-fail +// needs-unwind // error-pattern:is incompatible with this crate's strategy of `unwind` // aux-build:panic-runtime-abort.rs // aux-build:panic-runtime-lang-items.rs diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs index 5955075bae5..7a2e48e2f10 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs +++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs @@ -1,4 +1,5 @@ // build-fail +// needs-unwind // error-pattern:is incompatible with this crate's strategy of `unwind` // aux-build:panic-runtime-abort.rs // aux-build:wants-panic-runtime-abort.rs diff --git a/src/test/ui/parser/trait-object-delimiters.rs b/src/test/ui/parser/trait-object-delimiters.rs new file mode 100644 index 00000000000..650ab572261 --- /dev/null +++ b/src/test/ui/parser/trait-object-delimiters.rs @@ -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() {} diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr new file mode 100644 index 00000000000..18b1b24122e --- /dev/null +++ b/src/test/ui/parser/trait-object-delimiters.stderr @@ -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`. diff --git a/src/test/ui/structs-enums/rec-align-u64.rs b/src/test/ui/structs-enums/rec-align-u64.rs index 69544b1c060..cc6412e271a 100644 --- a/src/test/ui/structs-enums/rec-align-u64.rs +++ b/src/test/ui/structs-enums/rec-align-u64.rs @@ -35,6 +35,7 @@ struct Outer { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "macos", target_os = "netbsd", diff --git a/src/test/ui/suggestions/unsized-function-parameter.fixed b/src/test/ui/suggestions/unsized-function-parameter.fixed new file mode 100644 index 00000000000..18e93cb96cd --- /dev/null +++ b/src/test/ui/suggestions/unsized-function-parameter.fixed @@ -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() {} diff --git a/src/test/ui/suggestions/unsized-function-parameter.rs b/src/test/ui/suggestions/unsized-function-parameter.rs new file mode 100644 index 00000000000..344ee71c1bc --- /dev/null +++ b/src/test/ui/suggestions/unsized-function-parameter.rs @@ -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() {} diff --git a/src/test/ui/suggestions/unsized-function-parameter.stderr b/src/test/ui/suggestions/unsized-function-parameter.stderr new file mode 100644 index 00000000000..8cbd8bf3f34 --- /dev/null +++ b/src/test/ui/suggestions/unsized-function-parameter.stderr @@ -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`. diff --git a/src/test/ui/test-panic-abort-disabled.rs b/src/test/ui/test-panic-abort-disabled.rs index 4adb161d9ee..874dbdb42c3 100644 --- a/src/test/ui/test-panic-abort-disabled.rs +++ b/src/test/ui/test-panic-abort-disabled.rs @@ -1,6 +1,6 @@ // error-pattern:building tests with panic=abort is not supported // no-prefer-dynamic -// compile-flags: --test -Cpanic=abort +// compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no // run-flags: --test-threads=1 // ignore-wasm no panic or subprocess support diff --git a/src/test/ui/unwind-no-uwtable.rs b/src/test/ui/unwind-no-uwtable.rs index f249d3f4574..0440cf488e8 100644 --- a/src/test/ui/unwind-no-uwtable.rs +++ b/src/test/ui/unwind-no-uwtable.rs @@ -1,4 +1,5 @@ // run-pass +// needs-unwind // ignore-windows target requires uwtable // ignore-wasm32-bare no proper panic=unwind support // compile-flags: -C panic=unwind -C force-unwind-tables=n diff --git a/src/test/ui/x86stdcall.rs b/src/test/ui/x86stdcall.rs index e1136807b3c..2bf4cfc5003 100644 --- a/src/test/ui/x86stdcall.rs +++ b/src/test/ui/x86stdcall.rs @@ -27,6 +27,7 @@ pub fn main() { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "macos", target_os = "netbsd", diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index b7693a3cb14..408c0b8da0b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -171,6 +171,12 @@ impl fmt::Display for Debugger { } } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PanicStrategy { + Unwind, + Abort, +} + /// Configuration for compiletest #[derive(Debug, Clone)] pub struct Config { @@ -249,6 +255,9 @@ pub struct Config { /// Force the pass mode of a check/build/run-pass test to this mode. 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 pub logfile: Option<PathBuf>, @@ -262,6 +271,10 @@ pub struct Config { /// Flags to pass to the compiler when building for the target 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 pub target: String, @@ -348,6 +361,15 @@ pub struct Config { 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)] pub struct TestPaths { pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f31a24738df..983934d129a 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -7,7 +7,7 @@ use std::path::{Path, PathBuf}; 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::{extract_cdb_version, extract_gdb_version}; @@ -85,6 +85,10 @@ impl EarlyProps { props.ignore = true; } + if !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled") { + props.ignore = true; + } + if !rustc_has_sanitizer_support && config.parse_name_directive(ln, "needs-sanitizer-support") { @@ -111,6 +115,12 @@ impl EarlyProps { 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) { props.ignore = true; } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index d1798a52df7..d53e19f2908 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -5,7 +5,9 @@ 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::util::logv; use getopts::Options; @@ -87,6 +89,7 @@ pub fn parse_config(args: Vec<String>) -> Config { "force {check,build,run}-pass tests to this mode.", "check | build | run", ) + .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") .optflag("", "exact", "filters match exactly") .optopt( @@ -96,8 +99,9 @@ pub fn parse_config(args: Vec<String>) -> Config { (eg. emulator, valgrind)", "PROGRAM", ) - .optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") - .optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "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( "", @@ -234,10 +238,21 @@ pub fn parse_config(args: Vec<String>) -> Config { mode.parse::<PassMode>() .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)), runtool: matches.opt_str("runtool"), - host_rustcflags: matches.opt_str("host-rustcflags"), - target_rustcflags: matches.opt_str("target-rustcflags"), + host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")), + 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, host: opt_str2(matches.opt_str("host")), cdb, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ecbaccf744d..c606aa1dfbf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -259,6 +259,7 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) { pub fn compute_stamp_hash(config: &Config) -> String { let mut hash = DefaultHasher::new(); config.stage_id.hash(&mut hash); + config.run.hash(&mut hash); match config.debugger { Some(Debugger::Cdb) => { @@ -317,6 +318,7 @@ enum TestOutput { enum WillExecute { Yes, No, + Disabled, } /// Should `--emit metadata` be used? @@ -357,14 +359,17 @@ impl<'test> TestCx<'test> { } fn should_run(&self, pm: Option<PassMode>) -> WillExecute { - match self.config.mode { - Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => { - WillExecute::Yes - } - MirOpt if pm == Some(PassMode::Run) => WillExecute::Yes, - Ui | MirOpt => WillExecute::No, + let test_should_run = match self.config.mode { + Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true, + MirOpt if pm == Some(PassMode::Run) => true, + Ui | MirOpt => false, 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 { @@ -439,12 +444,17 @@ impl<'test> TestCx<'test> { fn run_rfail_test(&self) { 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() { self.fatal_proc_rec("compilation failed!", &proc_res); } + if let WillExecute::Disabled = should_run { + return; + } + let proc_res = self.exec_compiled_test(); // The value our Makefile configures valgrind to return on failure @@ -483,12 +493,17 @@ impl<'test> TestCx<'test> { fn run_rpass_test(&self) { 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() { self.fatal_proc_rec("compilation failed!", &proc_res); } + if let WillExecute::Disabled = should_run { + return; + } + // FIXME(#41968): Move this check to tidy? let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); assert!( @@ -510,12 +525,17 @@ impl<'test> TestCx<'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() { self.fatal_proc_rec("compilation failed!", &proc_res); } + if let WillExecute::Disabled = should_run { + return; + } + let mut new_config = self.config.clone(); new_config.runtool = new_config.valgrind_path.clone(); let new_cx = TestCx { config: &new_config, ..*self }; @@ -732,10 +752,14 @@ impl<'test> TestCx<'test> { fn run_debuginfo_cdb_test_no_opt(&self) { // 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() { self.fatal_proc_rec("compilation failed!", &compile_result); } + if let WillExecute::Disabled = should_run { + return; + } let exe_file = self.make_exe_name(); @@ -826,10 +850,14 @@ impl<'test> TestCx<'test> { let mut cmds = commands.join("\n"); // 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() { self.fatal_proc_rec("compilation failed!", &compiler_run_result); } + if let WillExecute::Disabled = should_run { + return; + } let exe_file = self.make_exe_name(); @@ -1044,10 +1072,14 @@ impl<'test> TestCx<'test> { fn run_debuginfo_lldb_test_no_opt(&self) { // 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() { self.fatal_proc_rec("compilation failed!", &compile_result); } + if let WillExecute::Disabled = should_run { + return; + } 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. let output_file = match will_execute { 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 { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b604b39967e..064dd716521 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -44,12 +44,29 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("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 and all their dependencies *must not* be in the exception list. const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; /// 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. /// @@ -72,7 +89,10 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "cc", "cfg-if", "chalk-derive", + "chalk-engine", "chalk-ir", + "chalk-solve", + "chrono", "cmake", "compiler_builtins", "cpuid-bool", @@ -92,6 +112,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "expect-test", "fake-simd", "filetime", + "fixedbitset", "flate2", "fortanix-sgx-abi", "fuchsia-zircon", @@ -107,6 +128,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "indexmap", "instant", "itertools", + "itoa", "jobserver", "kernel32-sys", "lazy_static", @@ -114,6 +136,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "libz-sys", "lock_api", "log", + "matchers", "maybe-uninit", "md-5", "measureme", @@ -123,6 +146,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "memoffset", "miniz_oxide", "num_cpus", + "num-integer", + "num-traits", "object", "once_cell", "opaque-debug", @@ -130,6 +155,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "parking_lot_core", "pathdiff", "perf-event-open-sys", + "petgraph", "pin-project-lite", "pkg-config", "polonius-engine", @@ -147,22 +173,28 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "rand_xorshift", "redox_syscall", "regex", + "regex-automata", "regex-syntax", "remove_dir_all", + "rls-data", + "rls-span", "rustc-demangle", "rustc-hash", "rustc-rayon", "rustc-rayon-core", "rustc_version", + "ryu", "scoped-tls", "scopeguard", "semver", "semver-parser", "serde", "serde_derive", + "serde_json", "sha-1", "sha2", "smallvec", + "sharded-slab", "snap", "stable_deref_trait", "stacker", @@ -172,9 +204,15 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "termcolor", "termize", "thread_local", + "time", + "tinyvec", "tracing", "tracing-attributes", "tracing-core", + "tracing-log", + "tracing-serde", + "tracing-subscriber", + "tracing-tree", "typenum", "unicode-normalization", "unicode-script", @@ -193,6 +231,59 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "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. /// /// `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")) .features(cargo_metadata::CargoOpt::AllFeatures); let metadata = t!(cmd.exec()); - check_exceptions(&metadata, bad); - check_dependencies(&metadata, bad); - check_crate_duplicate(&metadata, bad); + let runtime_ids = compute_runtime_crates(&metadata); + check_exceptions(&metadata, EXCEPTIONS, runtime_ids, 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`. /// /// 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. - for (name, license) in EXCEPTIONS { + for (name, license) in exceptions { // Check that the package actually exists. if !metadata.packages.iter().any(|p| p.name == *name) { tidy_error!( @@ -225,13 +338,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { } // Check that the license hasn't changed. 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 { None => { tidy_error!( @@ -242,14 +348,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { } Some(pkg_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!(" previously `{}` now `{}`", license, pkg_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 runtime_ids = compute_runtime_crates(metadata); + let exception_names: Vec<_> = exceptions.iter().map(|(name, _license)| *name).collect(); // Check if any package does not have a valid license. for pkg in &metadata.packages { @@ -296,9 +393,14 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { /// `true` if a check failed. /// /// 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. - for name in PERMITTED_DEPENDENCIES { + for name in permitted_dependencies { if !metadata.packages.iter().any(|p| p.name == *name) { tidy_error!( bad, @@ -309,12 +411,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { } } // 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. let mut visited = 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 mut bad = 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. -fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { - 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", - ]; - - for &name in FORBIDDEN_TO_HAVE_DUPLICATES { +fn check_crate_duplicate( + metadata: &Metadata, + forbidden_to_have_duplicates: &[&str], + bad: &mut bool, +) { + for &name in forbidden_to_have_duplicates { let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect(); match matches.len() { 0 => { @@ -456,16 +554,7 @@ fn normal_deps_of_r<'a>( .iter() .find(|n| &n.id == pkg_id) .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id)); - // Don't care about dev-dependencies. - // 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 { + for dep in &node.deps { normal_deps_of_r(resolve, &dep.pkg, result); } } |
