From 430553bc7766ecdbdb04113ef0137e6174e0dba2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Jan 2019 10:50:24 -0500 Subject: [PATCH 01/13] introduce `trait_def_id` method Co-Authored-By: Alexander Regueiro --- src/librustc/hir/mod.rs | 15 +++++++++++++++ src/librustc_typeck/astconv.rs | 22 ++++------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7e87171a5edf7..03a61dd03a9f5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -10,6 +10,7 @@ pub use self::PrimTy::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; +use errors::FatalError; use hir::def::Def; use hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; @@ -2053,6 +2054,20 @@ pub struct TraitRef { pub hir_ref_id: HirId, } +impl TraitRef { + /// Get the `DefId` of the referenced trait. It _must_ actually be a trait or trait alias. + pub fn trait_def_id(&self) -> DefId { + match self.path.def { + Def::Trait(did) => did, + Def::TraitAlias(did) => did, + Def::Err => { + FatalError.raise(); + } + _ => unreachable!(), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct PolyTraitRef { /// The `'a` in `<'a> Foo<&'a T>` diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 8e5eaa18b9de0..a841bbab5867b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2,7 +2,7 @@ //! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an //! instance of `AstConv`. -use errors::{Applicability, FatalError, DiagnosticId}; +use errors::{Applicability, DiagnosticId}; use hir::{self, GenericArg, GenericArgs}; use hir::def::Def; use hir::def_id::DefId; @@ -689,27 +689,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - let trait_def_id = self.trait_def_id(trait_ref); self.ast_path_to_mono_trait_ref(trait_ref.path.span, - trait_def_id, + trait_ref.trait_def_id(), self_ty, trait_ref.path.segments.last().unwrap()) } - /// Get the `DefId` of the given trait ref. It _must_ actually be a trait. - fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId { - let path = &trait_ref.path; - match path.def { - Def::Trait(trait_def_id) => trait_def_id, - Def::TraitAlias(alias_def_id) => alias_def_id, - Def::Err => { - FatalError.raise(); - } - _ => unreachable!(), - } - } - - /// The given trait ref must actually be a trait. + /// The given trait-ref must actually be a trait. pub(super) fn instantiate_poly_trait_ref_inner(&self, trait_ref: &hir::TraitRef, self_ty: Ty<'tcx>, @@ -717,7 +703,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { speculative: bool) -> (ty::PolyTraitRef<'tcx>, Option>) { - let trait_def_id = self.trait_def_id(trait_ref); + let trait_def_id = trait_ref.trait_def_id(); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); From 1336b8e8c7417fdde5384119a588a11ef0818cf3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Jan 2019 10:55:18 -0500 Subject: [PATCH 02/13] integrate trait aliases into def-paths / metadata Co-authored-by: Alexander Regueiro --- src/librustc/hir/map/def_collector.rs | 6 +-- src/librustc/hir/map/definitions.rs | 6 ++- src/librustc/traits/select.rs | 2 +- src/librustc/ty/item_path.rs | 1 + src/librustc/ty/mod.rs | 12 ------ src/librustc/ty/util.rs | 9 ++++ src/librustc/util/ppaux.rs | 1 + src/librustc_metadata/decoder.rs | 46 ++++++++++++++------- src/librustc_metadata/encoder.rs | 17 ++++++-- src/librustc_metadata/schema.rs | 13 ++++++ src/librustc_resolve/build_reduced_graph.rs | 3 ++ src/librustc_traits/lowering/mod.rs | 3 +- src/librustc_typeck/collect.rs | 2 +- 13 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index bc0a64ae7c5d8..c9b4b2bb99717 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -120,10 +120,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let def_data = match i.node { ItemKind::Impl(..) => DefPathData::Impl, ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()), + ItemKind::TraitAlias(..) => DefPathData::TraitAlias(i.ident.as_interned_str()), ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | - ItemKind::TraitAlias(..) | ItemKind::Existential(..) | - ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => - DefPathData::TypeNs(i.ident.as_interned_str()), + ItemKind::Existential(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | + ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 6b707dd2dcc80..1b7445199475c 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -373,7 +373,9 @@ pub enum DefPathData { /// GlobalMetaData identifies a piece of crate metadata that is global to /// a whole crate (as opposed to just one item). GlobalMetaData components /// are only supposed to show up right below the crate root. - GlobalMetaData(InternedString) + GlobalMetaData(InternedString), + /// A trait alias. + TraitAlias(InternedString), } #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, @@ -615,6 +617,7 @@ impl DefPathData { match *self { TypeNs(name) | Trait(name) | + TraitAlias(name) | AssocTypeInTrait(name) | AssocTypeInImpl(name) | AssocExistentialInImpl(name) | @@ -642,6 +645,7 @@ impl DefPathData { let s = match *self { TypeNs(name) | Trait(name) | + TraitAlias(name) | AssocTypeInTrait(name) | AssocTypeInImpl(name) | AssocExistentialInImpl(name) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6db6fe31fba70..4d478365e7276 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2154,7 +2154,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let def_id = obligation.predicate.def_id(); - if ty::is_trait_alias(self.tcx(), def_id) { + if self.tcx().is_trait_alias(def_id) { candidates.vec.push(TraitAliasCandidate(def_id.clone())); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 417e14054d24f..9328de4f6a0a1 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -311,6 +311,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::Misc | data @ DefPathData::TypeNs(..) | data @ DefPathData::Trait(..) | + data @ DefPathData::TraitAlias(..) | data @ DefPathData::AssocTypeInTrait(..) | data @ DefPathData::AssocTypeInImpl(..) | data @ DefPathData::AssocExistentialInImpl(..) | diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a2c96e7cf9f66..e2f696b0974a7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3178,18 +3178,6 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option, def_id: DefId) -> bool { - if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { - if let Node::Item(item) = tcx.hir().get(node_id) { - if let hir::ItemKind::TraitAlias(..) = item.node { - return true; - } - } - } - false -} - /// See `ParamEnv` struct definition for details. fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e989ef823e979..75fc0f716a2f6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -526,6 +526,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + /// True if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`). + pub fn is_trait_alias(self, def_id: DefId) -> bool { + if let DefPathData::TraitAlias(_) = self.def_key(def_id).disambiguated_data.data { + true + } else { + false + } + } + /// True if this def-id refers to the implicit constructor for /// a tuple struct like `struct Foo(u32)`. pub fn is_struct_constructor(self, def_id: DefId) -> bool { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 04e571863d42f..51e9192cd290d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -409,6 +409,7 @@ impl PrintContext { DefPathData::AssocTypeInImpl(_) | DefPathData::AssocExistentialInImpl(_) | DefPathData::Trait(_) | + DefPathData::TraitAlias(_) | DefPathData::Impl | DefPathData::TypeNs(_) => { break; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index dc8db5be5820a..1f07e8f478b5a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -418,6 +418,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Mod(_) => Def::Mod(did), EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), + EntryKind::TraitAlias(_) => Def::TraitAlias(did), EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), EntryKind::ForeignType => Def::ForeignTy(did), @@ -520,17 +521,26 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { - let data = match self.entry(item_id).kind { - EntryKind::Trait(data) => data.decode((self, sess)), - _ => bug!(), - }; - - ty::TraitDef::new(self.local_def_id(item_id), - data.unsafety, - data.paren_sugar, - data.has_auto_impl, - data.is_marker, - self.def_path_table.def_path_hash(item_id)) + match self.entry(item_id).kind { + EntryKind::Trait(data) => { + let data = data.decode((self, sess)); + ty::TraitDef::new(self.local_def_id(item_id), + data.unsafety, + data.paren_sugar, + data.has_auto_impl, + data.is_marker, + self.def_path_table.def_path_hash(item_id)) + }, + EntryKind::TraitAlias(_) => { + ty::TraitDef::new(self.local_def_id(item_id), + hir::Unsafety::Normal, + false, + false, + false, + self.def_path_table.def_path_hash(item_id)) + }, + _ => bug!("def-index does not refer to trait or trait alias"), + } } fn get_variant(&self, @@ -615,10 +625,13 @@ impl<'a, 'tcx> CrateMetadata { item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::GenericPredicates<'tcx> { - match self.entry(item_id).kind { - EntryKind::Trait(data) => data.decode(self).super_predicates.decode((self, tcx)), - _ => bug!(), - } + let super_predicates = match self.entry(item_id).kind { + EntryKind::Trait(data) => data.decode(self).super_predicates, + EntryKind::TraitAlias(data) => data.decode(self).super_predicates, + _ => bug!("def-index does not refer to trait or trait alias"), + }; + + super_predicates.decode((self, tcx)) } pub fn get_generics(&self, @@ -1014,7 +1027,8 @@ impl<'a, 'tcx> CrateMetadata { } def_key.parent.and_then(|parent_index| { match self.entry(parent_index).kind { - EntryKind::Trait(_) => Some(self.local_def_id(parent_index)), + EntryKind::Trait(_) | + EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)), _ => None, } }) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 032a4656efcda..2522469086f67 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1131,8 +1131,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { EntryKind::Impl(self.lazy(&data)) } - hir::ItemKind::Trait(..) | - hir::ItemKind::TraitAlias(..) => { + hir::ItemKind::Trait(..) => { let trait_def = tcx.trait_def(def_id); let data = TraitData { unsafety: trait_def.unsafety, @@ -1144,6 +1143,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { EntryKind::Trait(self.lazy(&data)) } + hir::ItemKind::TraitAlias(..) => { + let data = TraitAliasData { + super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), + }; + + EntryKind::TraitAlias(self.lazy(&data)) + } hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item), }; @@ -1217,6 +1223,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ItemKind::Impl(..) | hir::ItemKind::Existential(..) | hir::ItemKind::Trait(..) => Some(self.encode_generics(def_id)), + hir::ItemKind::TraitAlias(..) => Some(self.encode_generics(def_id)), _ => None, }, predicates: match item.node { @@ -1229,7 +1236,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ItemKind::Union(..) | hir::ItemKind::Impl(..) | hir::ItemKind::Existential(..) | - hir::ItemKind::Trait(..) => Some(self.encode_predicates(def_id)), + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates(def_id)), _ => None, }, @@ -1239,7 +1247,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // hack. (No reason not to expand it in the future if // necessary.) predicates_defined_on: match item.node { - hir::ItemKind::Trait(..) => Some(self.encode_predicates_defined_on(def_id)), + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates_defined_on(def_id)), _ => None, // not *wrong* for other kinds of items, but not needed }, diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 25f499bc31984..f3ff9747625f5 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -316,6 +316,7 @@ pub enum EntryKind<'tcx> { AssociatedType(AssociatedContainer), AssociatedExistential(AssociatedContainer), AssociatedConst(AssociatedContainer, ConstQualif, Lazy), + TraitAlias(Lazy>), } impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { @@ -370,6 +371,9 @@ impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { EntryKind::Trait(ref trait_data) => { trait_data.hash_stable(hcx, hasher); } + EntryKind::TraitAlias(ref trait_alias_data) => { + trait_alias_data.hash_stable(hcx, hasher); + } EntryKind::Impl(ref impl_data) => { impl_data.hash_stable(hcx, hasher); } @@ -474,6 +478,15 @@ impl_stable_hash_for!(struct TraitData<'tcx> { super_predicates }); +#[derive(RustcEncodable, RustcDecodable)] +pub struct TraitAliasData<'tcx> { + pub super_predicates: Lazy>, +} + +impl_stable_hash_for!(struct TraitAliasData<'tcx> { + super_predicates +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a452bbf0c9d54..28b80fe3aaf29 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -673,6 +673,9 @@ impl<'a> Resolver<'a> { } module.populated.set(true); } + Def::TraitAlias(..) => { + self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); + } Def::Struct(..) | Def::Union(..) => { self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 5502a1d186eee..9bdef3051e589 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -158,7 +158,8 @@ crate fn program_clauses_for<'a, 'tcx>( def_id: DefId, ) -> Clauses<'tcx> { match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id), + DefPathData::Trait(_) | + DefPathData::TraitAlias(_) => program_clauses_for_trait(tcx, def_id), DefPathData::Impl => program_clauses_for_impl(tcx, def_id), DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id), DefPathData::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx, def_id), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e0e173901ef38..66b2443af413a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -706,7 +706,7 @@ fn super_predicates_of<'a, 'tcx>( // In the case of trait aliases, however, we include all bounds in the where clause, // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` // as one of its "superpredicates". - let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id); + let is_trait_alias = tcx.is_trait_alias(trait_def_id); let superbounds2 = icx.type_parameter_bounds_in_generics( generics, item.id, self_param_ty, OnlySelfBounds(!is_trait_alias)); From b411994b3b9a571db486cb7de9ea06b071a22b6c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 10 Jan 2019 16:56:05 -0500 Subject: [PATCH 03/13] new trait alias tests Co-authored-by: Alexander Regueiro --- src/test/ui/issues/issue-56488.rs | 13 +++++++ .../lint-incoherent-auto-trait-objects.rs | 21 ++++++++++ .../lint-incoherent-auto-trait-objects.stderr | 39 +++++++++++++++++++ src/test/ui/traits/auxiliary/trait_alias.rs | 3 ++ src/test/ui/traits/trait-alias-cross-crate.rs | 17 ++++++++ .../ui/traits/trait-alias-cross-crate.stderr | 29 ++++++++++++++ 6 files changed, 122 insertions(+) create mode 100644 src/test/ui/issues/issue-56488.rs create mode 100644 src/test/ui/lint/lint-incoherent-auto-trait-objects.rs create mode 100644 src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr create mode 100644 src/test/ui/traits/auxiliary/trait_alias.rs create mode 100644 src/test/ui/traits/trait-alias-cross-crate.rs create mode 100644 src/test/ui/traits/trait-alias-cross-crate.stderr diff --git a/src/test/ui/issues/issue-56488.rs b/src/test/ui/issues/issue-56488.rs new file mode 100644 index 0000000000000..e2f3996927b7f --- /dev/null +++ b/src/test/ui/issues/issue-56488.rs @@ -0,0 +1,13 @@ +// run-pass + +#![feature(trait_alias)] + +mod alpha { + pub trait A {} + pub trait C = A; +} + +#[allow(unused_imports)] +use alpha::C; + +fn main() {} diff --git a/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs b/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs new file mode 100644 index 0000000000000..0d18965ee7338 --- /dev/null +++ b/src/test/ui/lint/lint-incoherent-auto-trait-objects.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +trait Foo {} + +impl Foo for dyn Send {} + +impl Foo for dyn Send + Send {} +//~^ ERROR conflicting implementations +//~| hard error + +impl Foo for dyn Send + Sync {} + +impl Foo for dyn Sync + Send {} +//~^ ERROR conflicting implementations +//~| hard error + +impl Foo for dyn Send + Sync + Send {} +//~^ ERROR conflicting implementations +//~| hard error + +fn main() {} diff --git a/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr b/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr new file mode 100644 index 0000000000000..928c92ef91655 --- /dev/null +++ b/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr @@ -0,0 +1,39 @@ +error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + 'static)`: (E0119) + --> $DIR/lint-incoherent-auto-trait-objects.rs:7:1 + | +LL | impl Foo for dyn Send {} + | --------------------- first implementation here +LL | +LL | impl Foo for dyn Send + Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)` + | + = note: #[deny(order_dependent_trait_objects)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 + +error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) + --> $DIR/lint-incoherent-auto-trait-objects.rs:13:1 + | +LL | impl Foo for dyn Send + Sync {} + | ---------------------------- first implementation here +LL | +LL | impl Foo for dyn Sync + Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 + +error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) + --> $DIR/lint-incoherent-auto-trait-objects.rs:17:1 + | +LL | impl Foo for dyn Sync + Send {} + | ---------------------------- first implementation here +... +LL | impl Foo for dyn Send + Sync + Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/traits/auxiliary/trait_alias.rs b/src/test/ui/traits/auxiliary/trait_alias.rs new file mode 100644 index 0000000000000..9e56b87e08813 --- /dev/null +++ b/src/test/ui/traits/auxiliary/trait_alias.rs @@ -0,0 +1,3 @@ +#![feature(trait_alias)] + +pub trait SendSync = Send + Sync; diff --git a/src/test/ui/traits/trait-alias-cross-crate.rs b/src/test/ui/traits/trait-alias-cross-crate.rs new file mode 100644 index 0000000000000..259fc4fa5d1ce --- /dev/null +++ b/src/test/ui/traits/trait-alias-cross-crate.rs @@ -0,0 +1,17 @@ +// aux-build:trait_alias.rs + +#![feature(trait_alias)] + +extern crate trait_alias; + +use std::rc::Rc; +use trait_alias::SendSync; + +fn use_alias() {} + +fn main() { + use_alias::(); + use_alias::>(); + //~^ ERROR `std::rc::Rc` cannot be sent between threads safely [E0277] + //~^^ ERROR `std::rc::Rc` cannot be shared between threads safely [E0277] +} diff --git a/src/test/ui/traits/trait-alias-cross-crate.stderr b/src/test/ui/traits/trait-alias-cross-crate.stderr new file mode 100644 index 0000000000000..972d213ac8f8f --- /dev/null +++ b/src/test/ui/traits/trait-alias-cross-crate.stderr @@ -0,0 +1,29 @@ +error[E0277]: `std::rc::Rc` cannot be sent between threads safely + --> $DIR/trait-alias-cross-crate.rs:14:5 + | +LL | use_alias::>(); + | ^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc` +note: required by `use_alias` + --> $DIR/trait-alias-cross-crate.rs:10:1 + | +LL | fn use_alias() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `std::rc::Rc` cannot be shared between threads safely + --> $DIR/trait-alias-cross-crate.rs:14:5 + | +LL | use_alias::>(); + | ^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc` cannot be shared between threads safely + | + = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` +note: required by `use_alias` + --> $DIR/trait-alias-cross-crate.rs:10:1 + | +LL | fn use_alias() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 28966e1a7ac509cebac4595e96f8d053b30fb946 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Jan 2019 15:20:56 +1100 Subject: [PATCH 04/13] Remove `TokenStream::Tree` variant. `TokenStream::Stream` can represent a token stream containing any number of token trees. `TokenStream::Tree` is the special case representing a single token tree. The latter doesn't occur all that often dynamically, so this commit removes it, which simplifies the code quite a bit. This change has mixed performance effects. - The size of `TokenStream` drops from 32 bytes to 8 bytes, and there is one less case for all the match statements. - The conversion of a `TokenTree` to a `TokenStream` now requires two allocations, for the creation of a single element Lrc>. (But a subsequent commit in this PR will reduce the main source of such conversions.) --- src/libsyntax/tokenstream.rs | 45 +++----------------------- src/libsyntax_ext/proc_macro_server.rs | 2 +- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index fb72ef9c956ce..95ff7728897e5 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -113,7 +113,7 @@ impl TokenTree { } pub fn joint(self) -> TokenStream { - TokenStream::Tree(self, Joint) + TokenStream::new(vec![(self, Joint)]) } /// Returns the opening delimiter as a token tree. @@ -146,7 +146,6 @@ impl TokenTree { #[derive(Clone, Debug)] pub enum TokenStream { Empty, - Tree(TokenTree, IsJoint), Stream(Lrc>), } @@ -154,7 +153,7 @@ pub type TreeAndJoint = (TokenTree, IsJoint); // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::() == 32); +static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::() == 8); #[derive(Clone, Copy, Debug, PartialEq)] pub enum IsJoint { @@ -201,7 +200,7 @@ impl TokenStream { impl From for TokenStream { fn from(tree: TokenTree) -> TokenStream { - TokenStream::Tree(tree, NonJoint) + TokenStream::new(vec![(tree, NonJoint)]) } } @@ -260,7 +259,6 @@ impl TokenStream { for stream in streams { match stream { TokenStream::Empty => {}, - TokenStream::Tree(tree, is_joint) => vec.push((tree, is_joint)), TokenStream::Stream(stream2) => vec.extend(stream2.iter().cloned()), } } @@ -269,13 +267,9 @@ impl TokenStream { } } - pub fn new(mut streams: Vec) -> TokenStream { + pub fn new(streams: Vec) -> TokenStream { match streams.len() { 0 => TokenStream::empty(), - 1 => { - let (tree, is_joint) = streams.pop().unwrap(); - TokenStream::Tree(tree, is_joint) - } _ => TokenStream::Stream(Lrc::new(streams)), } } @@ -283,7 +277,6 @@ impl TokenStream { pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec) { match self { TokenStream::Empty => {} - TokenStream::Tree(tree, is_joint) => vec.push((tree, is_joint)), TokenStream::Stream(stream) => vec.extend(stream.iter().cloned()), } } @@ -351,7 +344,6 @@ impl TokenStream { pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { match self { TokenStream::Empty => TokenStream::Empty, - TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(0, tree), is_joint), TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new( stream .iter() @@ -365,7 +357,6 @@ impl TokenStream { pub fn map TokenTree>(self, mut f: F) -> TokenStream { match self { TokenStream::Empty => TokenStream::Empty, - TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(tree), is_joint), TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new( stream .iter() @@ -378,7 +369,6 @@ impl TokenStream { fn first_tree_and_joint(&self) -> Option<(TokenTree, IsJoint)> { match self { TokenStream::Empty => None, - TokenStream::Tree(ref tree, is_joint) => Some((tree.clone(), *is_joint)), TokenStream::Stream(ref stream) => Some(stream.first().unwrap().clone()) } } @@ -386,13 +376,6 @@ impl TokenStream { fn last_tree_if_joint(&self) -> Option { match self { TokenStream::Empty => None, - TokenStream::Tree(ref tree, is_joint) => { - if *is_joint == Joint { - Some(tree.clone()) - } else { - None - } - } TokenStream::Stream(ref stream) => { if let (tree, Joint) = stream.last().unwrap() { Some(tree.clone()) @@ -422,7 +405,7 @@ impl TokenStreamBuilder { self.push_all_but_last_tree(&last_stream); let glued_span = last_span.to(span); let glued_tt = TokenTree::Token(glued_span, glued_tok); - let glued_tokenstream = TokenStream::Tree(glued_tt, is_joint); + let glued_tokenstream = TokenStream::new(vec![(glued_tt, is_joint)]); self.0.push(glued_tokenstream); self.push_all_but_first_tree(&stream); return @@ -441,7 +424,6 @@ impl TokenStreamBuilder { let len = streams.len(); match len { 1 => {} - 2 => self.0.push(TokenStream::Tree(streams[0].0.clone(), streams[0].1)), _ => self.0.push(TokenStream::Stream(Lrc::new(streams[0 .. len - 1].to_vec()))), } } @@ -452,7 +434,6 @@ impl TokenStreamBuilder { let len = streams.len(); match len { 1 => {} - 2 => self.0.push(TokenStream::Tree(streams[1].0.clone(), streams[1].1)), _ => self.0.push(TokenStream::Stream(Lrc::new(streams[1 .. len].to_vec()))), } } @@ -481,14 +462,6 @@ impl Cursor { pub fn next_with_joint(&mut self) -> Option { match self.stream { TokenStream::Empty => None, - TokenStream::Tree(ref tree, ref is_joint) => { - if self.index == 0 { - self.index = 1; - Some((tree.clone(), *is_joint)) - } else { - None - } - } TokenStream::Stream(ref stream) => { if self.index < stream.len() { self.index += 1; @@ -513,13 +486,6 @@ impl Cursor { pub fn look_ahead(&self, n: usize) -> Option { match self.stream { TokenStream::Empty => None, - TokenStream::Tree(ref tree, _) => { - if n == 0 && self.index == 0 { - Some(tree.clone()) - } else { - None - } - } TokenStream::Stream(ref stream) => stream[self.index ..].get(n).map(|(tree, _)| tree.clone()), } @@ -542,7 +508,6 @@ impl From for ThinTokenStream { fn from(stream: TokenStream) -> ThinTokenStream { ThinTokenStream(match stream { TokenStream::Empty => None, - TokenStream::Tree(tree, is_joint) => Some(Lrc::new(vec![(tree, is_joint)])), TokenStream::Stream(stream) => Some(stream), }) } diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index 158cbc791ef50..7de9b9343a8fa 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -269,7 +269,7 @@ impl ToInternal for TokenTree { }; let tree = tokenstream::TokenTree::Token(span, token); - TokenStream::Tree(tree, if joint { Joint } else { NonJoint }) + TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })]) } } From ce0d9949b817267e88e8d366a8cee929abf1e4ba Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Jan 2019 16:53:14 +1100 Subject: [PATCH 05/13] Remove `ThinTokenStream`. `TokenStream` is now almost identical to `ThinTokenStream`. This commit removes the latter, replacing it with the former. --- src/librustc/ich/impls_syntax.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/libsyntax/ast.rs | 8 ++--- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/mod.rs | 6 ++-- src/libsyntax/parse/parser.rs | 12 +++---- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/tokenstream.rs | 55 ++------------------------------ src/libsyntax/visit.rs | 2 +- 11 files changed, 23 insertions(+), 72 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 70ec72d73bc6c..de567183a3c05 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -258,7 +258,7 @@ for tokenstream::TokenTree { tokenstream::TokenTree::Delimited(span, delim, ref tts) => { span.hash_stable(hcx, hasher); std_hash::Hash::hash(&delim, hasher); - for sub_tt in tts.stream().trees() { + for sub_tt in tts.trees() { sub_tt.hash_stable(hcx, hasher); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5678f30dabccd..0fce166d828b0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1540,7 +1540,7 @@ impl KeywordIdents { _ => {}, } TokenTree::Delimited(_, _, tts) => { - self.check_tokens(cx, tts.stream()) + self.check_tokens(cx, tts) }, } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e3a8980a975c1..1e91f4adc36d7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -15,7 +15,7 @@ use rustc_target::spec::abi::Abi; use source_map::{dummy_spanned, respan, Spanned}; use symbol::{keywords, Symbol}; use syntax_pos::{Span, DUMMY_SP}; -use tokenstream::{ThinTokenStream, TokenStream}; +use tokenstream::TokenStream; use ThinVec; use rustc_data_structures::fx::FxHashSet; @@ -1216,7 +1216,7 @@ pub type Mac = Spanned; pub struct Mac_ { pub path: Path, pub delim: MacDelimiter, - pub tts: ThinTokenStream, + pub tts: TokenStream, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] @@ -1228,13 +1228,13 @@ pub enum MacDelimiter { impl Mac_ { pub fn stream(&self) -> TokenStream { - self.tts.stream() + self.tts.clone() } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct MacroDef { - pub tokens: ThinTokenStream, + pub tokens: TokenStream, pub legacy: bool, } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index d03563f8891aa..0f8ca5e7b9982 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -565,7 +565,7 @@ impl MetaItemKind { } Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => { tokens.next(); - tts.stream() + tts.clone() } _ => return Some(MetaItemKind::Word), }; diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c3124144009ab..c01e7f538b90d 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -748,7 +748,7 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, quoted: bool) -> Vec { let mut stmts = statements_mk_tt(cx, &TokenTree::open_tt(span.open, delim), false); - stmts.extend(statements_mk_tts(cx, tts.stream())); + stmts.extend(statements_mk_tts(cx, tts.clone())); stmts.extend(statements_mk_tt(cx, &TokenTree::close_tt(span.close, delim), false)); stmts } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8ac103856dcd1..a4c3b38f691ed 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -598,7 +598,7 @@ pub fn noop_fold_tt(tt: TokenTree, fld: &mut T) -> TokenTree { TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( DelimSpan::from_pair(fld.new_span(span.open), fld.new_span(span.close)), delim, - fld.fold_tts(tts.stream()).into(), + fld.fold_tts(tts).into(), ), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ba5676a65d7eb..759de578847a9 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -811,7 +811,7 @@ mod tests { ) if name_macro_rules.name == "macro_rules" && name_zip.name == "zip" => { - let tts = ¯o_tts.stream().trees().collect::>(); + let tts = ¯o_tts.trees().collect::>(); match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) { ( 3, @@ -820,7 +820,7 @@ mod tests { Some(&TokenTree::Delimited(_, second_delim, ref second_tts)), ) if macro_delim == token::Paren => { - let tts = &first_tts.stream().trees().collect::>(); + let tts = &first_tts.trees().collect::>(); match (tts.len(), tts.get(0), tts.get(1)) { ( 2, @@ -830,7 +830,7 @@ mod tests { if first_delim == token::Paren && ident.name == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), } - let tts = &second_tts.stream().trees().collect::>(); + let tts = &second_tts.trees().collect::>(); match (tts.len(), tts.get(0), tts.get(1)) { ( 2, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5c8ed94731afb..6df95d539affb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -46,7 +46,7 @@ use print::pprust; use ptr::P; use parse::PResult; use ThinVec; -use tokenstream::{self, DelimSpan, ThinTokenStream, TokenTree, TokenStream}; +use tokenstream::{self, DelimSpan, TokenTree, TokenStream}; use symbol::{Symbol, keywords}; use std::borrow::Cow; @@ -285,12 +285,12 @@ enum LastToken { } impl TokenCursorFrame { - fn new(sp: DelimSpan, delim: DelimToken, tts: &ThinTokenStream) -> Self { + fn new(sp: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { TokenCursorFrame { delim: delim, span: sp, open_delim: delim == token::NoDelim, - tree_cursor: tts.stream().into_trees(), + tree_cursor: tts.clone().into_trees(), close_delim: delim == token::NoDelim, last_token: LastToken::Was(None), } @@ -2325,7 +2325,7 @@ impl<'a> Parser<'a> { }) } - fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, ThinTokenStream)> { + fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> { let delim = match self.token { token::OpenDelim(delim) => delim, _ => { @@ -2345,7 +2345,7 @@ impl<'a> Parser<'a> { token::Brace => MacDelimiter::Brace, token::NoDelim => self.bug("unexpected no delimiter"), }; - Ok((delim, tts.stream().into())) + Ok((delim, tts.into())) } /// At the bottom (top?) of the precedence hierarchy, @@ -4633,7 +4633,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let tokens = if self.check(&token::OpenDelim(token::Brace)) { match self.parse_token_tree() { - TokenTree::Delimited(_, _, tts) => tts.stream(), + TokenTree::Delimited(_, _, tts) => tts, _ => unreachable!(), } } else if self.check(&token::OpenDelim(token::Paren)) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2ad3d3a6d6487..c53594032a00a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -807,7 +807,7 @@ pub trait PrintState<'a> { TokenTree::Delimited(_, delim, tts) => { self.writer().word(token_to_string(&token::OpenDelim(delim)))?; self.writer().space()?; - self.print_tts(tts.stream())?; + self.print_tts(tts)?; self.writer().space()?; self.writer().word(token_to_string(&token::CloseDelim(delim))) }, diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 95ff7728897e5..d5c362490ca6a 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -41,7 +41,7 @@ pub enum TokenTree { /// A single token Token(Span, token::Token), /// A delimited sequence of token trees - Delimited(DelimSpan, DelimToken, ThinTokenStream), + Delimited(DelimSpan, DelimToken, TokenStream), } impl TokenTree { @@ -62,8 +62,7 @@ impl TokenTree { (&TokenTree::Token(_, ref tk), &TokenTree::Token(_, ref tk2)) => tk == tk2, (&TokenTree::Delimited(_, delim, ref tts), &TokenTree::Delimited(_, delim2, ref tts2)) => { - delim == delim2 && - tts.stream().eq_unspanned(&tts2.stream()) + delim == delim2 && tts.eq_unspanned(&tts2) } (_, _) => false, } @@ -81,8 +80,7 @@ impl TokenTree { } (&TokenTree::Delimited(_, delim, ref tts), &TokenTree::Delimited(_, delim2, ref tts2)) => { - delim == delim2 && - tts.stream().probably_equal_for_proc_macro(&tts2.stream()) + delim == delim2 && tts.probably_equal_for_proc_macro(&tts2) } (_, _) => false, } @@ -492,41 +490,6 @@ impl Cursor { } } -/// The `TokenStream` type is large enough to represent a single `TokenTree` without allocation. -/// `ThinTokenStream` is smaller, but needs to allocate to represent a single `TokenTree`. -/// We must use `ThinTokenStream` in `TokenTree::Delimited` to avoid infinite size due to recursion. -#[derive(Debug, Clone)] -pub struct ThinTokenStream(Option>>); - -impl ThinTokenStream { - pub fn stream(&self) -> TokenStream { - self.clone().into() - } -} - -impl From for ThinTokenStream { - fn from(stream: TokenStream) -> ThinTokenStream { - ThinTokenStream(match stream { - TokenStream::Empty => None, - TokenStream::Stream(stream) => Some(stream), - }) - } -} - -impl From for TokenStream { - fn from(stream: ThinTokenStream) -> TokenStream { - stream.0.map(TokenStream::Stream).unwrap_or_else(TokenStream::empty) - } -} - -impl Eq for ThinTokenStream {} - -impl PartialEq for ThinTokenStream { - fn eq(&self, other: &ThinTokenStream) -> bool { - TokenStream::from(self.clone()) == TokenStream::from(other.clone()) - } -} - impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&pprust::tokens_to_string(self.clone())) @@ -545,18 +508,6 @@ impl Decodable for TokenStream { } } -impl Encodable for ThinTokenStream { - fn encode(&self, encoder: &mut E) -> Result<(), E::Error> { - TokenStream::from(self.clone()).encode(encoder) - } -} - -impl Decodable for ThinTokenStream { - fn decode(decoder: &mut D) -> Result { - TokenStream::decode(decoder).map(Into::into) - } -} - #[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct DelimSpan { pub open: Span, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 156546bbba94a..8cbd47ca70fde 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -832,7 +832,7 @@ pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { match tt { TokenTree::Token(_, tok) => visitor.visit_token(tok), - TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts.stream()), + TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts), } } From ba31d83adc839768ed8fab7dea79d9f6bd6c58ac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Jan 2019 11:58:38 +1100 Subject: [PATCH 06/13] Avoid some `TokenTree`-to-`TokenStream` conversions. This avoids some allocations. --- src/libsyntax/parse/parser.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6df95d539affb..537d536ec62c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -46,7 +46,7 @@ use print::pprust; use ptr::P; use parse::PResult; use ThinVec; -use tokenstream::{self, DelimSpan, TokenTree, TokenStream}; +use tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use symbol::{Symbol, keywords}; use std::borrow::Cow; @@ -280,8 +280,8 @@ struct TokenCursorFrame { /// on the parser. #[derive(Clone)] enum LastToken { - Collecting(Vec), - Was(Option), + Collecting(Vec), + Was(Option), } impl TokenCursorFrame { @@ -7677,7 +7677,7 @@ impl<'a> Parser<'a> { &mut self.token_cursor.stack[prev].last_token }; - // Pull our the toekns that we've collected from the call to `f` above + // Pull out the tokens that we've collected from the call to `f` above. let mut collected_tokens = match *last_token { LastToken::Collecting(ref mut v) => mem::replace(v, Vec::new()), LastToken::Was(_) => panic!("our vector went away?"), @@ -7696,10 +7696,9 @@ impl<'a> Parser<'a> { // call. In that case we need to record all the tokens we collected in // our parent list as well. To do that we push a clone of our stream // onto the previous list. - let stream = collected_tokens.into_iter().collect::(); match prev_collecting { Some(mut list) => { - list.push(stream.clone()); + list.extend(collected_tokens.iter().cloned()); list.extend(extra_token); *last_token = LastToken::Collecting(list); } @@ -7708,7 +7707,7 @@ impl<'a> Parser<'a> { } } - Ok((ret?, stream)) + Ok((ret?, TokenStream::new(collected_tokens))) } pub fn parse_item(&mut self) -> PResult<'a, Option>> { From 728572440171d8d9c0557c89c3d71cc8d7cf6c2e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Jan 2019 10:36:54 +1100 Subject: [PATCH 07/13] Make `TokenStream` use `Option`. Because that's the more typical way of representing an all-or-nothing type. --- src/libsyntax/tokenstream.rs | 95 +++++++++++++++++------------------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index d5c362490ca6a..f5d2d6f18ee87 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -141,11 +141,13 @@ impl TokenTree { /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `Token::Interpolated` for back-compat. +/// +/// The use of `Option` is an optimization that avoids the need for an +/// allocation when the stream is empty. However, it is not guaranteed that an +/// empty stream is represented with `None`; it may be represented as a `Some` +/// around an empty `Vec`. #[derive(Clone, Debug)] -pub enum TokenStream { - Empty, - Stream(Lrc>), -} +pub struct TokenStream(Option>>); pub type TreeAndJoint = (TokenTree, IsJoint); @@ -166,7 +168,7 @@ impl TokenStream { /// separating the two arguments with a comma for diagnostic suggestions. pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> { // Used to suggest if a user writes `foo!(a b);` - if let TokenStream::Stream(ref stream) = self { + if let Some(ref stream) = self.0 { let mut suggestion = None; let mut iter = stream.iter().enumerate().peekable(); while let Some((pos, ts)) = iter.next() { @@ -230,7 +232,7 @@ impl PartialEq for TokenStream { impl TokenStream { pub fn len(&self) -> usize { - if let TokenStream::Stream(ref slice) = self { + if let Some(ref slice) = self.0 { slice.len() } else { 0 @@ -238,13 +240,13 @@ impl TokenStream { } pub fn empty() -> TokenStream { - TokenStream::Empty + TokenStream(None) } pub fn is_empty(&self) -> bool { - match self { - TokenStream::Empty => true, - _ => false, + match self.0 { + None => true, + Some(ref stream) => stream.is_empty(), } } @@ -255,9 +257,9 @@ impl TokenStream { _ => { let mut vec = vec![]; for stream in streams { - match stream { - TokenStream::Empty => {}, - TokenStream::Stream(stream2) => vec.extend(stream2.iter().cloned()), + match stream.0 { + None => {}, + Some(stream2) => vec.extend(stream2.iter().cloned()), } } TokenStream::new(vec) @@ -267,15 +269,14 @@ impl TokenStream { pub fn new(streams: Vec) -> TokenStream { match streams.len() { - 0 => TokenStream::empty(), - _ => TokenStream::Stream(Lrc::new(streams)), + 0 => TokenStream(None), + _ => TokenStream(Some(Lrc::new(streams))), } } pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec) { - match self { - TokenStream::Empty => {} - TokenStream::Stream(stream) => vec.extend(stream.iter().cloned()), + if let Some(stream) = self.0 { + vec.extend(stream.iter().cloned()); } } @@ -340,41 +341,36 @@ impl TokenStream { } pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { - match self { - TokenStream::Empty => TokenStream::Empty, - TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new( + TokenStream(self.0.map(|stream| { + Lrc::new( stream .iter() .enumerate() .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint)) - .collect() - )), - } + .collect()) + })) } pub fn map TokenTree>(self, mut f: F) -> TokenStream { - match self { - TokenStream::Empty => TokenStream::Empty, - TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new( + TokenStream(self.0.map(|stream| { + Lrc::new( stream .iter() .map(|(tree, is_joint)| (f(tree.clone()), *is_joint)) - .collect() - )), - } + .collect()) + })) } - fn first_tree_and_joint(&self) -> Option<(TokenTree, IsJoint)> { - match self { - TokenStream::Empty => None, - TokenStream::Stream(ref stream) => Some(stream.first().unwrap().clone()) - } + fn first_tree_and_joint(&self) -> Option { + self.0.as_ref().map(|stream| { + stream.first().unwrap().clone() + }) } fn last_tree_if_joint(&self) -> Option { - match self { - TokenStream::Empty => None, - TokenStream::Stream(ref stream) => { + match self.0 { + None => None, + Some(ref stream) => { if let (tree, Joint) = stream.last().unwrap() { Some(tree.clone()) } else { @@ -418,21 +414,21 @@ impl TokenStreamBuilder { } fn push_all_but_last_tree(&mut self, stream: &TokenStream) { - if let TokenStream::Stream(ref streams) = stream { + if let Some(ref streams) = stream.0 { let len = streams.len(); match len { 1 => {} - _ => self.0.push(TokenStream::Stream(Lrc::new(streams[0 .. len - 1].to_vec()))), + _ => self.0.push(TokenStream(Some(Lrc::new(streams[0 .. len - 1].to_vec())))), } } } fn push_all_but_first_tree(&mut self, stream: &TokenStream) { - if let TokenStream::Stream(ref streams) = stream { + if let Some(ref streams) = stream.0 { let len = streams.len(); match len { 1 => {} - _ => self.0.push(TokenStream::Stream(Lrc::new(streams[1 .. len].to_vec()))), + _ => self.0.push(TokenStream(Some(Lrc::new(streams[1 .. len].to_vec())))), } } } @@ -458,9 +454,9 @@ impl Cursor { } pub fn next_with_joint(&mut self) -> Option { - match self.stream { - TokenStream::Empty => None, - TokenStream::Stream(ref stream) => { + match self.stream.0 { + None => None, + Some(ref stream) => { if self.index < stream.len() { self.index += 1; Some(stream[self.index - 1].clone()) @@ -476,16 +472,15 @@ impl Cursor { return; } let index = self.index; - let stream = mem::replace(&mut self.stream, TokenStream::Empty); + let stream = mem::replace(&mut self.stream, TokenStream(None)); *self = TokenStream::from_streams(vec![stream, new_stream]).into_trees(); self.index = index; } pub fn look_ahead(&self, n: usize) -> Option { - match self.stream { - TokenStream::Empty => None, - TokenStream::Stream(ref stream) => - stream[self.index ..].get(n).map(|(tree, _)| tree.clone()), + match self.stream.0 { + None => None, + Some(ref stream) => stream[self.index ..].get(n).map(|(tree, _)| tree.clone()), } } } From 260fb31fd5d4d90d6694570c8a1964d7e1c5f81b Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 15 Jan 2019 00:09:21 +0900 Subject: [PATCH 08/13] Add missing unpretty option help message --- src/librustc/session/config.rs | 9 +++++++-- src/librustc_driver/pretty.rs | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 42adc6a87fdba..03dbd7b54e1e3 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1342,10 +1342,15 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, unpretty: Option = (None, parse_unpretty, [UNTRACKED], "Present the input source, unstable (and less-pretty) variants; valid types are any of the types for `--pretty`, as well as: + `expanded`, `expanded,identified`, + `expanded,hygiene` (with internal representations), `flowgraph=` (graphviz formatted flowgraph for node), + `flowgraph,unlabelled=` (unlabelled graphviz formatted flowgraph for node), `everybody_loops` (all function bodies replaced with `loop {}`), - `hir` (the HIR), `hir,identified`, or - `hir,typed` (HIR with types for each node)."), + `hir` (the HIR), `hir,identified`, + `hir,typed` (HIR with types for each node), + `hir-tree` (dump the raw HIR), + `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], "run `dsymutil` and delete intermediate object files"), ui_testing: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index a9ec99358c1b2..dfd7a14a86435 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -123,7 +123,8 @@ pub fn parse_pretty(sess: &Session, sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ `expanded`, `flowgraph[,unlabelled]=`, \ `identified`, `expanded,identified`, `everybody_loops`, \ - `hir`, `hir,identified`, `hir,typed`, or `mir`; got {}", + `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ + `mir` or `mir-cfg`; got {}", name)); } else { sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \ From 0772dbbb09bb28602756c964188563c64e78bc9c Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 16 Jan 2019 11:36:38 +0530 Subject: [PATCH 09/13] Fix release manifest generation --- src/tools/build-manifest/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 8c1baa55bcdca..4ca285b9b1db1 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -95,6 +95,7 @@ static TARGETS: &'static [&'static str] = &[ "wasm32-unknown-unknown", "x86_64-apple-darwin", "x86_64-apple-ios", + "x86_64-fortanix-unknown-sgx", "x86_64-fuchsia", "x86_64-linux-android", "x86_64-pc-windows-gnu", From 02843d9eb71ad50d490afc6276f4bfe59f182624 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 17 Jan 2019 10:18:56 -0500 Subject: [PATCH 10/13] properly deprecate suggestion methods --- src/librustc_errors/diagnostic_builder.rs | 90 +++++++++++++-------- src/librustc_resolve/build_reduced_graph.rs | 9 ++- src/librustc_resolve/lib.rs | 9 ++- src/librustc_typeck/check/_match.rs | 9 ++- src/libsyntax/parse/parser.rs | 9 ++- 5 files changed, 86 insertions(+), 40 deletions(-) diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7449b2b758302..736cca6bd64af 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -33,7 +33,11 @@ pub struct DiagnosticBuilder<'a> { /// it easy to declare such methods on the builder. macro_rules! forward { // Forward pattern for &self -> &Self - (pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => { + ( + $(#[$attrs:meta])* + pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self + ) => { + $(#[$attrs])* pub fn $n(&self, $($name: $ty),*) -> &Self { #[allow(deprecated)] self.diagnostic.$n($($name),*); @@ -42,7 +46,11 @@ macro_rules! forward { }; // Forward pattern for &mut self -> &mut Self - (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => { + ( + $(#[$attrs:meta])* + pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self + ) => { + $(#[$attrs])* pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { #[allow(deprecated)] self.diagnostic.$n($($name),*); @@ -52,10 +60,15 @@ macro_rules! forward { // Forward pattern for &mut self -> &mut Self, with S: Into // type parameter. No obvious way to make this more generic. - (pub fn $n:ident>( - &mut self, - $($name:ident: $ty:ty),* - $(,)*) -> &mut Self) => { + ( + $(#[$attrs:meta])* + pub fn $n:ident>( + &mut self, + $($name:ident: $ty:ty),* + $(,)* + ) -> &mut Self + ) => { + $(#[$attrs])* pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { #[allow(deprecated)] self.diagnostic.$n($($name),*); @@ -177,34 +190,43 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, ) -> &mut Self); - #[deprecated(note = "Use `span_suggestion_short_with_applicability`")] - forward!(pub fn span_suggestion_short( - &mut self, - sp: Span, - msg: &str, - suggestion: String, - ) -> &mut Self); - - #[deprecated(note = "Use `multipart_suggestion_with_applicability`")] - forward!(pub fn multipart_suggestion( - &mut self, - msg: &str, - suggestion: Vec<(Span, String)>, - ) -> &mut Self); - - #[deprecated(note = "Use `span_suggestion_with_applicability`")] - forward!(pub fn span_suggestion(&mut self, - sp: Span, - msg: &str, - suggestion: String, - ) -> &mut Self); - - #[deprecated(note = "Use `span_suggestions_with_applicability`")] - forward!(pub fn span_suggestions(&mut self, - sp: Span, - msg: &str, - suggestions: Vec, - ) -> &mut Self); + forward!( + #[deprecated(note = "Use `span_suggestion_short_with_applicability`")] + pub fn span_suggestion_short( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + ) -> &mut Self + ); + + forward!( + #[deprecated(note = "Use `multipart_suggestion_with_applicability`")] + pub fn multipart_suggestion( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + ) -> &mut Self + ); + + forward!( + #[deprecated(note = "Use `span_suggestion_with_applicability`")] + pub fn span_suggestion( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + ) -> &mut Self + ); + + forward!( + #[deprecated(note = "Use `span_suggestions_with_applicability`")] + pub fn span_suggestions(&mut self, + sp: Span, + msg: &str, + suggestions: Vec, + ) -> &mut Self + ); pub fn multipart_suggestion_with_applicability(&mut self, msg: &str, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a452bbf0c9d54..fea013826e949 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,6 +21,8 @@ use std::cell::Cell; use std::ptr; use rustc_data_structures::sync::Lrc; +use errors::Applicability; + use syntax::ast::{Name, Ident}; use syntax::attr; @@ -345,7 +347,12 @@ impl<'a> Resolver<'a> { let module = if orig_name.is_none() && ident.name == keywords::SelfLower.name() { self.session .struct_span_err(item.span, "`extern crate self;` requires renaming") - .span_suggestion(item.span, "try", "extern crate self as name;".into()) + .span_suggestion_with_applicability( + item.span, + "try", + "extern crate self as name;".into(), + Applicability::HasPlaceholders, + ) .emit(); return; } else if orig_name == Some(keywords::SelfLower.name()) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a25009ccfb49c..896cb3d5a0c69 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4823,8 +4823,13 @@ impl<'a> Resolver<'a> { } else if ident.span.rust_2018() { let msg = "relative paths are not supported in visibilities on 2018 edition"; self.session.struct_span_err(ident.span, msg) - .span_suggestion(path.span, "try", format!("crate::{}", path)) - .emit(); + .span_suggestion_with_applicability( + path.span, + "try", + format!("crate::{}", path), + Applicability::MaybeIncorrect, + ) + .emit(); return ty::Visibility::Public; } else { let ctxt = ident.span.ctxt(); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1767af4870d3b..47f258e1aea74 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1,5 +1,6 @@ use check::{FnCtxt, Expectation, Diverges, Needs}; use check::coercion::CoerceMany; +use errors::Applicability; use rustc::hir::{self, PatKind}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -989,7 +990,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let suggested_name = find_best_match_for_name(input, &ident.as_str(), None); if let Some(suggested_name) = suggested_name { - err.span_suggestion(*span, "did you mean", suggested_name.to_string()); + err.span_suggestion_with_applicability( + *span, + "did you mean", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + // we don't want to throw `E0027` in case we have thrown `E0026` for them unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str()); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 823c786bded26..4f1bc2fc2412c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4063,12 +4063,13 @@ impl<'a> Parser<'a> { if let Some(mut err) = delayed_err { if let Some(etc_span) = etc_span { - err.multipart_suggestion( + err.multipart_suggestion_with_applicability( "move the `..` to the end of the field list", vec![ (etc_span, String::new()), (self.span, format!("{}.. }}", if ate_comma { "" } else { ", " })), ], + Applicability::MachineApplicable, ); } err.emit(); @@ -6913,7 +6914,11 @@ impl<'a> Parser<'a> { let mut err = self.struct_span_err(fixed_name_sp, error_msg); err.span_label(fixed_name_sp, "dash-separated idents are not valid"); - err.multipart_suggestion(suggestion_msg, replacement); + err.multipart_suggestion_with_applicability( + suggestion_msg, + replacement, + Applicability::MachineApplicable, + ); err.emit(); } Ok(ident) From d34b3e9bf2becb8fe8184559e2a376d1e7ab1fa3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 16 Jan 2019 01:47:49 +0300 Subject: [PATCH 11/13] privacy: Account for associated existential types --- src/librustc_privacy/lib.rs | 43 +++++++++++-------- .../ui/privacy/private-in-public-assoc-ty.rs | 9 +++- .../privacy/private-in-public-assoc-ty.stderr | 20 ++++++--- .../privacy/private-in-public-existential.rs | 10 +++++ 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4890369e13f20..c0d7248fab7f3 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -13,7 +13,7 @@ extern crate rustc_typeck; extern crate syntax_pos; extern crate rustc_data_structures; -use rustc::hir::{self, Node, PatKind}; +use rustc::hir::{self, Node, PatKind, AssociatedItemKind}; use rustc::hir::def::Def; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -548,7 +548,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { let mut reach = self.reach(trait_item_ref.id.node_id, item_level); reach.generics().predicates(); - if trait_item_ref.kind == hir::AssociatedItemKind::Type && + if trait_item_ref.kind == AssociatedItemKind::Type && !trait_item_ref.defaultness.has_value() { // No type to visit. } else { @@ -1333,11 +1333,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item_ref.kind { - hir::AssociatedItemKind::Const => { + AssociatedItemKind::Const => { found_pub_static = true; intravisit::walk_impl_item(self, impl_item); } - hir::AssociatedItemKind::Method { has_self: false } => { + AssociatedItemKind::Method { has_self: false } => { found_pub_static = true; intravisit::walk_impl_item(self, impl_item); } @@ -1558,6 +1558,24 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { in_assoc_ty: false, } } + + fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind, + defaultness: hir::Defaultness, vis: ty::Visibility) { + let mut check = self.check(node_id, vis); + + let (check_ty, is_assoc_ty) = match assoc_item_kind { + AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false), + AssociatedItemKind::Type => (defaultness.has_value(), true), + // `ty()` for existential types is the underlying type, + // it's not a part of interface, so we skip it. + AssociatedItemKind::Existential => (false, true), + }; + check.in_assoc_ty = is_assoc_ty; + check.generics().predicates(); + if check_ty { + check.ty(); + } + } } impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { @@ -1592,16 +1610,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> self.check(item.id, item_visibility).generics().predicates(); for trait_item_ref in trait_item_refs { - let mut check = self.check(trait_item_ref.id.node_id, item_visibility); - check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type; - check.generics().predicates(); - - if trait_item_ref.kind == hir::AssociatedItemKind::Type && - !trait_item_ref.defaultness.has_value() { - // No type to visit. - } else { - check.ty(); - } + self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind, + trait_item_ref.defaultness, item_visibility); } } hir::ItemKind::TraitAlias(..) => { @@ -1647,9 +1657,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } else { impl_vis }; - let mut check = self.check(impl_item.id, impl_item_vis); - check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type; - check.generics().predicates().ty(); + self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind, + impl_item_ref.defaultness, impl_item_vis); } } } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs index c6e86ed64ae73..81d23959fd4ad 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.rs +++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs @@ -1,7 +1,7 @@ // Private types and traits are not allowed in interfaces of associated types. // This test also ensures that the checks are performed even inside private modules. -#![feature(associated_type_defaults)] +#![feature(associated_type_defaults, existential_type)] mod m { struct Priv; @@ -23,10 +23,17 @@ mod m { type Alias4 = Priv; //~^ ERROR private type `m::Priv` in public interface + + type Exist; + fn infer_exist() -> Self::Exist; } impl PubTr for u8 { type Alias1 = Priv; //~^ ERROR private type `m::Priv` in public interface + + existential type Exist: PrivTr; + //~^ ERROR private trait `m::PrivTr` in public interface + fn infer_exist() -> Self::Exist { Priv } } } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index 6740277c9a7c1..0e5dab1a08c37 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -6,7 +6,7 @@ LL | | //~^ WARN private trait `m::PrivTr` in public interface LL | | //~| WARN this was previously accepted LL | | //~| WARN private type `m::Priv` in public interface ... | -LL | | //~^ ERROR private type `m::Priv` in public interface +LL | | fn infer_exist() -> Self::Exist; LL | | } | |_____^ | @@ -22,7 +22,7 @@ LL | | //~^ WARN private trait `m::PrivTr` in public interface LL | | //~| WARN this was previously accepted LL | | //~| WARN private type `m::Priv` in public interface ... | -LL | | //~^ ERROR private type `m::Priv` in public interface +LL | | fn infer_exist() -> Self::Exist; LL | | } | |_____^ | @@ -39,7 +39,7 @@ LL | type Alias4 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:28:9 + --> $DIR/private-in-public-assoc-ty.rs:31:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -47,6 +47,16 @@ LL | struct Priv; LL | type Alias1 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error: aborting due to 2 previous errors +error[E0445]: private trait `m::PrivTr` in public interface + --> $DIR/private-in-public-assoc-ty.rs:34:9 + | +LL | trait PrivTr {} + | - `m::PrivTr` declared as private +... +LL | existential type Exist: PrivTr; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0446`. +Some errors occurred: E0445, E0446. +For more information about an error, try `rustc --explain E0445`. diff --git a/src/test/ui/privacy/private-in-public-existential.rs b/src/test/ui/privacy/private-in-public-existential.rs index 95658f45df6f5..61c6130e47019 100644 --- a/src/test/ui/privacy/private-in-public-existential.rs +++ b/src/test/ui/privacy/private-in-public-existential.rs @@ -12,4 +12,14 @@ fn check() -> Pub { Priv } +pub trait Trait { + type Pub: Default; + fn method() -> Self::Pub; +} + +impl Trait for u8 { + existential type Pub: Default; + fn method() -> Self::Pub { Priv } +} + fn main() {} From 55768330a9046d240c5e542419d808626106a0aa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 18 Jan 2019 09:51:24 +1100 Subject: [PATCH 12/13] Remove unneeded `origin` arg from `iterate_until_fixed_point`'s closure. --- src/librustc/infer/lexical_region_resolve/mod.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 39ce8cc621b49..f45ed395c414f 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -186,8 +186,8 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { } fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { - self.iterate_until_fixed_point("Expansion", |constraint, origin| { - debug!("expansion: constraint={:?} origin={:?}", constraint, origin); + self.iterate_until_fixed_point("Expansion", |constraint| { + debug!("expansion: constraint={:?}", constraint); match *constraint { Constraint::RegSubVar(a_region, b_vid) => { let b_data = var_values.value_mut(b_vid); @@ -722,18 +722,17 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { } fn iterate_until_fixed_point(&self, tag: &str, mut body: F) - where - F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> (bool, bool), + where F: FnMut(&Constraint<'tcx>) -> (bool, bool), { - let mut constraints: SmallVec<[_; 16]> = self.data.constraints.iter().collect(); + let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect(); let mut iteration = 0; let mut changed = true; while changed { changed = false; iteration += 1; debug!("---- {} Iteration {}{}", "#", tag, iteration); - constraints.retain(|(constraint, origin)| { - let (edge_changed, retain) = body(constraint, origin); + constraints.retain(|constraint| { + let (edge_changed, retain) = body(constraint); if edge_changed { debug!("Updated due to constraint {:?}", constraint); changed = true; From 92fd6f9d30d0b6b4ecbcf01534809fb66393f139 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 18 Jan 2019 10:00:51 +1100 Subject: [PATCH 13/13] Inline `expand_node`. This requires restructuring things a little so that there is only one callsite, ensuring that inlinining doesn't cause unnecessary code bloat. This reduces instruction counts for the `unicode_normalization` benchmark by up to 4%. --- .../infer/lexical_region_resolve/mod.rs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index f45ed395c414f..545192a1f2113 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -188,32 +188,37 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { self.iterate_until_fixed_point("Expansion", |constraint| { debug!("expansion: constraint={:?}", constraint); - match *constraint { + let (a_region, b_vid, b_data, retain) = match *constraint { Constraint::RegSubVar(a_region, b_vid) => { let b_data = var_values.value_mut(b_vid); - (self.expand_node(a_region, b_vid, b_data), false) + (a_region, b_vid, b_data, false) } Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { - VarValue::ErrorValue => (false, false), + VarValue::ErrorValue => return (false, false), VarValue::Value(a_region) => { - let b_node = var_values.value_mut(b_vid); - let changed = self.expand_node(a_region, b_vid, b_node); - let retain = match *b_node { + let b_data = var_values.value_mut(b_vid); + let retain = match *b_data { VarValue::Value(ReStatic) | VarValue::ErrorValue => false, _ => true }; - (changed, retain) + (a_region, b_vid, b_data, retain) } }, Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => { // These constraints are checked after expansion // is done, in `collect_errors`. - (false, false) + return (false, false) } - } + }; + + let changed = self.expand_node(a_region, b_vid, b_data); + (changed, retain) }) } + // This function is very hot in some workloads. There's a single callsite + // so always inlining is ok even though it's large. + #[inline(always)] fn expand_node( &self, a_region: Region<'tcx>,