diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 0d0dc0832a459..1878720aa9520 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -538,6 +538,7 @@ define_dep_nodes!( <'tcx> [] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] IsFreeze { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, + [] IsSync { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] NeedsDrop { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] Layout { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index cda7d8d6b9003..936b2e7aa9787 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -346,8 +346,6 @@ struct ElisionFailureInfo { type ScopeRef<'a> = &'a Scope<'a>; -const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; - pub fn provide(providers: &mut ty::query::Providers<'_>) { *providers = ty::query::Providers { resolve_lifetimes, @@ -431,7 +429,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap { let mut visitor = LifetimeContext { tcx, map: &mut map, - scope: ROOT_SCOPE, + scope: &Scope::Root, trait_ref_hack: false, is_in_fn_syntax: false, labels_in_fn: vec![], @@ -490,7 +488,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // No lifetime parameters, but implied 'static. let scope = Scope::Elision { elide: Elide::Exact(Region::Static), - s: ROOT_SCOPE, + s: &Scope::Root, }; self.with(scope, |_, this| intravisit::walk_item(this, item)); } @@ -534,7 +532,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index: index + type_count, abstract_type_parent: true, track_lifetime_uses, - s: ROOT_SCOPE, + s: &Scope::Root, }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 9ea655ba6fd5d..e61554ad76ce6 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -181,6 +181,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_freeze_raw<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::is_sync_raw<'tcx> { + fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `Sync`", env.value) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::needs_drop_raw<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { format!("computing whether `{}` needs drop", env.value) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index e0a503a9cebf5..c58c498dfb74f 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -366,6 +366,7 @@ define_queries! { <'tcx> [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_sync_raw: is_sync_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx ty::layout::LayoutDetails, @@ -767,6 +768,10 @@ fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepCo DepConstructor::IsFreeze { param_env } } +fn is_sync_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsSync { param_env } +} + fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { DepConstructor::NeedsDrop { param_env } } diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 510ca08b62100..de7b8a518bc67 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1059,6 +1059,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::IsCopy | DepKind::IsSized | DepKind::IsFreeze | + DepKind::IsSync | DepKind::NeedsDrop | DepKind::Layout | DepKind::ConstEval | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 93fc77359e43a..5ea47bf30c21b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -16,7 +16,7 @@ use hir::map::DefPathData; use hir::{self, Node}; use ich::NodeIdHashingMode; use traits::{self, ObligationCause}; -use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; +use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, Predicate}; use ty::subst::{Substs, UnpackedKind}; use ty::query::TyCtxtAt; use ty::TyKind::*; @@ -655,6 +655,14 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx.at(span).is_freeze_raw(param_env.and(self)) } + pub fn is_sync(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span)-> bool + { + tcx.at(span).is_sync_raw(param_env.and(self)) + } + /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// `false`, then `ty` definitely has no destructor (i.e. no drop glue). @@ -853,6 +861,50 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("is_type_representable: {:?} is {:?}", self, r); r } + + /// Returns a potentially different type that + /// can be used to check whether a 0-argument constructor of this type is + /// a `Sync` value. + /// Concretely, some type parameters get replaced by `()`. We assume that + /// if a type parameter has no bounds (except for `Sized`), and if the same + /// type is `Sync` for that type parameter replaced by `()`, then the constructor + /// valie is also `Sync` at the original type. This is a kind of parametricity + /// assumption. + /// For now, we only do anything if *no* type parameter has any bound other than + /// `Sized`. That's just simpler to check. + pub fn generalize_for_value_based_sync( + &'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ) -> Ty<'tcx> { + match self.sty { + ty::Adt(def, substs) => { + for (bound, _) in def.predicates(tcx).predicates.iter() { + match bound { + Predicate::Trait(pred) + if Some(pred.def_id()) == tcx.lang_items().sized_trait() => + { + // A `Sized` bound. Ignore. + continue; + } + _ => {} + } + // There is a relevant bound. Do not do anything. + debug!("Type {:?} not generalizable because of bound {:?}", self, bound); + return self; + } + // If we got here, there are no bounds and we can replace all + // type parameters by `()`. + let unit_substs = substs.iter() + .map(|param| match param.unpack() { + UnpackedKind::Lifetime(_) => param.clone(), + UnpackedKind::Type(_) => tcx.mk_unit().into(), + }); + let unit_substs = tcx.mk_substs(unit_substs); + tcx.mk_ty(ty::Adt(def, unit_substs)) + } + _ => self, // don't change + } + } } fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -897,6 +949,20 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, DUMMY_SP)) } +fn is_sync_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + let (param_env, ty) = query.into_parts(); + let trait_def_id = tcx.require_lang_item(lang_items::SyncTraitLangItem); + tcx.infer_ctxt() + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP)) +} + fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool @@ -1044,6 +1110,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { is_copy_raw, is_sized_raw, is_freeze_raw, + is_sync_raw, needs_drop_raw, ..*providers }; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a6e2cad509408..37ed411ed4c9f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -46,8 +46,10 @@ bitflags! { // they have none of these qualifications, with // the exception of `STATIC_REF` (in statics only). struct Qualif: u8 { - // Constant containing interior mutability (UnsafeCell). - const MUTABLE_INTERIOR = 1 << 0; + // Constant containing interior mutability (UnsafeCell) or non-Sync data. + // Both of these prevent sound re-use of the same global static memory for + // the same data across multiple threads. + const UNSHAREABLE_INTERIOR = 1 << 0; // Constant containing an ADT that implements Drop. const NEEDS_DROP = 1 << 1; @@ -63,9 +65,9 @@ bitflags! { // promote_consts decided they weren't simple enough. const NOT_PROMOTABLE = 1 << 4; - // Const items can only have MUTABLE_INTERIOR + // Const items can only have UNSHAREABLE_INTERIOR // and NOT_PROMOTABLE without producing an error. - const CONST_ERROR = !Qualif::MUTABLE_INTERIOR.bits & + const CONST_ERROR = !Qualif::UNSHAREABLE_INTERIOR.bits & !Qualif::NOT_PROMOTABLE.bits; } } @@ -75,8 +77,8 @@ impl<'a, 'tcx> Qualif { fn restrict(&mut self, ty: Ty<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) { - if ty.is_freeze(tcx, param_env, DUMMY_SP) { - *self = *self - Qualif::MUTABLE_INTERIOR; + if ty.is_freeze(tcx, param_env, DUMMY_SP) && ty.is_sync(tcx, param_env, DUMMY_SP) { + *self = *self - Qualif::UNSHAREABLE_INTERIOR; } if !ty.needs_drop(tcx, param_env) { *self = *self - Qualif::NEEDS_DROP; @@ -206,7 +208,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// Add the given type's qualification to self.qualif. fn add_type(&mut self, ty: Ty<'tcx>) { - self.add(Qualif::MUTABLE_INTERIOR | Qualif::NEEDS_DROP); + self.add(Qualif::UNSHAREABLE_INTERIOR | Qualif::NEEDS_DROP); self.qualif.restrict(ty, self.tcx, self.param_env); } @@ -679,18 +681,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Constants cannot be borrowed if they contain interior mutability as // it means that our "silent insertion of statics" could change // initializer values (very bad). - if self.qualif.contains(Qualif::MUTABLE_INTERIOR) { - // A reference of a MUTABLE_INTERIOR place is instead + if self.qualif.contains(Qualif::UNSHAREABLE_INTERIOR) { + // A reference of a UNSHAREABLE_INTERIOR place is instead // NOT_CONST (see `if forbidden_mut` below), to avoid // duplicate errors (from reborrowing, for example). - self.qualif = self.qualif - Qualif::MUTABLE_INTERIOR; + self.qualif = self.qualif - Qualif::UNSHAREABLE_INTERIOR; if self.mode != Mode::Fn { span_err!(self.tcx.sess, self.span, E0492, "cannot borrow a constant which may contain \ - interior mutability, create a static instead"); + interior mutability or non-`Sync` data. If your \ + data is `Sync`, create a static instead"); } } else { - // We allow immutable borrows of frozen data. + // We allow immutable borrows of frozen non-Sync data. forbidden_mut = false; } } @@ -712,11 +715,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if self.mir.local_kind(local) == LocalKind::Temp { if let Some(qualif) = self.local_qualif[local] { // `forbidden_mut` is false, so we can safely ignore - // `MUTABLE_INTERIOR` from the local's qualifications. + // `UNSHAREABLE_INTERIOR` from the local's qualifications. // This allows borrowing fields which don't have - // `MUTABLE_INTERIOR`, from a type that does, e.g.: + // `UNSHAREABLE_INTERIOR`, from a type that does, e.g.: // `let _: &'static _ = &(Cell::new(1), 2).1;` - if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() { + if (qualif - Qualif::UNSHAREABLE_INTERIOR).is_empty() { self.promotion_candidates.push(candidate); } } @@ -788,16 +791,36 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - Rvalue::Aggregate(ref kind, _) => { + Rvalue::Aggregate(ref kind, ref args) => { if let AggregateKind::Adt(def, ..) = **kind { if def.has_dtor(self.tcx) { self.add(Qualif::NEEDS_DROP); } - if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() { - let ty = rvalue.ty(self.mir, self.tcx); - self.add_type(ty); - assert!(self.qualif.contains(Qualif::MUTABLE_INTERIOR)); + let ty = rvalue.ty(self.mir, self.tcx); + // Value-based reasoning: + // We are looking at a concrete type constructor, and we know + // the only way to construct "fresh" non-Freeze data is `UnsafeCell`. + // So we can check for that instead of `Freeze`. + let freeze = Some(def.did) != self.tcx.lang_items().unsafe_cell_type(); + // For Sync, we generally have to fall back on the type, but have a + // special exception for 0-argument ADT cosntructors. + let sync = { + let generalized_ty = if args.len() == 0 { + // A type cosntructor with no arguments is directly a value. + // We generalize its type before checking Sync to allow + // `None` to pass no matter the type parameter. + ty.generalize_for_value_based_sync(self.tcx) + } else { + ty + }; + generalized_ty.is_sync(self.tcx, self.param_env, DUMMY_SP) + }; + if !(freeze && sync) + { + // Not freeze and sync? Be careful. + debug!("Rvalue {:?} has unsharable interior", rvalue); + self.add(Qualif::UNSHAREABLE_INTERIOR); } } } @@ -1248,6 +1271,7 @@ impl MirPass for QualifyAndPromoteConstants { } } let ty = mir.return_ty(); + // Not using ty.is_sync() to get the right kind of error message tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(); let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 828800465209e..01605ee537d03 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -153,6 +153,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { debug!("type_promotability({})", ty); if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) && + ty.is_sync(self.tcx, self.param_env, DUMMY_SP) && !ty.needs_drop(self.tcx, self.param_env) { Promotable } else { @@ -375,8 +376,20 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Path(ref qpath) => { let def = v.tables.qpath_def(qpath, e.hir_id); match def { - Def::VariantCtor(..) | Def::StructCtor(..) | - Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => Promotable, + Def::Fn(..) | Def::Method(..) | + Def::VariantCtor(..) | Def::StructCtor(..) | Def::SelfCtor(..) => { + // This is a 0-argument constructor. Do some value-based-reasoning. + let ty = v.tables.expr_ty(e); + let ty = ty.generalize_for_value_based_sync(v.tcx); + if ty.is_sync(v.tcx, v.param_env, DUMMY_SP) { + Promotable + } else { + debug!("Constructor ({:?}) not promotable because generalized type \ + ({:?}) is not Sync", + e, ty); + NotPromotable + } + } // References to a static that are themselves within a static // are inherently promotable with the exception @@ -442,7 +455,16 @@ fn check_expr_kind<'a, 'tcx>( let def_result = match def { Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) | - Def::SelfCtor(..) => Promotable, + Def::SelfCtor(..) => { + let ty = v.tables.expr_ty(e); + if ty.is_sync(v.tcx, v.param_env, DUMMY_SP) { + Promotable + } else { + debug!("Constructor ({:?}) not promotable because type ({:?}) is not Sync", + e, ty); + NotPromotable + } + } Def::Fn(did) => { v.handle_const_fn_call(did, node_ty, e.span) } @@ -485,12 +507,18 @@ fn check_expr_kind<'a, 'tcx>( if let Some(ref expr) = *option_expr { struct_result &= v.check_expr(&expr); } - if let ty::Adt(adt, ..) = v.tables.expr_ty(e).sty { + let ty = v.tables.expr_ty(e); + if let ty::Adt(adt, ..) = ty.sty { // unsafe_cell_type doesn't necessarily exist with no_core if Some(adt.did) == v.tcx.lang_items().unsafe_cell_type() { return NotPromotable; } } + if !ty.is_sync(v.tcx, v.param_env, DUMMY_SP) { + debug!("Constructor ({:?}) not promotable because type ({:?}) is not Sync", + e, ty); + return NotPromotable; + } struct_result } @@ -509,6 +537,7 @@ fn check_expr_kind<'a, 'tcx>( if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) { NotPromotable } else { + // Nothing captured, so the environment type is trivially Freeze+Sync nested_body_promotable } } diff --git a/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs b/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs index 54f888b3796a1..1656d33c3d502 100644 --- a/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs +++ b/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs @@ -22,6 +22,8 @@ trait Sized {} trait Copy {} #[lang = "freeze"] trait Freeze {} +#[lang = "sync"] +trait Sync {} impl Copy for *mut T {} diff --git a/src/test/run-make-fulldeps/simd-ffi/simd.rs b/src/test/run-make-fulldeps/simd-ffi/simd.rs index 21411a35e3c35..a71e838f0647e 100644 --- a/src/test/run-make-fulldeps/simd-ffi/simd.rs +++ b/src/test/run-make-fulldeps/simd-ffi/simd.rs @@ -75,6 +75,9 @@ pub trait Sized { } #[lang = "copy"] pub trait Copy { } +#[lang="sync"] +pub trait Sync { } + impl Copy for f32 {} impl Copy for i32 {} diff --git a/src/test/run-make-fulldeps/target-specs/foo.rs b/src/test/run-make-fulldeps/target-specs/foo.rs index bbd1c5d900faf..a357c1f92d277 100644 --- a/src/test/run-make-fulldeps/target-specs/foo.rs +++ b/src/test/run-make-fulldeps/target-specs/foo.rs @@ -17,6 +17,9 @@ trait Copy { } #[lang="sized"] trait Sized { } +#[lang="sync"] +trait Sync { } + #[lang = "freeze"] auto trait Freeze {} diff --git a/src/test/run-pass/issues/issue-22777.rs b/src/test/run-pass/issues/issue-22777.rs index 92ad7a43d4d17..651fff118654b 100644 --- a/src/test/run-pass/issues/issue-22777.rs +++ b/src/test/run-pass/issues/issue-22777.rs @@ -16,6 +16,7 @@ // pretty-expanded FIXME #23616 #![allow(non_camel_case_types)] +#![recursion_limit="128"] pub fn noop_fold_impl_item() -> SmallVector { loop { } diff --git a/src/test/run-pass/issues/issue-49955-2.rs b/src/test/run-pass/issues/issue-49955-2.rs index 40827b0162202..d80c578b86a46 100644 --- a/src/test/run-pass/issues/issue-49955-2.rs +++ b/src/test/run-pass/issues/issue-49955-2.rs @@ -12,16 +12,23 @@ // compile-flags: -Z borrowck=mir use std::cell::Cell; +use std::sync::atomic::AtomicUsize; #[inline(never)] fn tuple_field() -> &'static u32 { // This test is MIR-borrowck-only because the old borrowck // doesn't agree that borrows of "frozen" (i.e. without any - // interior mutability) fields of non-frozen temporaries, + // interior mutability) fields of non-frozen (even non-Sync!) temporaries, // should be promoted, while MIR promotion does promote them. &(Cell::new(5), 42).1 } +#[inline(never)] +fn tuple_field2() -> &'static u32 { + &(AtomicUsize::new(5), 42).1 +} + fn main() { assert_eq!(tuple_field().to_string(), "42"); + assert_eq!(*tuple_field2(), 42); } diff --git a/src/test/ui/consts/const-eval/dont_promote_non_sync.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_non_sync.nll.stderr new file mode 100644 index 0000000000000..2d62297c18d43 --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_non_sync.nll.stderr @@ -0,0 +1,83 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:18:32 + | +LL | fn mk_foo() -> &'static Foo { &Foo } //~ ERROR does not live long enough + | ^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:19:32 + | +LL | fn mk_bar() -> &'static Bar { &Bar(0) } //~ ERROR does not live long enough + | ^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:20:32 + | +LL | fn mk_baz() -> &'static Baz { &Baz { field: 0 } } //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:21:34 + | +LL | fn mk_bla_t() -> &'static Bla { &Bla::T(0) } //~ ERROR does not live long enough + | ^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:22:34 + | +LL | fn mk_bla_s() -> &'static Bla { &Bla::S { field: 0 } } //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:26:42 + | +LL | fn mk_foo2() -> &'static Foo { &T::C } //~ ERROR does not live long enough + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:29:42 + | +LL | fn mk_bar2() -> &'static Bar { &T::C } //~ ERROR does not live long enough + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_non_sync.rs:32:60 + | +LL | fn mk_capturing_closure() -> &'static Fn() { let x = Foo; &move || { &x; } } //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/const-eval/dont_promote_non_sync.rs b/src/test/ui/consts/const-eval/dont_promote_non_sync.rs new file mode 100644 index 0000000000000..dacf17fbdb26a --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_non_sync.rs @@ -0,0 +1,34 @@ +// ignore-tidy-linelength + +#![feature(optin_builtin_traits)] + +struct Foo; +impl !Sync for Foo {} + +struct Bar(i32); +impl !Sync for Bar {} + +struct Baz { field: i32 } +impl !Sync for Baz {} + +enum Bla { T(i32), S { field: i32 } } +impl !Sync for Bla {} + +// Known values of the given types +fn mk_foo() -> &'static Foo { &Foo } //~ ERROR does not live long enough +fn mk_bar() -> &'static Bar { &Bar(0) } //~ ERROR does not live long enough +fn mk_baz() -> &'static Baz { &Baz { field: 0 } } //~ ERROR does not live long enough +fn mk_bla_t() -> &'static Bla { &Bla::T(0) } //~ ERROR does not live long enough +fn mk_bla_s() -> &'static Bla { &Bla::S { field: 0 } } //~ ERROR does not live long enough + +// Unknown values of the given types (test a ZST and a non-ZST) +trait FooT { const C: Foo; } +fn mk_foo2() -> &'static Foo { &T::C } //~ ERROR does not live long enough + +trait BarT { const C: Bar; } +fn mk_bar2() -> &'static Bar { &T::C } //~ ERROR does not live long enough + +// Closure capturing non-Sync data +fn mk_capturing_closure() -> &'static Fn() { let x = Foo; &move || { &x; } } //~ ERROR does not live long enough + +fn main() {} diff --git a/src/test/ui/consts/const-eval/dont_promote_non_sync.stderr b/src/test/ui/consts/const-eval/dont_promote_non_sync.stderr new file mode 100644 index 0000000000000..b59693203f429 --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_non_sync.stderr @@ -0,0 +1,83 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:18:32 + | +LL | fn mk_foo() -> &'static Foo { &Foo } //~ ERROR does not live long enough + | ^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:19:32 + | +LL | fn mk_bar() -> &'static Bar { &Bar(0) } //~ ERROR does not live long enough + | ^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:20:32 + | +LL | fn mk_baz() -> &'static Baz { &Baz { field: 0 } } //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:21:34 + | +LL | fn mk_bla_t() -> &'static Bla { &Bla::T(0) } //~ ERROR does not live long enough + | ^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:22:34 + | +LL | fn mk_bla_s() -> &'static Bla { &Bla::S { field: 0 } } //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:26:42 + | +LL | fn mk_foo2() -> &'static Foo { &T::C } //~ ERROR does not live long enough + | ^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:29:42 + | +LL | fn mk_bar2() -> &'static Bar { &T::C } //~ ERROR does not live long enough + | ^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/dont_promote_non_sync.rs:32:60 + | +LL | fn mk_capturing_closure() -> &'static Fn() { let x = Foo; &move || { &x; } } //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/const-eval/non_sync_const.nll.stderr b/src/test/ui/consts/const-eval/non_sync_const.nll.stderr new file mode 100644 index 0000000000000..29c01435ef592 --- /dev/null +++ b/src/test/ui/consts/const-eval/non_sync_const.nll.stderr @@ -0,0 +1,84 @@ +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:10:21 + | +LL | const FOO1 : &Foo = &Foo; //~ ERROR cannot borrow + | ^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:11:34 + | +LL | const FOO2 : Option<&Foo> = Some(&Foo); //~ ERROR cannot borrow + | ^^^^ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/non_sync_const.rs:11:35 + | +LL | const FOO2 : Option<&Foo> = Some(&Foo); //~ ERROR cannot borrow + | ^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:13:29 + | +LL | const FOO3 : &Option = &Some(Foo); //~ ERROR cannot borrow + | ^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:15:21 + | +LL | const BAR1 : &Bar = &Bar(42); //~ ERROR cannot borrow + | ^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:16:34 + | +LL | const BAR2 : Option<&Bar> = Some(&Bar(42)); //~ ERROR cannot borrow + | ^^^^^^^^ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/non_sync_const.rs:16:35 + | +LL | const BAR2 : Option<&Bar> = Some(&Bar(42)); //~ ERROR cannot borrow + | ^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:18:29 + | +LL | const BAR3 : &Option = &Some(Bar(42)); //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:27:32 + | +LL | const OPT1 : &MyOption1 = &MyOption1::None; //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:28:32 + | +LL | const OPT2 : &MyOption2 = &MyOption2::None; //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:31:26 + | +LL | const TESTS: &FnOnce() = &{ //~ ERROR cannot borrow + | __________________________^ +LL | | let x = Cell::new(32); +LL | | move || { +LL | | x; +LL | | } +LL | | }; + | |_^ + +error: aborting due to 11 previous errors + +Some errors occurred: E0492, E0716. +For more information about an error, try `rustc --explain E0492`. diff --git a/src/test/ui/consts/const-eval/non_sync_const.rs b/src/test/ui/consts/const-eval/non_sync_const.rs new file mode 100644 index 0000000000000..f17a09926cb43 --- /dev/null +++ b/src/test/ui/consts/const-eval/non_sync_const.rs @@ -0,0 +1,38 @@ +#![feature(optin_builtin_traits,const_let)] +use std::cell::Cell; + +struct Foo; +impl !Sync for Foo {} + +struct Bar(i32); +impl !Sync for Bar {} + +const FOO1 : &Foo = &Foo; //~ ERROR cannot borrow +const FOO2 : Option<&Foo> = Some(&Foo); //~ ERROR cannot borrow +//~^ ERROR borrowed value does not live long enough +const FOO3 : &Option = &Some(Foo); //~ ERROR cannot borrow + +const BAR1 : &Bar = &Bar(42); //~ ERROR cannot borrow +const BAR2 : Option<&Bar> = Some(&Bar(42)); //~ ERROR cannot borrow +//~^ ERROR borrowed value does not live long enough +const BAR3 : &Option = &Some(Bar(42)); //~ ERROR cannot borrow + +/// Tests making sure that value-based reasoning does not go too far. +enum MyOption1 { Some(Cell), None } // Never Sync, we shouldnt assume it has Sync values + +trait NotSync {} // private trait! +impl NotSync for Foo {} +enum MyOption2 { Some(T), None } // Never Sync, we shouldnt assume it has Sync values + +const OPT1 : &MyOption1 = &MyOption1::None; //~ ERROR cannot borrow +const OPT2 : &MyOption2 = &MyOption2::None; //~ ERROR cannot borrow + +// Hiding in closure variables +const TESTS: &FnOnce() = &{ //~ ERROR cannot borrow + let x = Cell::new(32); + move || { + x; + } +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/non_sync_const.stderr b/src/test/ui/consts/const-eval/non_sync_const.stderr new file mode 100644 index 0000000000000..e0d9f03a02933 --- /dev/null +++ b/src/test/ui/consts/const-eval/non_sync_const.stderr @@ -0,0 +1,84 @@ +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:10:21 + | +LL | const FOO1 : &Foo = &Foo; //~ ERROR cannot borrow + | ^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:11:34 + | +LL | const FOO2 : Option<&Foo> = Some(&Foo); //~ ERROR cannot borrow + | ^^^^ + +error[E0597]: borrowed value does not live long enough + --> $DIR/non_sync_const.rs:11:35 + | +LL | const FOO2 : Option<&Foo> = Some(&Foo); //~ ERROR cannot borrow + | ^^^- temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:13:29 + | +LL | const FOO3 : &Option = &Some(Foo); //~ ERROR cannot borrow + | ^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:15:21 + | +LL | const BAR1 : &Bar = &Bar(42); //~ ERROR cannot borrow + | ^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:16:34 + | +LL | const BAR2 : Option<&Bar> = Some(&Bar(42)); //~ ERROR cannot borrow + | ^^^^^^^^ + +error[E0597]: borrowed value does not live long enough + --> $DIR/non_sync_const.rs:16:35 + | +LL | const BAR2 : Option<&Bar> = Some(&Bar(42)); //~ ERROR cannot borrow + | ^^^^^^^- temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:18:29 + | +LL | const BAR3 : &Option = &Some(Bar(42)); //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:27:32 + | +LL | const OPT1 : &MyOption1 = &MyOption1::None; //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:28:32 + | +LL | const OPT2 : &MyOption2 = &MyOption2::None; //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^^^ + +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead + --> $DIR/non_sync_const.rs:31:26 + | +LL | const TESTS: &FnOnce() = &{ //~ ERROR cannot borrow + | __________________________^ +LL | | let x = Cell::new(32); +LL | | move || { +LL | | x; +LL | | } +LL | | }; + | |_^ + +error: aborting due to 11 previous errors + +Some errors occurred: E0492, E0597. +For more information about an error, try `rustc --explain E0492`. diff --git a/src/test/ui/consts/const-eval/value-based-reasoning.rs b/src/test/ui/consts/const-eval/value-based-reasoning.rs new file mode 100644 index 0000000000000..4bb75b7983c90 --- /dev/null +++ b/src/test/ui/consts/const-eval/value-based-reasoning.rs @@ -0,0 +1,16 @@ +// Things that we *can* take references of in consts even though their +// type is not Freeze+Sync. + +// compile-pass + +use std::cell::Cell; + +// test const qualification +const CLOSURE: &Fn() = &|| {}; +const NO_CELL: &Option> = &None; + +// test promotion +fn mk_closure() -> &'static Fn() { &|| {} } +fn mk_no_cell() -> &'static Option> { &None } + +fn main() {} diff --git a/src/test/ui/error-codes/E0492.stderr b/src/test/ui/error-codes/E0492.stderr index 157a192969021..d57d8c951f3e5 100644 --- a/src/test/ui/error-codes/E0492.stderr +++ b/src/test/ui/error-codes/E0492.stderr @@ -1,4 +1,4 @@ -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead --> $DIR/E0492.rs:14:34 | LL | static B: &'static AtomicUsize = &A; //~ ERROR E0492 diff --git a/src/test/ui/inhabitedness-infinite-loop.rs b/src/test/ui/inhabitedness-infinite-loop.rs index d11aacec19631..e906f06ac2beb 100644 --- a/src/test/ui/inhabitedness-infinite-loop.rs +++ b/src/test/ui/inhabitedness-infinite-loop.rs @@ -9,6 +9,7 @@ // except according to those terms. // error-pattern:reached recursion limit +// ignore-test FIXME #54419 #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/test/ui/issues/issue-17718-const-borrow.stderr b/src/test/ui/issues/issue-17718-const-borrow.stderr index 3b0217060f782..b0b32d08a239f 100644 --- a/src/test/ui/issues/issue-17718-const-borrow.stderr +++ b/src/test/ui/issues/issue-17718-const-borrow.stderr @@ -1,16 +1,16 @@ -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead --> $DIR/issue-17718-const-borrow.rs:14:39 | LL | const B: &'static UnsafeCell = &A; | ^^ -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead --> $DIR/issue-17718-const-borrow.rs:19:39 | LL | const E: &'static UnsafeCell = &D.a; | ^^^^ -error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead +error[E0492]: cannot borrow a constant which may contain interior mutability or non-`Sync` data. If your data is `Sync`, create a static instead --> $DIR/issue-17718-const-borrow.rs:21:23 | LL | const F: &'static C = &D; diff --git a/src/test/ui/required-lang-item.rs b/src/test/ui/required-lang-item.rs index ce40702b3dc2a..356f6b8fa4711 100644 --- a/src/test/ui/required-lang-item.rs +++ b/src/test/ui/required-lang-item.rs @@ -13,6 +13,7 @@ #[lang="copy"] pub trait Copy { } #[lang="sized"] pub trait Sized { } +#[lang="sync"] pub trait Sync { } // error-pattern:requires `start` lang_item diff --git a/src/test/ui/union-ub-fat-ptr.rs b/src/test/ui/union-ub-fat-ptr.rs index 0c42d28eb00f4..b903f01fa5cc5 100644 --- a/src/test/ui/union-ub-fat-ptr.rs +++ b/src/test/ui/union-ub-fat-ptr.rs @@ -68,7 +68,7 @@ union DynTransmute { repr: DynRepr, repr2: DynRepr2, bad: BadDynRepr, - rust: &'static Trait, + rust: &'static (Trait+Sync), } trait Trait {}