From 8ae8bc2808bd3b5e125b72a44bfdcd24353e5211 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Aug 2019 23:06:02 +0100 Subject: [PATCH 01/16] Fix various issues with making items reachable through macros * Allow items to be accessible through private modules and fields when a macro can access them. * Don't mark type-private items as reachable. * Never make items exported/public via macros --- src/librustc_privacy/lib.rs | 190 +++++++++++++++--- .../auxiliary/field-method-macro.rs | 23 +++ .../auxiliary/nested-fn-macro.rs | 11 + .../auxiliary/private-use-macro.rs | 11 + .../ui/definition-reachable/field-method.rs | 11 + src/test/ui/definition-reachable/nested-fn.rs | 11 + .../definition-reachable/private-non-types.rs | 21 ++ .../ui/definition-reachable/private-types.rs | 19 ++ .../ui/definition-reachable/private-use.rs | 10 + 9 files changed, 276 insertions(+), 31 deletions(-) create mode 100644 src/test/ui/definition-reachable/auxiliary/field-method-macro.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs create mode 100644 src/test/ui/definition-reachable/auxiliary/private-use-macro.rs create mode 100644 src/test/ui/definition-reachable/field-method.rs create mode 100644 src/test/ui/definition-reachable/nested-fn.rs create mode 100644 src/test/ui/definition-reachable/private-non-types.rs create mode 100644 src/test/ui/definition-reachable/private-types.rs create mode 100644 src/test/ui/definition-reachable/private-use.rs diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ac18f0e440b78..330370e3803dd 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -229,6 +229,13 @@ fn def_id_visibility<'tcx>( let vis = match tcx.hir().get(hir_id) { Node::Item(item) => &item.vis, Node::ForeignItem(foreign_item) => &foreign_item.vis, + Node::MacroDef(macro_def) => { + if attr::contains_name(¯o_def.attrs, sym::macro_export) { + return (ty::Visibility::Public, macro_def.span, "public"); + } else { + ¯o_def.vis + } + }, Node::TraitItem(..) | Node::Variant(..) => { return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id)); } @@ -433,11 +440,24 @@ impl VisibilityLike for Option { struct EmbargoVisitor<'tcx> { tcx: TyCtxt<'tcx>, - // Accessibility levels for reachable nodes. + /// Accessibility levels for reachable nodes. access_levels: AccessLevels, - // Previous accessibility level; `None` means unreachable. + /// A set of pairs corresponding to modules, where the first module is + /// reachable via a macro that's defined in the second module. This cannot + /// be represented as reachable because it can't handle the following case: + /// + /// pub mod n { // Should be `Public` + /// pub(crate) mod p { // Should *not* be accessible + /// pub fn f() -> i32 { 12 } // Must be `Reachable` + /// } + /// } + /// pub macro m() { + /// n::p::f() + /// } + macro_reachable: FxHashSet<(hir::HirId, DefId)>, + /// Previous accessibility level; `None` means unreachable. prev_level: Option, - // Has something changed in the level map? + /// Has something changed in the level map? changed: bool, } @@ -452,7 +472,7 @@ impl EmbargoVisitor<'tcx> { self.access_levels.map.get(&id).cloned() } - // Updates node level and returns the updated level. + /// Updates node level and returns the updated level. fn update(&mut self, id: hir::HirId, level: Option) -> Option { let old_level = self.get(id); // Accessibility levels can only grow. @@ -477,6 +497,127 @@ impl EmbargoVisitor<'tcx> { } } + /// Updates the item as being reachable through a macro defined in the given + /// module. Returns `true` if the level has changed. + fn update_macro_reachable(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) -> bool { + if self.macro_reachable.insert((reachable_mod, defining_mod)) { + self.update_macro_reachable_mod(reachable_mod, defining_mod); + true + } else { + false + } + } + + fn update_macro_reachable_mod( + &mut self, + reachable_mod: hir::HirId, + defining_mod: DefId, + ) { + let module_def_id = self.tcx.hir().local_def_id(reachable_mod); + let module = self.tcx.hir().get_module(module_def_id).0; + for item_id in &module.item_ids { + let hir_id = item_id.id; + let item_def_id = self.tcx.hir().local_def_id(hir_id); + if let Some(def_kind) = self.tcx.def_kind(item_def_id) { + let item = self.tcx.hir().expect_item(hir_id); + let vis = ty::Visibility::from_hir(&item.vis, hir_id, self.tcx); + self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod); + } + } + + if let Some(exports) = self.tcx.module_exports(module_def_id) { + for export in exports { + if export.vis.is_accessible_from(defining_mod, self.tcx) { + if let Res::Def(def_kind, def_id) = export.res { + let vis = def_id_visibility(self.tcx, def_id).0; + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { + self.update_macro_reachable_def( + hir_id, + def_kind, + vis, + defining_mod, + ); + } + } + } + } + } + } + + fn update_macro_reachable_def( + &mut self, + hir_id: hir::HirId, + def_kind: DefKind, + vis: ty::Visibility, + module: DefId, + ) { + let level = Some(AccessLevel::Reachable); + if let ty::Visibility::Public = vis { + self.update(hir_id, level); + } + match def_kind { + // No type privacy, so can be directly marked as reachable. + DefKind::Const + | DefKind::Macro(_) + | DefKind::Static + | DefKind::TraitAlias + | DefKind::TyAlias => { + if vis.is_accessible_from(module, self.tcx) { + self.update(hir_id, level); + } + }, + + // We can't use a module name as the final segment of a path, except + // in use statements. Since re-export checking doesn't consider + // hygiene these don't need to be marked reachable. The contents of + // the module, however may be reachable. + DefKind::Mod => { + if vis.is_accessible_from(module, self.tcx) { + self.update_macro_reachable(hir_id, module); + } + } + + DefKind::Struct | DefKind::Union => { + // While structs and unions have type privacy, their fields do + // not. + if let ty::Visibility::Public = vis { + let item = self.tcx.hir().expect_item(hir_id); + if let hir::ItemKind::Struct(ref struct_def, _) + | hir::ItemKind::Union(ref struct_def, _) = item.node + { + for field in struct_def.fields() { + let field_vis = ty::Visibility::from_hir( + &field.vis, + field.hir_id, + self.tcx, + ); + if field_vis.is_accessible_from(module, self.tcx) { + self.reach(field.hir_id, level).ty(); + } + } + } else { + bug!("item {:?} with DefKind {:?}", item, def_kind); + } + } + } + + // These have type privacy, so are not reachable unless they're + // public + DefKind::AssocConst + | DefKind::AssocTy + | DefKind::AssocOpaqueTy + | DefKind::ConstParam + | DefKind::Ctor(_, _) + | DefKind::Enum + | DefKind::ForeignTy + | DefKind::Fn + | DefKind::OpaqueTy + | DefKind::Method + | DefKind::Trait + | DefKind::TyParam + | DefKind::Variant => (), + } + } /// Given the path segments of a `ItemKind::Use`, then we need /// to update the visibility of the intermediate use so that it isn't linted @@ -746,40 +887,21 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { return } - let module_did = ty::DefIdTree::parent( + let macro_module_def_id = ty::DefIdTree::parent( self.tcx, self.tcx.hir().local_def_id(md.hir_id) ).unwrap(); - let mut module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap(); + let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap(); let level = if md.vis.node.is_pub() { self.get(module_id) } else { None }; - let level = self.update(md.hir_id, level); - if level.is_none() { + let new_level = self.update(md.hir_id, level); + if new_level.is_none() { return } loop { - let module = if module_id == hir::CRATE_HIR_ID { - &self.tcx.hir().krate().module - } else if let hir::ItemKind::Mod(ref module) = - self.tcx.hir().expect_item(module_id).node { - module - } else { - unreachable!() - }; - for id in &module.item_ids { - self.update(id.id, level); - } - let def_id = self.tcx.hir().local_def_id(module_id); - if let Some(exports) = self.tcx.module_exports(def_id) { - for export in exports.iter() { - if let Some(hir_id) = self.tcx.hir().as_local_hir_id(export.res.def_id()) { - self.update(hir_id, level); - } - } - } - - if module_id == hir::CRATE_HIR_ID { - break + let changed_reachability = self.update_macro_reachable(module_id, macro_module_def_id); + if changed_reachability || module_id == hir::CRATE_HIR_ID { + break; } module_id = self.tcx.hir().get_parent_node(module_id); } @@ -826,7 +948,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.ev.tcx } fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool { if let Some(hir_id) = self.ev.tcx.hir().as_local_hir_id(def_id) { - self.ev.update(hir_id, self.access_level); + if let ((ty::Visibility::Public, ..), _) + | (_, Some(AccessLevel::ReachableFromImplTrait)) + = (def_id_visibility(self.tcx(), def_id), self.access_level) + { + self.ev.update(hir_id, self.access_level); + } } false } @@ -1860,6 +1987,7 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, krate: CrateNum) -> &AccessLevels { let mut visitor = EmbargoVisitor { tcx, access_levels: Default::default(), + macro_reachable: Default::default(), prev_level: Some(AccessLevel::Public), changed: false, }; diff --git a/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs new file mode 100644 index 0000000000000..30ba70bdfeb66 --- /dev/null +++ b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs @@ -0,0 +1,23 @@ +#![feature(decl_macro)] + +mod n { + pub struct B(pub(crate) p::C); + impl B { + pub fn new() -> Self { + B(p::C) + } + } + mod p { + pub struct C; + + impl C { + pub fn foo(&self) -> i32 { + 33 + } + } + } +} + +pub macro m() { + n::B::new().0.foo() +} diff --git a/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs new file mode 100644 index 0000000000000..a39e8c986c391 --- /dev/null +++ b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] + +mod n { + pub(crate) mod p { + pub fn f() -> i32 { 12 } + } +} + +pub macro m() { + n::p::f() +} diff --git a/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs new file mode 100644 index 0000000000000..4f283d9c19c04 --- /dev/null +++ b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs @@ -0,0 +1,11 @@ +#![feature(decl_macro)] + +mod n { + pub static S: i32 = 57; +} + +use n::S; + +pub macro m() { + S +} diff --git a/src/test/ui/definition-reachable/field-method.rs b/src/test/ui/definition-reachable/field-method.rs new file mode 100644 index 0000000000000..60e895a2f9a07 --- /dev/null +++ b/src/test/ui/definition-reachable/field-method.rs @@ -0,0 +1,11 @@ +// Check that functions accessible through a field visible to a macro are +// considered reachable + +// aux-build:nested-fn-macro.rs +// run-pass + +extern crate nested_fn_macro; + +fn main() { + assert_eq!(nested_fn_macro::m!(), 12); +} diff --git a/src/test/ui/definition-reachable/nested-fn.rs b/src/test/ui/definition-reachable/nested-fn.rs new file mode 100644 index 0000000000000..b596ba8936a43 --- /dev/null +++ b/src/test/ui/definition-reachable/nested-fn.rs @@ -0,0 +1,11 @@ +// Check that functions visible to macros through paths with >2 segements are +// considered reachable + +// aux-build:field-method-macro.rs +// run-pass + +extern crate field_method_macro; + +fn main() { + assert_eq!(field_method_macro::m!(), 33); +} diff --git a/src/test/ui/definition-reachable/private-non-types.rs b/src/test/ui/definition-reachable/private-non-types.rs new file mode 100644 index 0000000000000..a601dabcb0b3f --- /dev/null +++ b/src/test/ui/definition-reachable/private-non-types.rs @@ -0,0 +1,21 @@ +// Check that we don't require stability annotations for private modules, +// imports and fields that are accessible to opaque macros. + +// check-pass + +#![feature(decl_macro, staged_api)] +#![stable(feature = "test", since = "1.0.0")] + +extern crate std as local_std; +use local_std::marker::Copy as LocalCopy; +mod private_mod { + #[stable(feature = "test", since = "1.0.0")] + pub struct A { + pub(crate) f: i32, + } +} + +#[stable(feature = "test", since = "1.0.0")] +pub macro m() {} + +fn main() {} diff --git a/src/test/ui/definition-reachable/private-types.rs b/src/test/ui/definition-reachable/private-types.rs new file mode 100644 index 0000000000000..02c1224f4e142 --- /dev/null +++ b/src/test/ui/definition-reachable/private-types.rs @@ -0,0 +1,19 @@ +// Check that type privacy is taken into account when considering reachability + +// check-pass + +#![feature(decl_macro, staged_api)] +#![stable(feature = "test", since = "1.0.0")] + +// Type privacy should prevent use of these in other crates, so we shouldn't +// need a stability annotation. +fn private_function() {} +struct PrivateStruct { f: () } +enum PrivateEnum { V } +union PrivateUnion { g: () } +trait PrivateTrait {} + +#[stable(feature = "test", since = "1.0.0")] +pub macro m() {} + +fn main() {} diff --git a/src/test/ui/definition-reachable/private-use.rs b/src/test/ui/definition-reachable/private-use.rs new file mode 100644 index 0000000000000..02cff0475e586 --- /dev/null +++ b/src/test/ui/definition-reachable/private-use.rs @@ -0,0 +1,10 @@ +// Check that private use statements can be used by + +// run-pass +// aux-build:private-use-macro.rs + +extern crate private_use_macro; + +fn main() { + assert_eq!(private_use_macro::m!(), 57); +} From 7b41fd215893c06110c7f650be47efed3910d90b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Aug 2019 23:06:40 +0100 Subject: [PATCH 02/16] Make some items in core::unicode private They were reachable through opaque macros defined in `core` --- src/libcore/unicode/tables.rs | 32 ++++++++++++++++---------------- src/libcore/unicode/unicode.py | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index bfe784afaa47d..3fae3a46ada6b 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -14,8 +14,8 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { micro: 0, _priv: (), }; -pub mod general_category { - pub const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie { +pub(crate) mod general_category { + const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie { r1: &[ 0, 1, 0 ], @@ -28,7 +28,7 @@ pub mod general_category { Cc_table.lookup(c) } - pub const N_table: &super::BoolTrie = &super::BoolTrie { + const N_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -141,8 +141,8 @@ pub mod general_category { } -pub mod derived_property { - pub const Alphabetic_table: &super::BoolTrie = &super::BoolTrie { +pub(crate) mod derived_property { + const Alphabetic_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, @@ -327,7 +327,7 @@ pub mod derived_property { Alphabetic_table.lookup(c) } - pub const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie { + const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -464,7 +464,7 @@ pub mod derived_property { Case_Ignorable_table.lookup(c) } - pub const Cased_table: &super::BoolTrie = &super::BoolTrie { + const Cased_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0, @@ -565,7 +565,7 @@ pub mod derived_property { Cased_table.lookup(c) } - pub const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie { + const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -689,7 +689,7 @@ pub mod derived_property { Grapheme_Extend_table.lookup(c) } - pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie { + const Lowercase_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, 0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240, @@ -789,7 +789,7 @@ pub mod derived_property { Lowercase_table.lookup(c) } - pub const Uppercase_table: &super::BoolTrie = &super::BoolTrie { + const Uppercase_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff, 0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490, @@ -890,7 +890,7 @@ pub mod derived_property { Uppercase_table.lookup(c) } - pub const XID_Continue_table: &super::BoolTrie = &super::BoolTrie { + const XID_Continue_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, @@ -1068,7 +1068,7 @@ pub mod derived_property { XID_Continue_table.lookup(c) } - pub const XID_Start_table: &super::BoolTrie = &super::BoolTrie { + const XID_Start_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, @@ -1250,8 +1250,8 @@ pub mod derived_property { } -pub mod property { - pub const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { +pub(crate) mod property { + const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { r1: &[ 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1268,7 +1268,7 @@ pub mod property { Pattern_White_Space_table.lookup(c) } - pub const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { + const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { r1: &[ 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1290,7 +1290,7 @@ pub mod property { } -pub mod conversions { +pub(crate) mod conversions { pub fn to_lower(c: char) -> [char; 3] { match bsearch_case_table(c, to_lowercase_table) { None => [c, '\0', '\0'], diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 5389d1cf80383..6de5d9e033b93 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -606,7 +606,7 @@ def compute_trie(raw_data, chunk_size): return root, child_data -def generate_bool_trie(name, codepoint_ranges, is_pub=True): +def generate_bool_trie(name, codepoint_ranges, is_pub=False): # type: (str, List[Tuple[int, int]], bool) -> Iterator[str] """ Generate Rust code for BoolTrie struct. @@ -681,7 +681,7 @@ def generate_bool_trie(name, codepoint_ranges, is_pub=True): yield " };\n\n" -def generate_small_bool_trie(name, codepoint_ranges, is_pub=True): +def generate_small_bool_trie(name, codepoint_ranges, is_pub=False): # type: (str, List[Tuple[int, int]], bool) -> Iterator[str] """ Generate Rust code for `SmallBoolTrie` struct. @@ -726,7 +726,7 @@ def generate_property_module(mod, grouped_categories, category_subset): Generate Rust code for module defining properties. """ - yield "pub mod %s {\n" % mod + yield "pub(crate) mod %s {\n" % mod for cat in sorted(category_subset): if cat in ("Cc", "White_Space", "Pattern_White_Space"): generator = generate_small_bool_trie("%s_table" % cat, grouped_categories[cat]) @@ -749,7 +749,7 @@ def generate_conversions_module(unicode_data): Generate Rust code for module defining conversions. """ - yield "pub mod conversions {" + yield "pub(crate) mod conversions {" yield """ pub fn to_lower(c: char) -> [char; 3] { match bsearch_case_table(c, to_lowercase_table) { From d9d9246418ae884cb67feb3574832696660b8e2e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Aug 2019 23:10:32 +0100 Subject: [PATCH 03/16] Remove gensym from format_args --- src/libcore/macros.rs | 2 -- src/libsyntax_ext/format.rs | 4 ++-- src/test/ui/format-hygiene.rs | 8 -------- src/test/ui/hygiene/format-args.rs | 12 ++++++++++++ 4 files changed, 14 insertions(+), 12 deletions(-) delete mode 100644 src/test/ui/format-hygiene.rs create mode 100644 src/test/ui/hygiene/format-args.rs diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 37cc71bff62b4..6a2c3bff4ddca 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -767,7 +767,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro format_args { ($fmt:expr) => ({ /* compiler built-in */ }), ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) @@ -779,7 +778,6 @@ pub(crate) mod builtin { language use and is subject to change")] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro format_args_nl { ($fmt:expr) => ({ /* compiler built-in */ }), ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index fe9cad1e32fca..1dfcc14021c3b 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -646,7 +646,7 @@ impl<'a, 'b> Context<'a, 'b> { let mut heads = Vec::with_capacity(self.args.len()); let names_pos: Vec<_> = (0..self.args.len()) - .map(|i| self.ecx.ident_of(&format!("arg{}", i)).gensym()) + .map(|i| ast::Ident::from_str_and_span(&format!("arg{}", i), self.macsp)) .collect(); // First, build up the static array which will become our precompiled @@ -843,7 +843,7 @@ pub fn expand_preparsed_format_args( let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let mut macsp = ecx.call_site(); - macsp = macsp.apply_mark(ecx.current_expansion.id); + macsp = macsp.with_ctxt(ecx.backtrace()); let msg = "format argument must be a string literal"; let fmt_sp = efmt.span; diff --git a/src/test/ui/format-hygiene.rs b/src/test/ui/format-hygiene.rs deleted file mode 100644 index 6bf5ae8beaddb..0000000000000 --- a/src/test/ui/format-hygiene.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - -#![allow(non_upper_case_globals)] -pub const arg0: u8 = 1; - -pub fn main() { - format!("{}", 1); -} diff --git a/src/test/ui/hygiene/format-args.rs b/src/test/ui/hygiene/format-args.rs new file mode 100644 index 0000000000000..d74889b95cc12 --- /dev/null +++ b/src/test/ui/hygiene/format-args.rs @@ -0,0 +1,12 @@ +// check-pass + +#![allow(non_upper_case_globals)] +#![feature(format_args_nl)] + +static arg0: () = (); + +fn main() { + static arg1: () = (); + format_args!("{} {:?}", 0, 1); + format_args_nl!("{} {:?}", 0, 1); +} From 642ee709427ada3711fb27dba9d26bbdaee6a3da Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 9 Aug 2019 08:37:40 +0900 Subject: [PATCH 04/16] Add test for issue-43623 --- src/test/ui/issues/issue-43623.rs | 19 ++++++++++++ src/test/ui/issues/issue-43623.stderr | 42 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/test/ui/issues/issue-43623.rs create mode 100644 src/test/ui/issues/issue-43623.stderr diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs new file mode 100644 index 0000000000000..b259e9e269d06 --- /dev/null +++ b/src/test/ui/issues/issue-43623.rs @@ -0,0 +1,19 @@ +pub trait Trait<'a> { + type Assoc; +} + +pub struct Type; + +impl<'a> Trait<'a> for Type { + type Assoc = (); +} + +pub fn break_me(f: F) +where T: for<'b> Trait<'b>, + F: for<'b> FnMut(>::Assoc) { + break_me::; + //~^ ERROR: type mismatch in function arguments + //~| ERROR: type mismatch resolving +} + +fn main() {} diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr new file mode 100644 index 0000000000000..b5674105f75d2 --- /dev/null +++ b/src/test/ui/issues/issue-43623.stderr @@ -0,0 +1,42 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/issue-43623.rs:14:5 + | +LL | break_me::; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected signature of `for<'b> fn(>::Assoc) -> _` + | found signature of `fn(_) -> _` + | +note: required by `break_me` + --> $DIR/issue-43623.rs:11:1 + | +LL | / pub fn break_me(f: F) +LL | | where T: for<'b> Trait<'b>, +LL | | F: for<'b> FnMut(>::Assoc) { +LL | | break_me::; +LL | | +LL | | +LL | | } + | |_^ + +error[E0271]: type mismatch resolving `for<'b> >::Assoc,)>>::Output == ()` + --> $DIR/issue-43623.rs:14:5 + | +LL | break_me::; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime + | +note: required by `break_me` + --> $DIR/issue-43623.rs:11:1 + | +LL | / pub fn break_me(f: F) +LL | | where T: for<'b> Trait<'b>, +LL | | F: for<'b> FnMut(>::Assoc) { +LL | | break_me::; +LL | | +LL | | +LL | | } + | |_^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. From 55f15d765565773e95c60e7e14b956bfeed30157 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 9 Aug 2019 08:37:55 +0900 Subject: [PATCH 05/16] Add test for issue-44405 --- src/test/ui/issues/issue-44405.rs | 22 ++++++++++++++++++++++ src/test/ui/issues/issue-44405.stderr | 11 +++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/ui/issues/issue-44405.rs create mode 100644 src/test/ui/issues/issue-44405.stderr diff --git a/src/test/ui/issues/issue-44405.rs b/src/test/ui/issues/issue-44405.rs new file mode 100644 index 0000000000000..d404b9044dd6f --- /dev/null +++ b/src/test/ui/issues/issue-44405.rs @@ -0,0 +1,22 @@ +use std::ops::Index; + +struct Test; +struct Container(Test); + +impl Test { + fn test(&mut self) {} +} + +impl<'a> Index<&'a bool> for Container { + type Output = Test; + + fn index(&self, _index: &'a bool) -> &Test { + &self.0 + } +} + +fn main() { + let container = Container(Test); + let mut val = true; + container[&mut val].test(); //~ ERROR: cannot borrow data +} diff --git a/src/test/ui/issues/issue-44405.stderr b/src/test/ui/issues/issue-44405.stderr new file mode 100644 index 0000000000000..1fd69f6e77799 --- /dev/null +++ b/src/test/ui/issues/issue-44405.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow data in an index of `Container` as mutable + --> $DIR/issue-44405.rs:21:5 + | +LL | container[&mut val].test(); + | ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Container` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. From fd7ac6b17ef98f63438f59edca40562c400d4128 Mon Sep 17 00:00:00 2001 From: BO41 Date: Sun, 23 Jun 2019 12:19:46 +0000 Subject: [PATCH 06/16] Deprecate `try!` macro Co-Authored-By: Mazdak Farrokhzad Co-Authored-By: Oliver Middleton --- src/libcore/macros.rs | 1 + src/libstd/lib.rs | 5 ++++- src/test/ui/associated-types/cache/chrono-scan.rs | 2 +- src/test/ui/derived-errors/issue-31997.rs | 2 +- src/test/ui/derived-errors/issue-31997.stderr | 6 +++--- src/test/ui/lint/lint-qualification.rs | 2 +- src/test/ui/macros/macro-comma-support-rpass.rs | 2 ++ src/test/ui/macros/try-macro.rs | 1 + src/test/ui/rust-2018/try-macro.fixed | 1 + src/test/ui/rust-2018/try-macro.rs | 1 + src/test/ui/rust-2018/try-macro.stderr | 2 +- 11 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 09d2331b60fed..ba641f7dc5c12 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -300,6 +300,7 @@ macro_rules! debug_assert_ne { /// Ok(()) /// } /// ``` +#[rustc_deprecated(since = "1.38.0", reason = "use the `?` operator instead")] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "?")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index cfee49a7b555c..34956fc839450 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -330,7 +330,10 @@ use prelude::v1::*; #[stable(feature = "rust1", since = "1.0.0")] pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::{unreachable, unimplemented, write, writeln, r#try, todo}; +pub use core::{unreachable, unimplemented, write, writeln, todo}; +#[allow(deprecated)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::r#try; #[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs index 8ddd347ff3607..5c05240552761 100644 --- a/src/test/ui/associated-types/cache/chrono-scan.rs +++ b/src/test/ui/associated-types/cache/chrono-scan.rs @@ -18,7 +18,7 @@ pub fn timezone_offset_zulu(s: &str, colon: F) -> ParseResult<(&str, i32)> pub fn parse<'a, I>(mut s: &str, items: I) -> ParseResult<()> where I: Iterator> { macro_rules! try_consume { - ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) + ($e:expr) => ({ let (s_, v) = $e?; s = s_; v }) } let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space)); let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space)); diff --git a/src/test/ui/derived-errors/issue-31997.rs b/src/test/ui/derived-errors/issue-31997.rs index cfdee26c5599c..6d7d21e367322 100644 --- a/src/test/ui/derived-errors/issue-31997.rs +++ b/src/test/ui/derived-errors/issue-31997.rs @@ -10,7 +10,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(core::ptr::null_mut()))); //~ ERROR cannot find function `bar` in this scope + closure(|| bar(core::ptr::null_mut()))?; //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/src/test/ui/derived-errors/issue-31997.stderr b/src/test/ui/derived-errors/issue-31997.stderr index e9fe0d3971ee6..d9260f79f2742 100644 --- a/src/test/ui/derived-errors/issue-31997.stderr +++ b/src/test/ui/derived-errors/issue-31997.stderr @@ -1,8 +1,8 @@ error[E0425]: cannot find function `bar` in this scope - --> $DIR/issue-31997.rs:13:21 + --> $DIR/issue-31997.rs:13:16 | -LL | try!(closure(|| bar(core::ptr::null_mut()))); - | ^^^ not found in this scope +LL | closure(|| bar(core::ptr::null_mut()))?; + | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/lint/lint-qualification.rs b/src/test/ui/lint/lint-qualification.rs index 2aa4526b8169b..d458c31dc4926 100644 --- a/src/test/ui/lint/lint-qualification.rs +++ b/src/test/ui/lint/lint-qualification.rs @@ -9,7 +9,7 @@ fn main() { foo::bar(); //~ ERROR: unnecessary qualification bar(); - let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345 + let _ = || -> Result<(), ()> { Ok(())?; Ok(()) }; // issue #37345 macro_rules! m { () => { $crate::foo::bar(); // issue #37357 diff --git a/src/test/ui/macros/macro-comma-support-rpass.rs b/src/test/ui/macros/macro-comma-support-rpass.rs index 12a612c153ad6..17c27b7cda473 100644 --- a/src/test/ui/macros/macro-comma-support-rpass.rs +++ b/src/test/ui/macros/macro-comma-support-rpass.rs @@ -261,7 +261,9 @@ fn thread_local() { #[test] fn try() { fn inner() -> Result<(), ()> { + #[allow(deprecated)] try!(Ok(())); + #[allow(deprecated)] try!(Ok(()),); Ok(()) } diff --git a/src/test/ui/macros/try-macro.rs b/src/test/ui/macros/try-macro.rs index 83b30a8b7ba11..643312654493a 100644 --- a/src/test/ui/macros/try-macro.rs +++ b/src/test/ui/macros/try-macro.rs @@ -1,4 +1,5 @@ // run-pass +#[allow(deprecated)] use std::num::{ParseFloatError, ParseIntError}; fn main() { diff --git a/src/test/ui/rust-2018/try-macro.fixed b/src/test/ui/rust-2018/try-macro.fixed index 7c1692fd7fb13..a7b7d3faf5ee9 100644 --- a/src/test/ui/rust-2018/try-macro.fixed +++ b/src/test/ui/rust-2018/try-macro.fixed @@ -6,6 +6,7 @@ #![warn(rust_2018_compatibility)] #![allow(unused_variables)] #![allow(dead_code)] +#![allow(deprecated)] fn foo() -> Result { let x: Result = Ok(22); diff --git a/src/test/ui/rust-2018/try-macro.rs b/src/test/ui/rust-2018/try-macro.rs index 2089d367be698..986e158eb644e 100644 --- a/src/test/ui/rust-2018/try-macro.rs +++ b/src/test/ui/rust-2018/try-macro.rs @@ -6,6 +6,7 @@ #![warn(rust_2018_compatibility)] #![allow(unused_variables)] #![allow(dead_code)] +#![allow(deprecated)] fn foo() -> Result { let x: Result = Ok(22); diff --git a/src/test/ui/rust-2018/try-macro.stderr b/src/test/ui/rust-2018/try-macro.stderr index eb65d4150642a..fad1bb9f1b068 100644 --- a/src/test/ui/rust-2018/try-macro.stderr +++ b/src/test/ui/rust-2018/try-macro.stderr @@ -1,5 +1,5 @@ warning: `try` is a keyword in the 2018 edition - --> $DIR/try-macro.rs:12:5 + --> $DIR/try-macro.rs:13:5 | LL | try!(x); | ^^^ help: you can use a raw identifier to stay compatible: `r#try` From 90fa7901b98367d04857cb96366b2eedf70693e2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 15 Jul 2019 17:42:08 +0000 Subject: [PATCH 07/16] Postpone deprecating try! until 1.39.0 --- src/libcore/macros.rs | 2 +- src/libstd/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index ba641f7dc5c12..aa661078e7176 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -300,9 +300,9 @@ macro_rules! debug_assert_ne { /// Ok(()) /// } /// ``` -#[rustc_deprecated(since = "1.38.0", reason = "use the `?` operator instead")] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.39.0", reason = "use the `?` operator instead")] #[doc(alias = "?")] macro_rules! r#try { ($expr:expr) => (match $expr { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 34956fc839450..54abf72d3075a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -331,7 +331,8 @@ use prelude::v1::*; pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::{unreachable, unimplemented, write, writeln, todo}; -#[allow(deprecated)] +// FIXME: change this to `#[allow(deprecated)]` when we update nightly compiler. +#[allow(deprecated_in_future)] #[stable(feature = "rust1", since = "1.0.0")] pub use core::r#try; From 6842316f6ff4586465e6412edce5e6808cfcd396 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2019 08:16:46 +0000 Subject: [PATCH 08/16] Allow deprecated try macro in test crates --- src/test/ui/associated-types/cache/chrono-scan.rs | 4 +++- src/test/ui/derived-errors/issue-31997.rs | 3 ++- src/test/ui/derived-errors/issue-31997.stderr | 6 +++--- src/test/ui/lint/lint-qualification.rs | 3 ++- src/test/ui/lint/lint-qualification.stderr | 2 +- src/test/ui/macros/macro-comma-support-rpass.rs | 3 +-- src/test/ui/macros/try-macro.rs | 2 +- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs index 5c05240552761..964ddc9b625de 100644 --- a/src/test/ui/associated-types/cache/chrono-scan.rs +++ b/src/test/ui/associated-types/cache/chrono-scan.rs @@ -1,5 +1,7 @@ // check-pass +#![allow(deprecated)] + pub type ParseResult = Result; pub enum Item<'a> { @@ -18,7 +20,7 @@ pub fn timezone_offset_zulu(s: &str, colon: F) -> ParseResult<(&str, i32)> pub fn parse<'a, I>(mut s: &str, items: I) -> ParseResult<()> where I: Iterator> { macro_rules! try_consume { - ($e:expr) => ({ let (s_, v) = $e?; s = s_; v }) + ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) } let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space)); let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space)); diff --git a/src/test/ui/derived-errors/issue-31997.rs b/src/test/ui/derived-errors/issue-31997.rs index 6d7d21e367322..ff619313afb5b 100644 --- a/src/test/ui/derived-errors/issue-31997.rs +++ b/src/test/ui/derived-errors/issue-31997.rs @@ -1,5 +1,6 @@ // Test that the resolve failure does not lead to downstream type errors. // See issue #31997. +#![allow(deprecated)] trait TheTrait { } @@ -10,7 +11,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - closure(|| bar(core::ptr::null_mut()))?; //~ ERROR cannot find function `bar` in this scope + try!(closure(|| bar(core::ptr::null_mut()))); //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/src/test/ui/derived-errors/issue-31997.stderr b/src/test/ui/derived-errors/issue-31997.stderr index d9260f79f2742..b53c0cda8de4d 100644 --- a/src/test/ui/derived-errors/issue-31997.stderr +++ b/src/test/ui/derived-errors/issue-31997.stderr @@ -1,8 +1,8 @@ error[E0425]: cannot find function `bar` in this scope - --> $DIR/issue-31997.rs:13:16 + --> $DIR/issue-31997.rs:14:21 | -LL | closure(|| bar(core::ptr::null_mut()))?; - | ^^^ not found in this scope +LL | try!(closure(|| bar(core::ptr::null_mut()))); + | ^^^ not found in this scope error: aborting due to previous error diff --git a/src/test/ui/lint/lint-qualification.rs b/src/test/ui/lint/lint-qualification.rs index d458c31dc4926..1b24191a111c2 100644 --- a/src/test/ui/lint/lint-qualification.rs +++ b/src/test/ui/lint/lint-qualification.rs @@ -1,4 +1,5 @@ #![deny(unused_qualifications)] +#[allow(deprecated)] mod foo { pub fn bar() {} @@ -9,7 +10,7 @@ fn main() { foo::bar(); //~ ERROR: unnecessary qualification bar(); - let _ = || -> Result<(), ()> { Ok(())?; Ok(()) }; // issue #37345 + let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345 macro_rules! m { () => { $crate::foo::bar(); // issue #37357 diff --git a/src/test/ui/lint/lint-qualification.stderr b/src/test/ui/lint/lint-qualification.stderr index 78f7e32a30cd1..125aeb3db0366 100644 --- a/src/test/ui/lint/lint-qualification.stderr +++ b/src/test/ui/lint/lint-qualification.stderr @@ -1,5 +1,5 @@ error: unnecessary qualification - --> $DIR/lint-qualification.rs:9:5 + --> $DIR/lint-qualification.rs:10:5 | LL | foo::bar(); | ^^^^^^^^ diff --git a/src/test/ui/macros/macro-comma-support-rpass.rs b/src/test/ui/macros/macro-comma-support-rpass.rs index 17c27b7cda473..50c0ef3451d3d 100644 --- a/src/test/ui/macros/macro-comma-support-rpass.rs +++ b/src/test/ui/macros/macro-comma-support-rpass.rs @@ -15,6 +15,7 @@ #![cfg_attr(core, no_std)] +#![allow(deprecated)] // for deprecated `try!()` macro #![feature(concat_idents)] #[cfg(std)] use std::fmt; @@ -261,9 +262,7 @@ fn thread_local() { #[test] fn try() { fn inner() -> Result<(), ()> { - #[allow(deprecated)] try!(Ok(())); - #[allow(deprecated)] try!(Ok(()),); Ok(()) } diff --git a/src/test/ui/macros/try-macro.rs b/src/test/ui/macros/try-macro.rs index 643312654493a..824c77d9de528 100644 --- a/src/test/ui/macros/try-macro.rs +++ b/src/test/ui/macros/try-macro.rs @@ -1,5 +1,5 @@ // run-pass -#[allow(deprecated)] +#![allow(deprecated)] // for deprecated `try!()` macro use std::num::{ParseFloatError, ParseIntError}; fn main() { From e9ee2cbc53af43dc007bfd81054fb20e57d5da67 Mon Sep 17 00:00:00 2001 From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com> Date: Fri, 9 Aug 2019 12:47:27 +0530 Subject: [PATCH 09/16] Improve test output for libcore/time --- src/libcore/tests/time.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 09aae4583482f..fac70c468c89d 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -2,7 +2,7 @@ use core::time::Duration; #[test] fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_ne!(Duration::from_secs(1), Duration::from_secs(0)); assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), Duration::from_secs(3)); assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), @@ -107,14 +107,12 @@ fn checked_sub() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn sub_bad1() { let _ = Duration::new(0, 0) - Duration::new(0, 1); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn sub_bad2() { let _ = Duration::new(0, 0) - Duration::new(1, 0); } From 623debfe9dcbb70bcb5fd891db2e861d91e1b8a9 Mon Sep 17 00:00:00 2001 From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com> Date: Fri, 9 Aug 2019 12:51:34 +0530 Subject: [PATCH 10/16] Improve tests for libcore/slice --- src/libcore/tests/slice.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 31d16e0e32057..c036dd8d92f22 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -3,19 +3,19 @@ use core::result::Result::{Ok, Err}; #[test] fn test_position() { let b = [1, 2, 3, 5, 5]; - assert!(b.iter().position(|&v| v == 9) == None); - assert!(b.iter().position(|&v| v == 5) == Some(3)); - assert!(b.iter().position(|&v| v == 3) == Some(2)); - assert!(b.iter().position(|&v| v == 0) == None); + assert_eq!(b.iter().position(|&v| v == 9), None); + assert_eq!(b.iter().position(|&v| v == 5), Some(3)); + assert_eq!(b.iter().position(|&v| v == 3), Some(2)); + assert_eq!(b.iter().position(|&v| v == 0), None); } #[test] fn test_rposition() { let b = [1, 2, 3, 5, 5]; - assert!(b.iter().rposition(|&v| v == 9) == None); - assert!(b.iter().rposition(|&v| v == 5) == Some(4)); - assert!(b.iter().rposition(|&v| v == 3) == Some(2)); - assert!(b.iter().rposition(|&v| v == 0) == None); + assert_eq!(b.iter().rposition(|&v| v == 9), None); + assert_eq!(b.iter().rposition(|&v| v == 5), Some(4)); + assert_eq!(b.iter().rposition(|&v| v == 3), Some(2)); + assert_eq!(b.iter().rposition(|&v| v == 0), None); } #[test] From 33445aea509cadcd715009c79795d289268daa7c Mon Sep 17 00:00:00 2001 From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com> Date: Fri, 9 Aug 2019 12:53:14 +0530 Subject: [PATCH 11/16] Improve tests for liballoc/btree/set --- src/liballoc/tests/btree/set.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 4f5168f1ce572..9e03137594961 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -10,7 +10,7 @@ fn test_clone_eq() { m.insert(1); m.insert(2); - assert!(m.clone() == m); + assert_eq!(m.clone(), m); } #[test] @@ -28,7 +28,7 @@ fn test_hash() { y.insert(2); y.insert(1); - assert!(hash(&x) == hash(&y)); + assert_eq!(hash(&x), hash(&y)); } fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) From c5687e3940faaa398843e8e9e9c8f9a00a267b0b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 10:07:59 +0200 Subject: [PATCH 12/16] enable flt2dec tests in Miri --- src/libcore/tests/num/flt2dec/estimator.rs | 7 +++++- src/libcore/tests/num/flt2dec/mod.rs | 16 +++++++++++-- src/libcore/tests/num/flt2dec/random.rs | 23 +++++++++++++++---- .../tests/num/flt2dec/strategy/dragon.rs | 1 + .../tests/num/flt2dec/strategy/grisu.rs | 1 + 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs index 2dbb8e3a5f06e..50fe61b5e2267 100644 --- a/src/libcore/tests/num/flt2dec/estimator.rs +++ b/src/libcore/tests/num/flt2dec/estimator.rs @@ -42,7 +42,12 @@ fn test_estimate_scaling_factor() { assert_almost_eq!(estimate_scaling_factor(1, -1074), -323); assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309); - for i in -1074..972 { + #[cfg(not(miri))] // Miri is too slow + let iter = -1074..972; + #[cfg(miri)] + let iter = (-1074..972).step_by(11); + + for i in iter { let expected = super::ldexp_f64(1.0, i).log10().ceil(); assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); } diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index f42f500c2df1d..c41d35efced6c 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -1,5 +1,3 @@ -#![cfg(not(miri))] // Miri does not implement ldexp, which most tests here need - use std::prelude::v1::*; use std::{str, i16, f32, f64, fmt}; @@ -257,6 +255,7 @@ pub fn f32_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) check_shortest!(f(minf32) => b"1", -44); } +#[cfg(not(miri))] // Miri is too slow pub fn f32_exact_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { let minf32 = ldexp_f32(1.0, -149); @@ -362,6 +361,7 @@ pub fn f64_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) check_shortest!(f(minf64) => b"5", -323); } +#[cfg(not(miri))] // Miri is too slow pub fn f64_exact_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { let minf64 = ldexp_f64(1.0, -1074); @@ -553,6 +553,10 @@ pub fn to_shortest_str_test(mut f_: F) assert_eq!(to_string(f, minf64, Minus, 324, false), format!("0.{:0>323}5", "")); assert_eq!(to_string(f, minf64, Minus, 325, false), format!("0.{:0>323}50", "")); + if cfg!(miri) { // Miri is too slow + return; + } + // very large output assert_eq!(to_string(f, 1.1, Minus, 80000, false), format!("1.1{:0>79999}", "")); } @@ -807,6 +811,10 @@ pub fn to_exact_exp_str_test(mut f_: F) "1.401298464324817070923729583289916131280261941876515771757068283\ 8897910826858606014866381883621215820312500000000000000000000000e-45"); + if cfg!(miri) { // Miri is too slow + return; + } + assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); @@ -1040,6 +1048,10 @@ pub fn to_exact_fixed_str_test(mut f_: F) assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "340282346638528859811704183484516925440.00"); + if cfg!(miri) { // Miri is too slow + return; + } + let minf32 = ldexp_f32(1.0, -149); assert_eq!(to_string(f, minf32, Minus, 0, false), "0"); assert_eq!(to_string(f, minf32, Minus, 1, false), "0.0"); diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index d56787b2819a7..3db5b4c84fc3b 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -109,8 +109,13 @@ pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) #[test] fn shortest_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); + #[cfg(not(miri))] // Miri is too slow + const N: usize = 10_000; + #[cfg(miri)] + const N: usize = 20; + + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); } #[test] #[ignore] // it is too expensive @@ -138,17 +143,27 @@ fn shortest_f64_hard_random_equivalence_test() { #[test] fn exact_f32_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; + #[cfg(not(miri))] // Miri is too slow + const N: usize = 1_000; + #[cfg(miri)] + const N: usize = 10; + for k in 1..21 { f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + |d, buf| fallback(d, buf, i16::MIN), k, N); } } #[test] fn exact_f64_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; + #[cfg(not(miri))] // Miri is too slow + const N: usize = 1_000; + #[cfg(miri)] + const N: usize = 5; + for k in 1..21 { f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + |d, buf| fallback(d, buf, i16::MIN), k, N); } } diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs index 5e4cc23d33c8c..dc4d78bfae109 100644 --- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs @@ -23,6 +23,7 @@ fn shortest_sanity_test() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn exact_sanity_test() { // This test ends up running what I can only assume is some corner-ish case // of the `exp2` library function, defined in whatever C runtime we're diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs index f1afd7d4bf86f..f8bdddfe2e410 100644 --- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs @@ -36,6 +36,7 @@ fn shortest_sanity_test() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn exact_sanity_test() { // See comments in dragon.rs's exact_sanity_test for why this test is // ignored on MSVC From c7e16c5f47ac86877ab6c52db61709349e4cf276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Tue, 6 Aug 2019 14:55:57 +0200 Subject: [PATCH 13/16] Check links on all platforms when running locally --- src/bootstrap/tool.rs | 26 ++++++++++++++++++++--- src/ci/docker/x86_64-gnu-tools/Dockerfile | 3 +++ src/tools/rustbook/Cargo.toml | 7 +++--- src/tools/rustbook/src/main.rs | 13 ++++++------ 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 15a329a5b9152..df7eb7c455d02 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -9,7 +9,7 @@ use build_helper::t; use crate::Mode; use crate::Compiler; use crate::builder::{Step, RunConfig, ShouldRun, Builder}; -use crate::util::{exe, add_lib_path}; +use crate::util::{exe, add_lib_path, CiEnv}; use crate::compile; use crate::channel::GitInfo; use crate::channel; @@ -279,11 +279,26 @@ pub fn prepare_tool_cargo( cargo } +fn rustbook_features() -> Vec { + let mut features = Vec::new(); + + // Due to CI budged and risk of spurious failures we want to limit jobs running this check. + // At same time local builds should run it regardless of the platform. + // `CiEnv::None` means it's local build and `CHECK_LINKS` is defined in x86_64-gnu-tools to + // explicitly enable it on single job + if CiEnv::current() == CiEnv::None || env::var("CHECK_LINKS").is_ok() { + features.push("linkcheck".to_string()); + } + + features +} + macro_rules! bootstrap_tool { ($( $name:ident, $path:expr, $tool_name:expr $(,llvm_tools = $llvm:expr)* $(,is_external_tool = $external:expr)* + $(,features = $features:expr)* ; )+) => { #[derive(Copy, PartialEq, Eq, Clone)] @@ -350,7 +365,12 @@ macro_rules! bootstrap_tool { } else { SourceType::InTree }, - extra_features: Vec::new(), + extra_features: { + // FIXME(#60643): avoid this lint by using `_` + let mut _tmp = Vec::new(); + $(_tmp.extend($features);)* + _tmp + }, }).expect("expected to build -- essential tool") } } @@ -359,7 +379,7 @@ macro_rules! bootstrap_tool { } bootstrap_tool!( - Rustbook, "src/tools/rustbook", "rustbook"; + Rustbook, "src/tools/rustbook", "rustbook", features = rustbook_features(); UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen"; Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; diff --git a/src/ci/docker/x86_64-gnu-tools/Dockerfile b/src/ci/docker/x86_64-gnu-tools/Dockerfile index f11ae7a34cb91..8035195c6ed0a 100644 --- a/src/ci/docker/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/x86_64-gnu-tools/Dockerfile @@ -21,6 +21,9 @@ COPY x86_64-gnu-tools/checkregression.py /tmp/ COPY x86_64-gnu-tools/checktools.sh /tmp/ COPY x86_64-gnu-tools/repo.sh /tmp/ +# Run rustbook with `linkcheck` feature enabled +ENV CHECK_LINKS 1 + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstates.json diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index bb10d06851b5a..a7188f0d11eac 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -5,14 +5,15 @@ version = "0.1.0" license = "MIT OR Apache-2.0" edition = "2018" +[features] +linkcheck = ["mdbook-linkcheck"] + [dependencies] clap = "2.25.0" failure = "0.1" +mdbook-linkcheck = { version = "0.3.0", optional = true } [dependencies.mdbook] version = "0.3.0" default-features = false features = ["search"] - -[target.'cfg(all(target_arch = "x86_64", target_os = "linux"))'.dependencies] -mdbook-linkcheck = "0.3.0" diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 6bce7c3a978eb..95530b210afd6 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -8,10 +8,9 @@ use clap::{App, ArgMatches, SubCommand, AppSettings}; use mdbook::MDBook; use mdbook::errors::{Result as Result3}; -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] +#[cfg(feature = "linkcheck")] use mdbook::renderer::RenderContext; - -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] +#[cfg(feature = "linkcheck")] use mdbook_linkcheck::{self, errors::BrokenLinks}; use failure::Error; @@ -52,7 +51,7 @@ fn main() { if let Err(err) = linkcheck(sub_matches) { eprintln!("Error: {}", err); - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] + #[cfg(feature = "linkcheck")] { if let Ok(broken_links) = err.downcast::() { for cause in broken_links.links().iter() { @@ -68,7 +67,7 @@ fn main() { }; } -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] +#[cfg(feature = "linkcheck")] pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> { let book_dir = get_book_dir(args); let book = MDBook::load(&book_dir).unwrap(); @@ -78,9 +77,9 @@ pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> { mdbook_linkcheck::check_links(&render_ctx) } -#[cfg(not(all(target_arch = "x86_64", target_os = "linux")))] +#[cfg(not(feature = "linkcheck"))] pub fn linkcheck(_args: &ArgMatches<'_>) -> Result<(), Error> { - println!("mdbook-linkcheck only works on x86_64 linux targets."); + println!("mdbook-linkcheck is disabled."); Ok(()) } From 29ca428ffa753a300b880ee11e132ead54f4dbb7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:18:17 +0200 Subject: [PATCH 14/16] Miri is really slow --- src/libcore/tests/num/dec2flt/mod.rs | 1 + src/libcore/tests/num/flt2dec/estimator.rs | 2 +- src/libcore/tests/num/flt2dec/random.rs | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index 0e71426c64108..46eacb4200acc 100644 --- a/src/libcore/tests/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs @@ -77,6 +77,7 @@ fn infinity() { fn zero() { test_literal!(0.0); test_literal!(1e-325); + #[cfg(not(miri))] // Miri is too slow test_literal!(1e-326); #[cfg(not(miri))] // Miri is too slow test_literal!(1e-500); diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs index 50fe61b5e2267..c51451708f3ce 100644 --- a/src/libcore/tests/num/flt2dec/estimator.rs +++ b/src/libcore/tests/num/flt2dec/estimator.rs @@ -45,7 +45,7 @@ fn test_estimate_scaling_factor() { #[cfg(not(miri))] // Miri is too slow let iter = -1074..972; #[cfg(miri)] - let iter = (-1074..972).step_by(11); + let iter = (-1074..972).step_by(37); for i in iter { let expected = super::ldexp_f64(1.0, i).log10().ceil(); diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index 3db5b4c84fc3b..d9543793397bf 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -112,7 +112,7 @@ fn shortest_random_equivalence_test() { #[cfg(not(miri))] // Miri is too slow const N: usize = 10_000; #[cfg(miri)] - const N: usize = 20; + const N: usize = 10; f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); @@ -146,7 +146,7 @@ fn exact_f32_random_equivalence_test() { #[cfg(not(miri))] // Miri is too slow const N: usize = 1_000; #[cfg(miri)] - const N: usize = 10; + const N: usize = 3; for k in 1..21 { f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), @@ -160,7 +160,7 @@ fn exact_f64_random_equivalence_test() { #[cfg(not(miri))] // Miri is too slow const N: usize = 1_000; #[cfg(miri)] - const N: usize = 5; + const N: usize = 3; for k in 1..21 { f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), From 73edef7fdc1caa72fbceb773743a2c4b31162601 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:43:25 +0200 Subject: [PATCH 15/16] reduce some test sizes in Miri --- src/liballoc/tests/btree/map.rs | 3 +++ src/liballoc/tests/btree/set.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 844afe870766b..266a0d055d5bc 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -689,7 +689,10 @@ fn test_split_off_empty_left() { #[test] fn test_split_off_large_random_sorted() { + #[cfg(not(miri))] // Miri is too slow let mut data = rand_data(1529); + #[cfg(miri)] + let mut data = rand_data(529); // special case with maximum height. data.sort(); diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 989beb3b1bfd9..b3e85ce186082 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -69,6 +69,11 @@ fn test_intersection() { check_intersection(&[11, 1, 3, 77, 103, 5, -5], &[2, 11, 77, -9, -42, 5, 3], &[3, 5, 11, 77]); + + if cfg!(miri) { // Miri is too slow + return; + } + let large = (0..1000).collect::>(); check_intersection(&[], &large, &[]); check_intersection(&large, &[], &[]); @@ -98,6 +103,11 @@ fn test_difference() { check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); + + if cfg!(miri) { // Miri is too slow + return; + } + let large = (0..1000).collect::>(); check_difference(&[], &large, &[]); check_difference(&[-1], &large, &[-1]); @@ -166,6 +176,17 @@ fn test_is_subset() { assert_eq!(is_subset(&[1, 2], &[1]), false); assert_eq!(is_subset(&[1, 2], &[1, 2]), true); assert_eq!(is_subset(&[1, 2], &[2, 3]), false); + assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42], + &[-12, -5, 14, 23, 11, 34, 22, 38, 33, 42, 39, 40]), + true); + assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42], + &[-12, -5, 14, 23, 34, 38, 22, 11]), + false); + + if cfg!(miri) { // Miri is too slow + return; + } + let large = (0..1000).collect::>(); assert_eq!(is_subset(&[], &large), true); assert_eq!(is_subset(&large, &[]), false); @@ -371,7 +392,10 @@ fn test_split_off_empty_left() { #[test] fn test_split_off_large_random_sorted() { + #[cfg(not(miri))] // Miri is too slow let mut data = rand_data(1529); + #[cfg(miri)] + let mut data = rand_data(529); // special case with maximum height. data.sort(); From 78caca00d7112c0216c52e86833e93a63085dcd1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 13:55:22 +0200 Subject: [PATCH 16/16] explain Miri disabling --- src/libcore/tests/slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 1ef77f87ab7e2..a0426c0d4fe8a 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -1153,7 +1153,7 @@ fn test_rotate_right() { } #[test] -#[cfg(not(miri))] +#[cfg(not(miri))] // Miri is too slow fn brute_force_rotate_test_0() { // In case of edge cases involving multiple algorithms let n = 300;