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 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..131ecfc6e0c78 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>> { + if !self.tcx.sess.features.borrow().static_in_const { + self.tcx + .sess + .struct_span_err(span, + "this needs a `'static` lifetime or the \ + `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 + } +} + /// 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/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() {} diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index b9382520cf9d3..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 - 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); - } -}