From 41d1cd7196d6799fa960ac220d20b958c1b797ed Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 7 Sep 2016 23:18:46 +0200 Subject: [PATCH 1/5] add static_in_const feature gate also updates tests and deletes the spurious .bk files I inadvertently added last time. --- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/rscope.rs | 39 ++++++++++ src/libsyntax/feature_gate.rs | 3 + src/test/compile-fail/const-unsized.rs | 2 + src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/rfc1623.rs | 2 +- src/test/compile-fail/rfc1623.rs.bk | 98 -------------------------- src/test/run-pass/rfc1623.rs | 1 + src/test/run-pass/rfc1623.rs.bk | 81 --------------------- 9 files changed, 48 insertions(+), 182 deletions(-) delete mode 100644 src/test/compile-fail/rfc1623.rs.bk delete mode 100644 src/test/run-pass/rfc1623.rs.bk diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fcc0b09e31acf..0eb6a747263ea 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1567,7 +1567,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, ..) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t) + ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index f5b13c4207d90..5b00a625bacf5 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -213,6 +213,45 @@ impl RegionScope for ElidableRscope { } } +/// A scope that behaves as an ElidabeRscope with a `'static` default region +/// that should also warn if the `static_in_const` feature is unset. +#[derive(Copy, Clone)] +pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { + /// create a new StaticRscope from a reference to the `TyCtxt` + pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self { + StaticRscope { tcx: tcx } + } +} + +impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { + fn anon_regions(&self, + _span: Span, + count: usize) + -> Result, Option>> { + Ok(vec![ty::ReStatic; count]) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + if !self.tcx.sess.features.borrow().static_in_const { + self.tcx + .sess + .struct_span_warn(span, + "This needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") + .emit(); + } + ty::ReStatic + } +} + /// A scope in which we generate anonymous, late-bound regions for /// omitted regions. This occurs in function signatures. pub struct BindingRscope { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dd2956f706c95..8b8a41fc20488 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -295,6 +295,9 @@ declare_features! ( // Allows untagged unions `union U { ... }` (active, untagged_unions, "1.13.0", Some(32836)), + + // elide `'static` lifetimes in `static`s and `const`s + (active, static_in_const, "1.13.0", Some(35897)), ); declare_features! ( diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index a73164b957c83..07d6edb1f3b15 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,6 +15,7 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size +//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -27,6 +28,7 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size +//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index b9382520cf9d3..d721c8bb6d2bf 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - + //~| WARNING: This needs a `'static` lifetime or the `static_in_const` feature 0 }; } diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 1d8fc7fe111c0..083cc218eecf3 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(static_in_const)] #![allow(dead_code)] fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { diff --git a/src/test/compile-fail/rfc1623.rs.bk b/src/test/compile-fail/rfc1623.rs.bk deleted file mode 100644 index abdcc02de767f..0000000000000 --- a/src/test/compile-fail/rfc1623.rs.bk +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } - -// the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ ERROR: missing lifetime specifier - &(non_elidable as fn(&u8, &u8) -> &u8); - -struct SomeStruct<'x, 'y, 'z: 'x> { - foo: &'x Foo<'z>, - bar: &'x Bar<'z>, - f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, -} - -fn id(t: T) -> T { t } - -static SOME_STRUCT : &SomeStruct = SomeStruct { - foo: &Foo { bools: &[false, true] }, - bar: &Bar { bools: &[true, true] }, - f: &id, -}; - -// very simple test for a 'static static with default lifetime -static STATIC_STR : &'static str = "&'static str"; -const CONST_STR : &'static str = "&'static str"; - -// this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; - -// a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] -} - -static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; -const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; - -type Bar<'a> = Foo<'a>; - -static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; -const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; - -type Baz<'a> = fn(&'a [u8]) -> Option; - -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } - -static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); -const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); - -static BYTES : &'static [u8] = &[1, 2, 3]; - -fn main() { - let x = &[1u8, 2, 3]; - let y = x; - - //this works, so lifetime < `'static` is valid - assert_eq!(Some(1), STATIC_BAZ(y)); - assert_eq!(Some(1), CONST_BAZ(y)); - - let y = &[1u8, 2, 3]; - //^~ ERROR: borrowed values does not live long enough - STATIC_BAZ(BYTES); // BYTES has static lifetime - CONST_BAZ(y); // This forces static lifetime, which y has not -} diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 17453933c8abc..fc9143dc450b7 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(static_in_const)] #![allow(dead_code)] // very simple test for a 'static static with default lifetime diff --git a/src/test/run-pass/rfc1623.rs.bk b/src/test/run-pass/rfc1623.rs.bk deleted file mode 100644 index 0915118ca27c0..0000000000000 --- a/src/test/run-pass/rfc1623.rs.bk +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -// very simple test for a 'static static with default lifetime -static STATIC_STR : &str = "&'static str"; -const CONST_STR : &str = "&'static str"; - -// this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; - -// a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] -} - -static STATIC_FOO : Foo = Foo { bools: &[true, false] }; -const CONST_FOO : Foo = Foo { bools: &[true, false] }; - -type Bar<'a> = Foo<'a>; - -static STATIC_BAR : Bar = Bar { bools: &[true, false] }; -const CONST_BAR : Bar = Bar { bools: &[true, false] }; - -type Baz<'a> = fn(&'a [u8]) -> Option; - -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } - -static STATIC_BAZ : &Baz = &(baz as Baz); -const CONST_BAZ : &Baz = &(baz as Baz); - -static BYTES : &[u8] = &[1, 2, 3]; - -fn main() { - // make sure that the lifetime is actually elided (and not defaulted) - let x = &[1u8, 2, 3]; - STATIC_SIMPLE_FN(x); - CONST_SIMPLE_FN(x); - - STATIC_BAZ(BYTES); // neees static lifetime - CONST_BAZ(BYTES); - - // make sure this works with different lifetimes - let a = &1; - { - let b = &2; - let c = &3; - CONST_MULTI_FN(a, b, c); - } -} From e0eea8b7c1fbf2247694a94e216c239e0ec285b1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:26:55 +0200 Subject: [PATCH 2/5] =?UTF-8?q?warning=20=E2=86=92=20error,=20lowercase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustc_typeck/rscope.rs | 6 +++--- src/test/compile-fail/const-unsized.rs | 4 ++-- src/test/compile-fail/issue-24446.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 5b00a625bacf5..be44dce8a8aca 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -243,9 +243,9 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess - .struct_span_warn(span, - "This needs a `'static` lifetime or the \ - `static_in_const` feature, see #35897") + .struct_span_err(span, + "this needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") .emit(); } ty::ReStatic diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index 07d6edb1f3b15..d3c0bf0021350 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,7 +15,7 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature +//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -28,7 +28,7 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature +//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index d721c8bb6d2bf..bcc1d3c3e42d9 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - //~| WARNING: This needs a `'static` lifetime or the `static_in_const` feature + //~| ERROR: this needs a `'static` lifetime or the `static_in_const` feature 0 }; } From 2859177ea0f36863672e05b8be044b4c94cfd8f1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:29:37 +0200 Subject: [PATCH 3/5] added feature gate test --- .../compile-fail/feature-gate-static-in-const.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-static-in-const.rs diff --git a/src/test/compile-fail/feature-gate-static-in-const.rs b/src/test/compile-fail/feature-gate-static-in-const.rs new file mode 100644 index 0000000000000..c1fc7cdd06cd0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-static-in-const.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static FOO: &str = "this will work once static_in_const is stable"; +//~^ ERROR: this needs a `'static` lifetime or the `static_in_const` feature + +fn main() {} From df611a62bb4407373bea42d2fb623e6579972521 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:34:41 +0200 Subject: [PATCH 4/5] added feature description to reference --- src/doc/reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index f29cdf6b08035..b72c3743a69ce 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2441,6 +2441,9 @@ The currently implemented features of the reference compiler are: into a Rust program. This capability, especially the signature for the annotated function, is subject to change. +* `static_in_const` - Enables lifetime elision with a `'static` default for + `const` and `static` item declarations. + * `thread_local` - The usage of the `#[thread_local]` attribute is experimental and should be seen as unstable. This attribute is used to declare a `static` as being unique per-thread leveraging From 76a2f9f4542ccb15d6eb2426b162ce91094f04e2 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 22:59:21 +0200 Subject: [PATCH 5/5] fix feature error, test fallout --- src/librustc_typeck/rscope.rs | 18 +++++++++--------- src/test/compile-fail/const-unsized.rs | 2 -- src/test/compile-fail/issue-24446.rs | 1 - 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index be44dce8a8aca..131ecfc6e0c78 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -229,17 +229,9 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { fn anon_regions(&self, - _span: Span, + span: Span, count: usize) -> Result, Option>> { - Ok(vec![ty::ReStatic; count]) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess @@ -248,6 +240,14 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> `static_in_const` feature, see #35897") .emit(); } + Ok(vec![ty::ReStatic; count]) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { ty::ReStatic } } diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index d3c0bf0021350..a73164b957c83 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,7 +15,6 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -28,7 +27,6 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index bcc1d3c3e42d9..acd50bcf9e112 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,6 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - //~| ERROR: this needs a `'static` lifetime or the `static_in_const` feature 0 }; }