Add feature gate for non_lifetime_binders
This commit is contained in:
parent
c5283576ec
commit
262a344d72
@ -294,27 +294,6 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
|
||||
// Check only lifetime parameters are present and that the lifetime
|
||||
// parameters that are present have no bounds.
|
||||
let non_lt_param_spans: Vec<_> = params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.session.emit_err(ForbiddenLifetimeBound { spans });
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => Some(param.ident.span),
|
||||
})
|
||||
.collect();
|
||||
if !non_lt_param_spans.is_empty() {
|
||||
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
self.check_decl_num_args(fn_decl);
|
||||
self.check_decl_cvaradic_pos(fn_decl);
|
||||
@ -745,7 +724,6 @@ impl<'a> AstValidator<'a> {
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
self.check_late_bound_lifetime_defs(&bfty.generic_params);
|
||||
if let Extern::Implicit(_) = bfty.ext {
|
||||
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
|
||||
self.maybe_lint_missing_abi(sig_span, ty.id);
|
||||
@ -1318,9 +1296,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
match predicate {
|
||||
WherePredicate::BoundPredicate(bound_pred) => {
|
||||
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
|
||||
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
|
||||
|
||||
// This is slightly complicated. Our representation for poly-trait-refs contains a single
|
||||
// binder and thus we only allow a single level of quantification. However,
|
||||
// the syntax of Rust permits quantification in two places in where clauses,
|
||||
@ -1396,11 +1371,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
|
||||
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
|
||||
visit::walk_poly_trait_ref(self, t);
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self, s: &'a VariantData) {
|
||||
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
|
||||
}
|
||||
@ -1437,10 +1407,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
|
||||
self.check_late_bound_lifetime_defs(generic_params);
|
||||
}
|
||||
|
||||
if let FnKind::Fn(
|
||||
_,
|
||||
_,
|
||||
|
@ -11,6 +11,8 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
use crate::errors::ForbiddenLifetimeBound;
|
||||
|
||||
macro_rules! gate_feature_fn {
|
||||
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
|
||||
let (visitor, has_feature, span, name, explain, help) =
|
||||
@ -136,6 +138,34 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
}
|
||||
ImplTraitVisitor { vis: self }.visit_ty(ty);
|
||||
}
|
||||
|
||||
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
|
||||
// Check only lifetime parameters are present and that the lifetime
|
||||
// parameters that are present have no bounds.
|
||||
let non_lt_param_spans: Vec<_> = params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
ast::GenericParamKind::Lifetime { .. } => None,
|
||||
_ => Some(param.ident.span),
|
||||
})
|
||||
.collect();
|
||||
// FIXME: gate_feature_post doesn't really handle multispans...
|
||||
if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders {
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::non_lifetime_binders,
|
||||
non_lt_param_spans,
|
||||
rustc_errors::fluent::ast_passes_forbidden_non_lifetime_param,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
for param in params {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.sess.emit_err(ForbiddenLifetimeBound { spans });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
@ -147,7 +177,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
..
|
||||
}) = attr_info
|
||||
{
|
||||
gate_feature_fn!(self, has_feature, attr.span, *name, descr);
|
||||
gate_feature_fn!(self, has_feature, attr.span, *name, *descr);
|
||||
}
|
||||
// Check unstable flavors of the `#[doc]` attribute.
|
||||
if attr.has_name(sym::doc) {
|
||||
@ -306,6 +336,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
ast::TyKind::BareFn(bare_fn_ty) => {
|
||||
// Function pointers cannot be `const`
|
||||
self.check_extern(bare_fn_ty.ext, ast::Const::No);
|
||||
self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
|
||||
}
|
||||
ast::TyKind::Never => {
|
||||
gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
|
||||
@ -318,6 +349,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
visit::walk_ty(self, ty)
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
||||
for predicate in &g.where_clause.predicates {
|
||||
match predicate {
|
||||
ast::WherePredicate::BoundPredicate(bound_pred) => {
|
||||
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
|
||||
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
visit::walk_generics(self, g);
|
||||
}
|
||||
|
||||
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
|
||||
if let ast::FnRetTy::Ty(output_ty) = ret_ty {
|
||||
if let ast::TyKind::Never = output_ty.kind {
|
||||
@ -437,12 +481,21 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
visit::walk_pat(self, pattern)
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
|
||||
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
|
||||
visit::walk_poly_trait_ref(self, t);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
if let Some(header) = fn_kind.header() {
|
||||
// Stability of const fn methods are covered in `visit_assoc_item` below.
|
||||
self.check_extern(header.ext, header.constness);
|
||||
}
|
||||
|
||||
if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
|
||||
self.check_late_bound_lifetime_defs(generic_params);
|
||||
}
|
||||
|
||||
if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
|
||||
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
|
||||
}
|
||||
|
@ -731,7 +731,7 @@ pub fn eval_condition(
|
||||
sess,
|
||||
sym::cfg_target_compact,
|
||||
cfg.span,
|
||||
&"compact `cfg(target(..))` is experimental and subject to change"
|
||||
"compact `cfg(target(..))` is experimental and subject to change"
|
||||
).emit();
|
||||
}
|
||||
|
||||
|
@ -473,6 +473,8 @@ declare_features! (
|
||||
(active, no_sanitize, "1.42.0", Some(39699), None),
|
||||
/// Allows using the `non_exhaustive_omitted_patterns` lint.
|
||||
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
|
||||
/// Allows `for<T>` binders in where-clauses
|
||||
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(1), None),
|
||||
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
|
||||
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
|
||||
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
|
||||
|
@ -4,7 +4,7 @@ use crate::cgu_reuse_tracker::CguReuse;
|
||||
use crate::parse::ParseSess;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::util::literal::LitError;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
|
||||
@ -27,12 +27,22 @@ pub struct CguNotRecorded<'a> {
|
||||
pub cgu_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_feature_gate_error, code = "E0658")]
|
||||
pub struct FeatureGateError<'a> {
|
||||
#[primary_span]
|
||||
pub struct FeatureGateError {
|
||||
pub span: MultiSpan,
|
||||
pub explain: &'a str,
|
||||
pub explain: DiagnosticMessage,
|
||||
}
|
||||
|
||||
impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
handler: &'a rustc_errors::Handler,
|
||||
) -> rustc_errors::DiagnosticBuilder<'a, T> {
|
||||
let mut diag = handler.struct_diagnostic(self.explain);
|
||||
diag.set_span(self.span);
|
||||
diag.code(error_code!(E0658));
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
@ -88,7 +88,7 @@ pub fn feature_err<'a>(
|
||||
sess: &'a ParseSess,
|
||||
feature: Symbol,
|
||||
span: impl Into<MultiSpan>,
|
||||
explain: &str,
|
||||
explain: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
feature_err_issue(sess, feature, span, GateIssue::Language, explain)
|
||||
}
|
||||
@ -103,7 +103,7 @@ pub fn feature_err_issue<'a>(
|
||||
feature: Symbol,
|
||||
span: impl Into<MultiSpan>,
|
||||
issue: GateIssue,
|
||||
explain: &str,
|
||||
explain: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let span = span.into();
|
||||
|
||||
@ -114,7 +114,7 @@ pub fn feature_err_issue<'a>(
|
||||
.map(|err| err.cancel());
|
||||
}
|
||||
|
||||
let mut err = sess.create_err(FeatureGateError { span, explain });
|
||||
let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() });
|
||||
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
|
||||
err
|
||||
}
|
||||
|
@ -1016,6 +1016,7 @@ symbols! {
|
||||
non_ascii_idents,
|
||||
non_exhaustive,
|
||||
non_exhaustive_omitted_patterns_lint,
|
||||
non_lifetime_binders,
|
||||
non_modrs_mods,
|
||||
nontemporal_store,
|
||||
noop_method_borrow,
|
||||
|
@ -16,17 +16,24 @@ error: lifetime bounds cannot be used in this context
|
||||
LL | type C = for<'b, 'a: 'b +> fn();
|
||||
| ^^
|
||||
|
||||
error: only lifetime parameters can be used in this context
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:4:18
|
||||
|
|
||||
LL | type D = for<'a, T> fn();
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: only lifetime parameters can be used in this context
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:5:18
|
||||
|
|
||||
LL | type E = dyn for<T> Fn();
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,8 +1,12 @@
|
||||
error: only lifetime parameters can be used in this context
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/disallow-const.rs:4:15
|
||||
|
|
||||
LL | for<const N: i32> || -> () {};
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,8 +1,12 @@
|
||||
error: only lifetime parameters can be used in this context
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/disallow-ty.rs:4:9
|
||||
|
|
||||
LL | for<T> || -> () {};
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,21 +1,3 @@
|
||||
error: only lifetime parameters can be used in this context
|
||||
--> $DIR/cfg-generic-params.rs:7:45
|
||||
|
|
||||
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
|
||||
| ^
|
||||
|
||||
error: only lifetime parameters can be used in this context
|
||||
--> $DIR/cfg-generic-params.rs:11:51
|
||||
|
|
||||
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
|
||||
| ^
|
||||
|
||||
error: only lifetime parameters can be used in this context
|
||||
--> $DIR/cfg-generic-params.rs:15:54
|
||||
|
|
||||
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
|
||||
| ^
|
||||
|
||||
error: cannot find attribute `unknown` in this scope
|
||||
--> $DIR/cfg-generic-params.rs:19:29
|
||||
|
|
||||
@ -46,5 +28,33 @@ error: cannot find attribute `unknown` in this scope
|
||||
LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/cfg-generic-params.rs:7:45
|
||||
|
|
||||
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/cfg-generic-params.rs:11:51
|
||||
|
|
||||
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/cfg-generic-params.rs:15:54
|
||||
|
|
||||
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -0,0 +1,4 @@
|
||||
fn foo() where for<T> T:, {}
|
||||
//~^ ERROR only lifetime parameters can be used in this context
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,12 @@
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/feature-gate-non_lifetime_binders.rs:1:20
|
||||
|
|
||||
LL | fn foo() where for<T> T:, {}
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -1,14 +1,21 @@
|
||||
error: only lifetime parameters can be used in this context
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/hrtb-wrong-kind.rs:1:18
|
||||
|
|
||||
LL | fn a() where for<T> T: Copy {}
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: only lifetime parameters can be used in this context
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/hrtb-wrong-kind.rs:4:24
|
||||
|
|
||||
LL | fn b() where for<const C: usize> [(); C]: Copy {}
|
||||
| ^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -88,12 +88,6 @@ error: expected identifier, found `>`
|
||||
LL | type QuiteBroken = fn<const>();
|
||||
| ^ expected identifier
|
||||
|
||||
error: lifetime bounds cannot be used in this context
|
||||
--> $DIR/recover-fn-ptr-with-generics.rs:22:26
|
||||
|
|
||||
LL | let _: extern fn<'a: 'static>();
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0412]: cannot find type `T` in this scope
|
||||
--> $DIR/recover-fn-ptr-with-generics.rs:5:27
|
||||
|
|
||||
@ -106,6 +100,12 @@ error[E0412]: cannot find type `T` in this scope
|
||||
LL | type Identity = fn<T>(T) -> T;
|
||||
| ^ not found in this scope
|
||||
|
||||
error: lifetime bounds cannot be used in this context
|
||||
--> $DIR/recover-fn-ptr-with-generics.rs:22:26
|
||||
|
|
||||
LL | let _: extern fn<'a: 'static>();
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user