diff --git a/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md b/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md new file mode 100644 index 00000000000..f50472fb41e --- /dev/null +++ b/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md @@ -0,0 +1,45 @@ +# `infer_static_outlives_requirements` + +The tracking issue for this feature is: [#44493] + +[#44493]: https://github.com/rust-lang/rust/issues/44493 + +------------------------ +The `infer_static_outlives_requirements` feature indicates that certain +`'static` outlives requirements can be infered by the compiler rather than +stating them explicitly. + +Note: It is an accompanying feature to `infer_outlives_requirements`, +which must be enabled to infer outlives requirements. + +For example, currently generic struct definitions that contain +references, require where-clauses of the form T: 'static. By using +this feature the outlives predicates will be infered, although +they may still be written explicitly. + +```rust,ignore (pseudo-Rust) +struct Foo where U: 'static { // <-- currently required + bar: Bar +} +struct Bar { + x: T, +} +``` + + +## Examples: + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] +#![feature(infer_static_outlives_requirements)] + +#[rustc_outlives] +// Implicitly infer U: 'static +struct Foo { + bar: Bar +} +struct Bar { + x: T, +} +``` + diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index 5cb1822b04e..0d833c50d7e 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -27,7 +27,7 @@ pub fn insert_outlives_predicate<'tcx>( ) { // If the `'a` region is bound within the field type itself, we // don't want to propagate this constraint to the header. - if !is_free_region(outlived_region) { + if !is_free_region(tcx, outlived_region) { return; } @@ -120,7 +120,7 @@ pub fn insert_outlives_predicate<'tcx>( } UnpackedKind::Lifetime(r) => { - if !is_free_region(r) { + if !is_free_region(tcx, r) { return; } required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); @@ -128,19 +128,36 @@ pub fn insert_outlives_predicate<'tcx>( } } -fn is_free_region(region: Region<'_>) -> bool { +fn is_free_region<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, region: Region<'_>) -> bool { // First, screen for regions that might appear in a type header. match region { - // *These* correspond to `T: 'a` relationships where `'a` is - // either declared on the type or `'static`: + // These correspond to `T: 'a` relationships: // // struct Foo<'a, T> { // field: &'a T, // this would generate a ReEarlyBound referencing `'a` - // field2: &'static T, // this would generate a ReStatic // } // // We care about these, so fall through. - RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true, + RegionKind::ReEarlyBound(_) => true, + + // These correspond to `T: 'static` relationships which can be + // rather surprising. We are therefore putting this behind a + // feature flag: + // + // struct Foo<'a, T> { + // field: &'static T, // this would generate a ReStatic + // } + RegionKind::ReStatic => { + if tcx + .sess + .features_untracked() + .infer_static_outlives_requirements + { + true + } else { + false + } + } // Late-bound regions can appear in `fn` types: // diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 30137439e77..087fec09719 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -396,6 +396,9 @@ declare_features! ( // Infer outlives requirements; RFC 2093 (active, infer_outlives_requirements, "1.26.0", Some(44493), None), + // Infer outlives requirements; RFC 2093 + (active, infer_static_outlives_requirements, "1.26.0", Some(44493), None), + // Multiple patterns with `|` in `if let` and `while let` (active, if_while_or_patterns, "1.26.0", Some(48215), None), @@ -1057,6 +1060,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "infer outlives requirements is an experimental feature", cfg_fn!(infer_outlives_requirements))), + // RFC #2093 + ("infer_static_outlives_requirements", Normal, Gated(Stability::Unstable, + "infer_static_outlives_requirements", + "infer 'static lifetime requirements", + cfg_fn!(infer_static_outlives_requirements))), + // RFC 2070 ("panic_implementation", Normal, Gated(Stability::Unstable, "panic_implementation", diff --git a/src/test/ui/feature-gate-infer_static_outlives_requirements.rs b/src/test/ui/feature-gate-infer_static_outlives_requirements.rs new file mode 100644 index 00000000000..7b68449859e --- /dev/null +++ b/src/test/ui/feature-gate-infer_static_outlives_requirements.rs @@ -0,0 +1,22 @@ +// 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. + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Type T needs to outlive lifetime 'static. +struct Foo { + bar: Bar //~ ERROR 15:5: 15:16: the parameter type `U` may not live long enough [E0310] +} +struct Bar { + x: T, +} + + +fn main() { } diff --git a/src/test/ui/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gate-infer_static_outlives_requirements.stderr new file mode 100644 index 00000000000..13022b901a7 --- /dev/null +++ b/src/test/ui/feature-gate-infer_static_outlives_requirements.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/feature-gate-infer_static_outlives_requirements.rs:15:5 + | +LL | struct Foo { + | - help: consider adding an explicit lifetime bound `U: 'static`... +LL | bar: Bar //~ ERROR 15:5: 15:16: the parameter type `U` may not live long enough [E0310] + | ^^^^^^^^^^^ + | +note: ...so that the type `U` will meet its required lifetime bounds + --> $DIR/feature-gate-infer_static_outlives_requirements.rs:15:5 + | +LL | bar: Bar //~ ERROR 15:5: 15:16: the parameter type `U` may not live long enough [E0310] + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs new file mode 100644 index 00000000000..72d5127c294 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.rs @@ -0,0 +1,29 @@ +// 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. + +// ignore-tidy-linelength + +#![feature(infer_outlives_requirements)] + +/* + * We don't infer `T: 'static` outlives relationships by default. + * Instead an additional feature gate `infer_static_outlives_requirements` + * is required. + */ + +struct Foo { + bar: Bar //~ ERROR 22:5: 22:16: the parameter type `U` may not live long enough [E0310] +} +struct Bar { + x: T, +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr new file mode 100644 index 00000000000..775ac215e19 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/dont-infer-static.rs:22:5 + | +LL | struct Foo { + | - help: consider adding an explicit lifetime bound `U: 'static`... +LL | bar: Bar //~ ERROR 22:5: 22:16: the parameter type `U` may not live long enough [E0310] + | ^^^^^^^^^^^ + | +note: ...so that the type `U` will meet its required lifetime bounds + --> $DIR/dont-infer-static.rs:22:5 + | +LL | bar: Bar //~ ERROR 22:5: 22:16: the parameter type `U` may not live long enough [E0310] + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/rfc-2093-infer-outlives/infer-static.rs b/src/test/ui/rfc-2093-infer-outlives/infer-static.rs new file mode 100644 index 00000000000..aeca18c24b3 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/infer-static.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] +#![feature(infer_static_outlives_requirements)] + +#[rustc_outlives] +struct Foo { //~ ERROR 16:1: 18:2: rustc_outlives + bar: Bar +} +struct Bar { + x: T, +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr new file mode 100644 index 00000000000..f167e522df6 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/infer-static.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/infer-static.rs:16:1 + | +LL | / struct Foo { //~ ERROR 16:1: 18:2: rustc_outlives +LL | | bar: Bar +LL | | } + | |_^ + | + = note: U : 'static + +error: aborting due to previous error +