diff options
Diffstat (limited to 'compiler/rustc_ast_passes/src/feature_gate.rs')
-rw-r--r-- | compiler/rustc_ast_passes/src/feature_gate.rs | 111 |
1 files changed, 71 insertions, 40 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 89ba6f936..96042ea30 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd}; -use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_errors::{Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; use rustc_session::Session; @@ -10,6 +10,10 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi; +use thin_vec::ThinVec; +use tracing::debug; + +use crate::errors; macro_rules! gate_feature_fn { ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ @@ -136,6 +140,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, + crate::fluent_generated::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(errors::ForbiddenLifetimeBound { spans }); + } + } + } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -147,7 +179,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) { @@ -186,13 +218,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { || attr.has_name(sym::rustc_const_stable) || attr.has_name(sym::rustc_default_body_unstable) { - struct_span_err!( - self.sess, - attr.span, - E0734, - "stability attributes may not be used outside of the standard library", - ) - .emit(); + self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span }); } } } @@ -220,7 +246,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ItemKind::Struct(..) => { for attr in self.sess.filter_by_name(&i.attrs, sym::repr) { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { gate_feature_post!( &self, @@ -306,6 +332,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 +345,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 { @@ -346,7 +386,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ).span_suggestion_verbose( lhs.span.shrink_to_lo(), "you might have meant to introduce a new binding", - "let ".to_string(), + "let ", Applicability::MachineApplicable, ).emit(); } @@ -437,12 +477,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"); } @@ -580,13 +629,13 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { return; } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { - let mut err = struct_span_err!( - sess.parse_sess.span_diagnostic, - attr.span, - E0554, - "`#![feature]` may not be used on the {} release channel", - option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)") - ); + let mut err = errors::FeatureOnNonNightly { + span: attr.span, + channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), + stable_features: vec![], + sugg: None, + }; + let mut all_stable = true; for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) @@ -597,24 +646,15 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .next(); if let Some(since) = stable_since { - err.help(&format!( - "the feature `{}` has been stable since {} and no longer requires \ - an attribute to enable", - name, since - )); + err.stable_features.push(errors::StableFeature { name, since }); } else { all_stable = false; } } if all_stable { - err.span_suggestion( - attr.span, - "remove the attribute", - "", - Applicability::MachineApplicable, - ); + err.sugg = Some(attr.span); } - err.emit(); + sess.parse_sess.span_diagnostic.emit_err(err); } } } @@ -637,16 +677,7 @@ fn check_incompatible_features(sess: &Session) { if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) { let spans = vec![f1_span, f2_span]; - sess.struct_span_err( - spans, - &format!( - "features `{}` and `{}` are incompatible, using them at the same time \ - is not allowed", - f1_name, f2_name - ), - ) - .help("remove one of these features") - .emit(); + sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name }); } } } |