From e991abd00455b20bb96076bbeec63e56764fc822 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 26 Jun 2019 21:15:13 -0400 Subject: [PATCH 01/12] remove unused derives and variants --- src/librustdoc/clean/cfg.rs | 2 +- src/librustdoc/clean/mod.rs | 111 +++++++++++++++---------------- src/librustdoc/doctree.rs | 2 +- src/librustdoc/html/format.rs | 3 - src/librustdoc/html/item_type.rs | 1 - src/librustdoc/html/render.rs | 3 - src/librustdoc/lib.rs | 2 - 7 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 67113787915a3..ad211763a6c46 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -16,7 +16,7 @@ use syntax_pos::Span; use crate::html::escape::Escape; -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Cfg { /// Accepts all configurations. True, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 41a56756a1480..3fe048a6986bb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ExternalCrate { pub name: String, pub src: FileName, @@ -355,7 +355,7 @@ impl Clean for CrateNum { /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone)] pub struct Item { /// Stringified span pub source: Span, @@ -528,7 +528,7 @@ impl Item { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum ItemEnum { ExternCrateItem(String, Option), ImportItem(Import), @@ -594,7 +594,7 @@ impl ItemEnum { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Module { pub items: Vec, pub is_crate: bool, @@ -731,7 +731,7 @@ impl> NestedAttributesExt for I { /// Included files are kept separate from inline doc comments so that proper line-number /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are /// kept separate because of issue #42760. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum DocFragment { /// A doc fragment created from a `///` or `//!` doc comment. SugaredDoc(usize, syntax_pos::Span, String), @@ -781,7 +781,7 @@ impl<'a> FromIterator<&'a DocFragment> for String { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Attributes { pub doc_strings: Vec, pub other_attrs: Vec, @@ -1048,7 +1048,7 @@ impl Clean for [ast::Attribute] { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifier), Outlives(Lifetime), @@ -1231,7 +1231,7 @@ impl<'tcx> Clean>> for InternalSubsts<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Lifetime(String); impl Lifetime { @@ -1326,7 +1326,7 @@ impl Clean> for ty::RegionKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec }, @@ -1464,7 +1464,7 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericParamDefKind { Lifetime, Type { @@ -1498,7 +1498,7 @@ impl GenericParamDefKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct GenericParamDef { pub name: String, @@ -1610,7 +1610,7 @@ impl Clean for hir::GenericParam { } // maybe use a Generic enum and use Vec? -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] pub struct Generics { pub params: Vec, pub where_predicates: Vec, @@ -1874,7 +1874,7 @@ pub fn get_all_types( (all_types.into_iter().collect(), ret_types) } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Method { pub generics: Generics, pub decl: FnDecl, @@ -1902,7 +1902,7 @@ impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId, } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct TyMethod { pub header: hir::FnHeader, pub decl: FnDecl, @@ -1911,7 +1911,7 @@ pub struct TyMethod { pub ret_types: Vec, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Function { pub decl: FnDecl, pub generics: Generics, @@ -1952,7 +1952,7 @@ impl Clean for doctree::Function<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, @@ -1989,7 +1989,7 @@ impl FnDecl { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Arguments { pub values: Vec, } @@ -2063,13 +2063,13 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Argument { pub type_: Type, pub name: String, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] pub enum SelfTy { SelfValue, SelfBorrowed(Option, Mutability), @@ -2093,7 +2093,7 @@ impl Argument { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum FunctionRetTy { Return(Type), DefaultReturn, @@ -2117,7 +2117,7 @@ impl GetDefId for FunctionRetTy { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Trait { pub auto: bool, pub unsafety: hir::Unsafety, @@ -2153,7 +2153,7 @@ impl Clean for doctree::Trait<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct TraitAlias { pub generics: Generics, pub bounds: Vec, @@ -2437,7 +2437,7 @@ impl Clean for ty::AssocItem { } /// A trait reference, which may have higher ranked lifetimes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct PolyTrait { pub trait_: Type, pub generic_params: Vec, @@ -2446,7 +2446,7 @@ pub struct PolyTrait { /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most /// importantly, it does not preserve mutability or boxes. -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum Type { /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). ResolvedPath { @@ -2469,7 +2469,6 @@ pub enum Type { Array(Box, String), Never, CVarArgs, - Unique(Box), RawPointer(Mutability, Box), BorrowedRef { lifetime: Option, @@ -2491,7 +2490,7 @@ pub enum Type { ImplTrait(Vec), } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] pub enum PrimitiveType { Isize, I8, I16, I32, I64, I128, Usize, U8, U16, U32, U64, U128, @@ -2510,7 +2509,7 @@ pub enum PrimitiveType { CVarArgs, } -#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] +#[derive(Clone, Copy, Debug)] pub enum TypeKind { Enum, Function, @@ -2520,7 +2519,6 @@ pub enum TypeKind { Struct, Union, Trait, - Variant, Typedef, Foreign, Macro, @@ -3190,7 +3188,7 @@ impl Clean for ty::FieldDef { } } -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum Visibility { Public, Inherited, @@ -3219,7 +3217,7 @@ impl Clean> for ty::Visibility { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Struct { pub struct_type: doctree::StructType, pub generics: Generics, @@ -3227,7 +3225,7 @@ pub struct Struct { pub fields_stripped: bool, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Union { pub struct_type: doctree::StructType, pub generics: Generics, @@ -3278,7 +3276,7 @@ impl Clean for doctree::Union<'_> { /// This is a more limited form of the standard Struct, different in that /// it lacks the things most items have (name, id, parameterization). Found /// only as a variant in an enum. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct VariantStruct { pub struct_type: doctree::StructType, pub fields: Vec, @@ -3295,7 +3293,7 @@ impl Clean for ::rustc::hir::VariantData { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Enum { pub variants: IndexVec, pub generics: Generics, @@ -3321,7 +3319,7 @@ impl Clean for doctree::Enum<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Variant { pub kind: VariantKind, } @@ -3384,7 +3382,7 @@ impl Clean for ty::VariantDef { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum VariantKind { CLike, Tuple(Vec), @@ -3402,7 +3400,7 @@ impl Clean for hir::VariantData { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Span { pub filename: FileName, pub loline: usize, @@ -3448,7 +3446,7 @@ impl Clean for syntax_pos::Span { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Path { pub global: bool, pub res: Res, @@ -3471,7 +3469,7 @@ impl Clean for hir::Path { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArg { Lifetime(Lifetime), Type(Type), @@ -3488,7 +3486,7 @@ impl fmt::Display for GenericArg { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArgs { AngleBracketed { args: Vec, @@ -3528,7 +3526,7 @@ impl Clean for hir::GenericArgs { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct PathSegment { pub name: String, pub args: GenericArgs, @@ -3553,7 +3551,6 @@ fn strip_type(ty: Type) -> Type { } Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), - Type::Unique(inner_ty) => Type::Unique(Box::new(strip_type(*inner_ty))), Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), Type::BorrowedRef { lifetime, mutability, type_ } => { Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } @@ -3625,7 +3622,7 @@ impl Clean for InternedString { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Typedef { pub type_: Type, pub generics: Generics, @@ -3649,7 +3646,7 @@ impl Clean for doctree::Typedef<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Existential { pub bounds: Vec, pub generics: Generics, @@ -3673,7 +3670,7 @@ impl Clean for doctree::Existential<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct BareFunctionDecl { pub unsafety: hir::Unsafety, pub generic_params: Vec, @@ -3695,7 +3692,7 @@ impl Clean for hir::BareFnTy { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Static { pub type_: Type, pub mutability: Mutability, @@ -3725,7 +3722,7 @@ impl Clean for doctree::Static<'_> { } } -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Constant { pub type_: Type, pub expr: String, @@ -3749,7 +3746,7 @@ impl Clean for doctree::Constant<'_> { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] pub enum Mutability { Mutable, Immutable, @@ -3764,7 +3761,7 @@ impl Clean for hir::Mutability { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Copy, Debug, Hash)] pub enum ImplPolarity { Positive, Negative, @@ -3779,7 +3776,7 @@ impl Clean for hir::ImplPolarity { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Impl { pub unsafety: hir::Unsafety, pub generics: Generics, @@ -4003,7 +4000,7 @@ impl Clean> for doctree::Import<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub enum Import { // use source as str; Simple(String, ImportSource), @@ -4011,7 +4008,7 @@ pub enum Import { Glob(ImportSource) } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ImportSource { pub path: Path, pub did: Option, @@ -4227,7 +4224,7 @@ fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Macro { pub source: String, pub imported_from: Option, @@ -4256,7 +4253,7 @@ impl Clean for doctree::Macro<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct ProcMacro { pub kind: MacroKind, pub helpers: Vec, @@ -4280,7 +4277,7 @@ impl Clean for doctree::ProcMacro<'_> { } } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Stability { pub level: stability::StabilityLevel, pub feature: Option, @@ -4290,7 +4287,7 @@ pub struct Stability { pub issue: Option, } -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, Debug)] pub struct Deprecation { pub since: Option, pub note: Option, @@ -4340,13 +4337,13 @@ impl Clean for attr::Deprecation { /// An type binding on an associated type (e.g., `A = Bar` in `Foo` or /// `A: Send + Sync` in `Foo`). -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeBinding { pub name: String, pub kind: TypeBindingKind, } -#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum TypeBindingKind { Equality { ty: Type, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 51deb4e9b9747..2557b8d1627c0 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -78,7 +78,7 @@ impl Module<'hir> { } } -#[derive(Debug, Clone, RustcEncodable, RustcDecodable, Copy)] +#[derive(Debug, Clone, Copy)] pub enum StructType { /// A braced struct Plain, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fa3bc3f5f4f8b..9e5cc03b83123 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -737,9 +737,6 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } } - clean::Unique(..) => { - panic!("should have been cleaned") - } } } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 3f3f4c85e81fc..5f1a1b31616c1 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -110,7 +110,6 @@ impl From for ItemType { clean::TypeKind::Module => ItemType::Module, clean::TypeKind::Static => ItemType::Static, clean::TypeKind::Const => ItemType::Constant, - clean::TypeKind::Variant => ItemType::Variant, clean::TypeKind::Typedef => ItemType::Typedef, clean::TypeKind::Foreign => ItemType::ForeignType, clean::TypeKind::Macro => ItemType::Macro, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f0aff961c6751..2080637ecb402 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -5188,9 +5188,6 @@ fn collect_paths_for_type(first_ty: clean::Type) -> Vec { clean::Type::Array(ty, _) => { work.push_back(*ty); }, - clean::Type::Unique(ty) => { - work.push_back(*ty); - }, clean::Type::RawPointer(_, ty) => { work.push_back(*ty); }, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 7a8b088020c53..ba423300e0277 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -42,8 +42,6 @@ extern crate test as testing; #[macro_use] extern crate log; extern crate rustc_errors as errors; -extern crate serialize as rustc_serialize; // used by deriving - use std::default::Default; use std::env; use std::panic; From 07c5e2b310bf20fdccedc6a927f1417cb9ddc7fa Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 22 Jun 2019 13:00:17 -0700 Subject: [PATCH 02/12] Use a more efficient iteration order for forward dataflow Currently, dataflow begins by visiting each block in order of ID (`BasicBlock(0)`, `BasicBlock(1)`, etc.). This PR changes that initial iteration to reverse post-order. This ensures that the effects of all predecessors will be applied before a basic block is visited if the CFG has no back-edges, and should result in less total iterations even when back-edges exist. This should not change the results of dataflow analysis. The current ordering for basic blocks is pretty close to RPO already--`BasicBlock(0)` is already the start block, so the gains from this are pretty small, especially since we need to do an extra traversal up front. Note that some basic blocks are unreachable from the `START_BLOCK` during dataflow. We add these blocks to the work queue as well to preserve the original behavior. --- src/librustc_mir/dataflow/mod.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 80f65a9c8d04e..6cdd9de8b954d 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -228,9 +228,25 @@ where BD: BitDenotation<'tcx>, { fn walk_cfg(&mut self, in_out: &mut BitSet) { - let mut dirty_queue: WorkQueue = - WorkQueue::with_all(self.builder.body.basic_blocks().len()); let body = self.builder.body; + + // Initialize the dirty queue in reverse post-order. This makes it more likely that the + // entry state for each basic block will have the effects of its predecessors applied + // before it is processed. In fact, for CFGs without back edges, this guarantees that + // dataflow will converge in exactly `N` iterations, where `N` is the number of basic + // blocks. + let mut dirty_queue: WorkQueue = + WorkQueue::with_none(body.basic_blocks().len()); + for (bb, _) in traversal::reverse_postorder(body) { + dirty_queue.insert(bb); + } + + // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will + // be processed after the ones added above. + for bb in body.basic_blocks().indices() { + dirty_queue.insert(bb); + } + while let Some(bb) = dirty_queue.pop() { let (on_entry, trans) = self.builder.flow_state.sets.get_mut(bb.index()); debug_assert!(in_out.words().len() == on_entry.words().len()); From e2479e263ef1135dcd1318cce51ee8fafeae62ae Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 22 Jun 2019 13:27:16 -0700 Subject: [PATCH 03/12] Use more efficient iteration order for backward dataflow This applies the same basic principle as #62062 to the reverse dataflow analysis used to compute liveness information. It is functionally equivalent, except that post-order is used instead of reverse post-order. Some `mir::Body`s contain basic blocks which are not reachable from the `START_BLOCK`. We need to add them to the work queue as well to preserve the original semantics. --- src/librustc_mir/util/liveness.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index cf0fc09472b6c..8ead571d9664d 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -75,9 +75,24 @@ pub fn liveness_of_locals<'tcx>( let mut bits = LiveVarSet::new_empty(num_live_vars); - // queue of things that need to be re-processed, and a set containing - // the things currently in the queue - let mut dirty_queue: WorkQueue = WorkQueue::with_all(body.basic_blocks().len()); + // The dirty queue contains the set of basic blocks whose entry sets have changed since they + // were last processed. At the start of the analysis, we initialize the queue in post-order to + // make it more likely that the entry set for a given basic block will have the effects of all + // its successors in the CFG applied before it is processed. + // + // FIXME(ecstaticmorse): Reverse post-order on the reverse CFG may generate a better iteration + // order when cycles are present, but the overhead of computing the reverse CFG may outweigh + // any benefits. Benchmark this and find out. + let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks().len()); + for (bb, _) in traversal::postorder(body) { + dirty_queue.insert(bb); + } + + // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will + // be processed after the ones added above. + for bb in body.basic_blocks().indices() { + dirty_queue.insert(bb); + } let predecessors = body.predecessors(); From 47551b1513f24ec695a6fc05326044d74a64e156 Mon Sep 17 00:00:00 2001 From: lcolaholicl Date: Sun, 30 Jun 2019 02:02:03 +0900 Subject: [PATCH 04/12] Fix a typo Fix a typo in `libcore/char/methods.rs` --- src/libcore/char/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 722c4c805168f..b1f43ef99dd99 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -337,7 +337,7 @@ impl char { /// ``` /// // as chars /// let eastern = '東'; - /// let capitol = '京'; + /// let capital = '京'; /// /// // both can be represented as three bytes /// assert_eq!(3, eastern.len_utf8()); From 1fd64cf9b5772020b0af034318236aa3db54553e Mon Sep 17 00:00:00 2001 From: lcolaholicl Date: Sun, 30 Jun 2019 02:46:45 +0900 Subject: [PATCH 05/12] fix the same typo in doctest --- src/libcore/char/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index b1f43ef99dd99..e843303380ad0 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -341,12 +341,12 @@ impl char { /// /// // both can be represented as three bytes /// assert_eq!(3, eastern.len_utf8()); - /// assert_eq!(3, capitol.len_utf8()); + /// assert_eq!(3, capital.len_utf8()); /// /// // as a &str, these two are encoded in UTF-8 /// let tokyo = "東京"; /// - /// let len = eastern.len_utf8() + capitol.len_utf8(); + /// let len = eastern.len_utf8() + capital.len_utf8(); /// /// // we can see that they take six bytes total... /// assert_eq!(6, tokyo.len()); From ce1d95af4c1b179536c3c0daccd62946ef20b006 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 29 Jun 2019 21:38:26 +0200 Subject: [PATCH 06/12] Always parse 'async unsafe fn' + properly ban in 2015. --- src/librustc_passes/ast_validation.rs | 7 ----- src/libsyntax/parse/parser.rs | 26 +++++++++++------ src/test/ui/async-await/async-await.rs | 13 +++++++-- .../edition-deny-async-fns-2015.rs | 6 ++++ .../edition-deny-async-fns-2015.stderr | 28 +++++++++++-------- src/test/ui/async-await/no-unsafe-async.rs | 11 ++++++++ .../ui/async-await/no-unsafe-async.stderr | 14 ++++++++++ 7 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/async-await/no-unsafe-async.rs create mode 100644 src/test/ui/async-await/no-unsafe-async.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2da9c5adf9baf..560635962995c 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -837,13 +837,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { the relevant `fold_*()` method in `PlaceholderExpander`?"); } - fn visit_fn_header(&mut self, header: &'a FnHeader) { - if header.asyncness.node.is_async() && self.session.rust_2015() { - struct_span_err!(self.session, header.asyncness.span, E0670, - "`async fn` is not permitted in the 2015 edition").emit(); - } - } - fn visit_impl_item(&mut self, ii: &'a ImplItem) { match ii.node { ImplItemKind::Method(ref sig, _) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc206580e3811..696b5f48385e7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5734,9 +5734,12 @@ impl<'a> Parser<'a> { { let is_const_fn = self.eat_keyword(kw::Const); let const_span = self.prev_span; - let unsafety = self.parse_unsafety(); let asyncness = self.parse_asyncness(); + if let IsAsync::Async { .. } = asyncness { + self.ban_async_in_2015(self.prev_span); + } let asyncness = respan(self.prev_span, asyncness); + let unsafety = self.parse_unsafety(); let (constness, unsafety, abi) = if is_const_fn { (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { @@ -7254,13 +7257,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - if self.token.span.rust_2015() { - self.diagnostic().struct_span_err_with_code( - async_span, - "`async fn` is not permitted in the 2015 edition", - DiagnosticId::Error("E0670".into()) - ).emit(); - } + self.ban_async_in_2015(async_span); return Ok(Some(item)); } } @@ -7534,6 +7531,19 @@ impl<'a> Parser<'a> { self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) } + /// We are parsing `async fn`. If we are on Rust 2015, emit an error. + fn ban_async_in_2015(&self, async_span: Span) { + if async_span.rust_2015() { + self.diagnostic() + .struct_span_err_with_code( + async_span, + "`async fn` is not permitted in the 2015 edition", + DiagnosticId::Error("E0670".into()) + ) + .emit(); + } + } + /// Parses a foreign item. crate fn parse_foreign_item(&mut self) -> PResult<'a, ForeignItem> { maybe_whole!(self, NtForeignItem, |ni| ni); diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs index 38261ca4570eb..0eae1467fbfa0 100644 --- a/src/test/ui/async-await/async-await.rs +++ b/src/test/ui/async-await/async-await.rs @@ -134,11 +134,15 @@ trait Bar { } impl Foo { - async fn async_method(x: u8) -> u8 { + async fn async_assoc_item(x: u8) -> u8 { unsafe { unsafe_async_fn(x).await } } + + async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 { + unsafe_async_fn(x).await + } } fn test_future_yields_once_then_returns(f: F) @@ -180,12 +184,17 @@ fn main() { async_fn, generic_async_fn, async_fn_with_internal_borrow, - Foo::async_method, + Foo::async_assoc_item, |x| { async move { unsafe { unsafe_async_fn(x).await } } }, + |x| { + async move { + unsafe { Foo::async_unsafe_assoc_item(x).await } + } + }, } test_with_borrow! { async_block_with_borrow_named_lifetime, diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs index e1111f9e0e4b9..a5bc181015475 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -28,6 +28,12 @@ fn main() { async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition } + accept_item! { + impl Foo { + async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition + } + } + let inside_closure = || { async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition }; diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index 05a06124dc220..efb4462095d0d 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -23,7 +23,19 @@ LL | async fn async_baz() { | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:32:9 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^ + +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/edition-deny-async-fns-2015.rs:38:9 | LL | async fn bar() {} | ^^^^^ @@ -35,10 +47,10 @@ LL | async fn foo() {} | ^^^^^ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:16:5 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 | -LL | async fn foo() {} - | ^^^^^ +LL | async fn bar() {} + | ^^^^^ error[E0706]: trait fns cannot be declared `async` --> $DIR/edition-deny-async-fns-2015.rs:20:5 @@ -46,12 +58,6 @@ error[E0706]: trait fns cannot be declared `async` LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ -error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} - | ^^^^^ - -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0670`. diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs new file mode 100644 index 0000000000000..81e0cd799ad70 --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.rs @@ -0,0 +1,11 @@ +// edition:2018 + +struct S; + +impl S { + #[cfg(FALSE)] + unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found `async` +} + +#[cfg(FALSE)] +unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found `async` diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr new file mode 100644 index 0000000000000..c339c7c3bf5bf --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -0,0 +1,14 @@ +error: expected one of `extern` or `fn`, found `async` + --> $DIR/no-unsafe-async.rs:7:12 + | +LL | unsafe async fn g() {} + | ^^^^^ expected one of `extern` or `fn` here + +error: expected one of `extern`, `fn`, or `{`, found `async` + --> $DIR/no-unsafe-async.rs:11:8 + | +LL | unsafe async fn f() {} + | ^^^^^ expected one of `extern`, `fn`, or `{` here + +error: aborting due to 2 previous errors + From c0fb34795a37c8e26d4d8d1bbccaa011b922a5b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 18:29:39 +0200 Subject: [PATCH 07/12] before_exec actually will only get deprecated with 1.37 --- RELEASES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index b6e2171f6eef9..5ceeea8d037cb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -309,9 +309,9 @@ Misc Compatibility Notes ------------------- -- [`Command::before_exec` is now deprecated in favor of the - unsafe method `Command::pre_exec`.][58059] -- [Use of `ATOMIC_{BOOL, ISIZE, USIZE}_INIT` is now deprecated.][57425] As you +- [`Command::before_exec` is being replaced by the unsafe method + `Command::pre_exec`][58059] and will be deprecated with Rust 1.37.0. +- [Use of `ATOMIC_{BOOL, ISIZE, USIZE}_INIT` is now deprecated][57425] as you can now use `const` functions in `static` variables. [58370]: https://github.com/rust-lang/rust/pull/58370/ From b613ef143641382f7474f9ef2260e276514f3862 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 29 Jun 2019 13:53:46 +0100 Subject: [PATCH 08/12] Extend the #[must_use] lint to boxed types --- src/librustc_lint/unused.rs | 20 +++++++++++++++----- src/libstd/panicking.rs | 4 +++- src/test/ui/lint/must_use-trait.rs | 5 +++++ src/test/ui/lint/must_use-trait.stderr | 10 ++++++++-- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index b5c5fc0608b95..2481c9d02837c 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } let ty = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, ""); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", ""); let mut fn_warned = false; let mut op_warned = false; @@ -133,6 +133,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty: Ty<'tcx>, expr: &hir::Expr, span: Span, + descr_pre_path: &str, descr_post_path: &str, ) -> bool { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( @@ -142,14 +143,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } match ty.sty { - ty::Adt(def, _) => check_must_use_def(cx, def.did, span, "", descr_post_path), + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre_path = format!("{}boxed ", descr_pre_path); + check_must_use_ty(cx, boxed_ty, expr, span, &descr_pre_path, descr_post_path) + } + ty::Adt(def, _) => { + check_must_use_def(cx, def.did, span, descr_pre_path, descr_post_path) + } ty::Opaque(def, _) => { let mut has_emitted = false; for (predicate, _) in &cx.tcx.predicates_of(def).predicates { if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; - if check_must_use_def(cx, def_id, span, "implementer of ", "") { + let descr_pre = format!("{}implementer of ", descr_pre_path); + if check_must_use_def(cx, def_id, span, &descr_pre, descr_post_path) { has_emitted = true; break; } @@ -162,7 +171,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for predicate in binder.skip_binder().iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { let def_id = trait_ref.def_id; - if check_must_use_def(cx, def_id, span, "", " trait object") { + let descr_post = " trait object"; + if check_must_use_def(cx, def_id, span, descr_pre_path, descr_post) { has_emitted = true; break; } @@ -181,7 +191,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { let descr_post_path = &format!(" in tuple element {}", i); let span = *spans.get(i).unwrap_or(&span); - if check_must_use_ty(cx, ty, expr, span, descr_post_path) { + if check_must_use_ty(cx, ty, expr, span, descr_pre_path, descr_post_path) { has_emitted = true; } } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 9ef42063f9412..797d85e941d96 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -103,7 +103,9 @@ pub fn set_hook(hook: Box) + 'static + Sync + Send>) { HOOK_LOCK.write_unlock(); if let Hook::Custom(ptr) = old_hook { - Box::from_raw(ptr); + #[allow(unused_must_use)] { + Box::from_raw(ptr); + } } } } diff --git a/src/test/ui/lint/must_use-trait.rs b/src/test/ui/lint/must_use-trait.rs index 23df4fa6132d3..fb6f5384bbea1 100644 --- a/src/test/ui/lint/must_use-trait.rs +++ b/src/test/ui/lint/must_use-trait.rs @@ -17,6 +17,11 @@ fn get_critical() -> impl NotSoCritical + Critical + DecidedlyUnimportant { Anon {} } +fn get_boxed_critical() -> Box { + Box::new(Anon {}) +} + fn main() { get_critical(); //~ ERROR unused implementer of `Critical` that must be used + get_boxed_critical(); //~ ERROR unused boxed `Critical` trait object that must be used } diff --git a/src/test/ui/lint/must_use-trait.stderr b/src/test/ui/lint/must_use-trait.stderr index 7e2b2f67964ac..124d4d42a7466 100644 --- a/src/test/ui/lint/must_use-trait.stderr +++ b/src/test/ui/lint/must_use-trait.stderr @@ -1,5 +1,5 @@ error: unused implementer of `Critical` that must be used - --> $DIR/must_use-trait.rs:21:5 + --> $DIR/must_use-trait.rs:25:5 | LL | get_critical(); | ^^^^^^^^^^^^^^^ @@ -10,5 +10,11 @@ note: lint level defined here LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unused boxed `Critical` trait object that must be used + --> $DIR/must_use-trait.rs:26:5 + | +LL | get_boxed_critical(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors From d066f19a7907f36adef1e2d8704dc15e08c89ced Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 29 Jun 2019 14:57:12 +0100 Subject: [PATCH 09/12] Improve error messages for boxed trait objects in tuples --- src/librustc_lint/unused.rs | 10 +++++----- src/test/ui/lint/must_use-trait.rs | 12 ++++++++++++ src/test/ui/lint/must_use-trait.stderr | 24 +++++++++++++++++++++--- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 2481c9d02837c..3fbd7db765b70 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -145,8 +145,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { match ty.sty { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); - let descr_pre_path = format!("{}boxed ", descr_pre_path); - check_must_use_ty(cx, boxed_ty, expr, span, &descr_pre_path, descr_post_path) + let descr_pre_path = &format!("{}boxed ", descr_pre_path); + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre_path, descr_post_path) } ty::Adt(def, _) => { check_must_use_def(cx, def.did, span, descr_pre_path, descr_post_path) @@ -157,8 +157,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; - let descr_pre = format!("{}implementer of ", descr_pre_path); - if check_must_use_def(cx, def_id, span, &descr_pre, descr_post_path) { + let descr_pre = &format!("{}implementer of ", descr_pre_path); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post_path) { has_emitted = true; break; } @@ -171,7 +171,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for predicate in binder.skip_binder().iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { let def_id = trait_ref.def_id; - let descr_post = " trait object"; + let descr_post = &format!(" trait object{}", descr_post_path); if check_must_use_def(cx, def_id, span, descr_pre_path, descr_post) { has_emitted = true; break; diff --git a/src/test/ui/lint/must_use-trait.rs b/src/test/ui/lint/must_use-trait.rs index fb6f5384bbea1..0aa751443a080 100644 --- a/src/test/ui/lint/must_use-trait.rs +++ b/src/test/ui/lint/must_use-trait.rs @@ -21,7 +21,19 @@ fn get_boxed_critical() -> Box { Box::new(Anon {}) } +fn get_nested_boxed_critical() -> Box> { + Box::new(Box::new(Anon {})) +} + +fn get_critical_tuple() -> (u32, Box, impl Critical, ()) { + (0, get_boxed_critical(), get_critical(), ()) +} + fn main() { get_critical(); //~ ERROR unused implementer of `Critical` that must be used get_boxed_critical(); //~ ERROR unused boxed `Critical` trait object that must be used + get_nested_boxed_critical(); + //~^ ERROR unused boxed boxed `Critical` trait object that must be used + get_critical_tuple(); //~ ERROR unused boxed `Critical` trait object in tuple element 1 + //~^ ERROR unused implementer of `Critical` in tuple element 2 } diff --git a/src/test/ui/lint/must_use-trait.stderr b/src/test/ui/lint/must_use-trait.stderr index 124d4d42a7466..be74362e29d62 100644 --- a/src/test/ui/lint/must_use-trait.stderr +++ b/src/test/ui/lint/must_use-trait.stderr @@ -1,5 +1,5 @@ error: unused implementer of `Critical` that must be used - --> $DIR/must_use-trait.rs:25:5 + --> $DIR/must_use-trait.rs:33:5 | LL | get_critical(); | ^^^^^^^^^^^^^^^ @@ -11,10 +11,28 @@ LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ error: unused boxed `Critical` trait object that must be used - --> $DIR/must_use-trait.rs:26:5 + --> $DIR/must_use-trait.rs:34:5 | LL | get_boxed_critical(); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: unused boxed boxed `Critical` trait object that must be used + --> $DIR/must_use-trait.rs:35:5 + | +LL | get_nested_boxed_critical(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unused boxed `Critical` trait object in tuple element 1 that must be used + --> $DIR/must_use-trait.rs:37:5 + | +LL | get_critical_tuple(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unused implementer of `Critical` in tuple element 2 that must be used + --> $DIR/must_use-trait.rs:37:5 + | +LL | get_critical_tuple(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors From 75f31e78b8a892f6b901f8247684f062be1eb640 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 29 Jun 2019 16:51:44 +0100 Subject: [PATCH 10/12] Fix run-pass tests --- src/test/run-pass/issues/issue-30530.rs | 4 +++- src/test/run-pass/panics/panic-handler-flail-wildly.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/issues/issue-30530.rs b/src/test/run-pass/issues/issue-30530.rs index e837fc81721a8..111fb8aa506a4 100644 --- a/src/test/run-pass/issues/issue-30530.rs +++ b/src/test/run-pass/issues/issue-30530.rs @@ -12,7 +12,9 @@ pub enum Handler { } fn main() { - take(Handler::Default, Box::new(main)); + #[allow(unused_must_use)] { + take(Handler::Default, Box::new(main)); + } } #[inline(never)] diff --git a/src/test/run-pass/panics/panic-handler-flail-wildly.rs b/src/test/run-pass/panics/panic-handler-flail-wildly.rs index ebe4f70378cf0..6badd203842ff 100644 --- a/src/test/run-pass/panics/panic-handler-flail-wildly.rs +++ b/src/test/run-pass/panics/panic-handler-flail-wildly.rs @@ -1,5 +1,7 @@ // run-pass + #![allow(stable_features)] +#![allow(unused_must_use)] // ignore-emscripten no threads support From 400fd6055fea43ccd89769a4ddb85586c70bf8ae Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 30 Jun 2019 18:18:44 +0100 Subject: [PATCH 11/12] Update miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 945f007c0d305..72b2e1045d642 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 945f007c0d305c3ec069b5e5d911ef783f6d70e7 +Subproject commit 72b2e1045d642c517347c421b1db92e34c22a70d From 76f5b50716d609d09e53cf537be54a42bd0f007d Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 29 Jun 2019 16:23:15 +0100 Subject: [PATCH 12/12] Extend #[must_use] lint to arrays --- src/librustc_lint/unused.rs | 48 +++++++++++++++++++------- src/test/ui/lint/must_use-array.rs | 47 +++++++++++++++++++++++++ src/test/ui/lint/must_use-array.stderr | 44 +++++++++++++++++++++++ 3 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/lint/must_use-array.rs create mode 100644 src/test/ui/lint/must_use-array.stderr diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 3fbd7db765b70..2db2e0bc0da96 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { } let ty = cx.tables.expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", ""); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", false); let mut fn_warned = false; let mut op_warned = false; @@ -133,8 +133,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty: Ty<'tcx>, expr: &hir::Expr, span: Span, - descr_pre_path: &str, - descr_post_path: &str, + descr_pre: &str, + descr_post: &str, + plural: bool, ) -> bool { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( cx.tcx.hir().get_module_parent(expr.hir_id), ty) @@ -142,14 +143,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return true; } + let plural_suffix = if plural { "s" } else { "" }; + match ty.sty { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); - let descr_pre_path = &format!("{}boxed ", descr_pre_path); - check_must_use_ty(cx, boxed_ty, expr, span, descr_pre_path, descr_post_path) + let descr_pre = &format!("{}boxed ", descr_pre); + check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural) } ty::Adt(def, _) => { - check_must_use_def(cx, def.did, span, descr_pre_path, descr_post_path) + check_must_use_def(cx, def.did, span, descr_pre, descr_post) } ty::Opaque(def, _) => { let mut has_emitted = false; @@ -157,8 +160,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; - let descr_pre = &format!("{}implementer of ", descr_pre_path); - if check_must_use_def(cx, def_id, span, descr_pre, descr_post_path) { + let descr_pre = &format!( + "{}implementer{} of ", + descr_pre, + plural_suffix, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { has_emitted = true; break; } @@ -171,8 +178,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { for predicate in binder.skip_binder().iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { let def_id = trait_ref.def_id; - let descr_post = &format!(" trait object{}", descr_post_path); - if check_must_use_def(cx, def_id, span, descr_pre_path, descr_post) { + let descr_post = &format!( + " trait object{}{}", + plural_suffix, + descr_post, + ); + if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { has_emitted = true; break; } @@ -189,14 +200,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { vec![] }; for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { - let descr_post_path = &format!(" in tuple element {}", i); + let descr_post = &format!(" in tuple element {}", i); let span = *spans.get(i).unwrap_or(&span); - if check_must_use_ty(cx, ty, expr, span, descr_pre_path, descr_post_path) { + if check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, plural) { has_emitted = true; } } has_emitted } + ty::Array(ty, len) => match len.assert_usize(cx.tcx) { + // If the array is definitely non-empty, we can do `#[must_use]` checking. + Some(n) if n != 0 => { + let descr_pre = &format!( + "{}array{} of ", + descr_pre, + plural_suffix, + ); + check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, true) + } + // Otherwise, we don't lint, to avoid false positives. + _ => false, + } _ => false, } } diff --git a/src/test/ui/lint/must_use-array.rs b/src/test/ui/lint/must_use-array.rs new file mode 100644 index 0000000000000..97825dd2f6c43 --- /dev/null +++ b/src/test/ui/lint/must_use-array.rs @@ -0,0 +1,47 @@ +#![deny(unused_must_use)] + +#[must_use] +struct S; + +struct A; + +#[must_use] +trait T {} + +impl T for A {} + +fn empty() -> [S; 0] { + [] +} + +fn singleton() -> [S; 1] { + [S] +} + +fn many() -> [S; 4] { + [S, S, S, S] +} + +fn array_of_impl_trait() -> [impl T; 2] { + [A, A] +} + +fn impl_array() -> [(u8, Box); 2] { + [(0, Box::new(A)), (0, Box::new(A))] +} + +fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] { + [[[S], [S]]] +} + +fn main() { + empty(); // ok + singleton(); //~ ERROR unused array of `S` that must be used + many(); //~ ERROR unused array of `S` that must be used + ([S], 0, ()); //~ ERROR unused array of `S` in tuple element 0 that must be used + array_of_impl_trait(); //~ ERROR unused array of implementers of `T` that must be used + impl_array(); + //~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used + array_of_arrays_of_arrays(); + //~^ ERROR unused array of arrays of arrays of `S` that must be used +} diff --git a/src/test/ui/lint/must_use-array.stderr b/src/test/ui/lint/must_use-array.stderr new file mode 100644 index 0000000000000..a6dbd8e93d4d3 --- /dev/null +++ b/src/test/ui/lint/must_use-array.stderr @@ -0,0 +1,44 @@ +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:39:5 + | +LL | singleton(); + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/must_use-array.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:40:5 + | +LL | many(); + | ^^^^^^^ + +error: unused array of `S` in tuple element 0 that must be used + --> $DIR/must_use-array.rs:41:6 + | +LL | ([S], 0, ()); + | ^^^ + +error: unused array of implementers of `T` that must be used + --> $DIR/must_use-array.rs:42:5 + | +LL | array_of_impl_trait(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unused array of boxed `T` trait objects in tuple element 1 that must be used + --> $DIR/must_use-array.rs:43:5 + | +LL | impl_array(); + | ^^^^^^^^^^^^^ + +error: unused array of arrays of arrays of `S` that must be used + --> $DIR/must_use-array.rs:45:5 + | +LL | array_of_arrays_of_arrays(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors +