diff options
Diffstat (limited to 'compiler/rustc_ast_passes')
-rw-r--r-- | compiler/rustc_ast_passes/Cargo.toml | 1 | ||||
-rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 298 | ||||
-rw-r--r-- | compiler/rustc_ast_passes/src/errors.rs | 245 | ||||
-rw-r--r-- | compiler/rustc_ast_passes/src/feature_gate.rs | 97 | ||||
-rw-r--r-- | compiler/rustc_ast_passes/src/lib.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_ast_passes/src/node_count.rs | 22 |
6 files changed, 393 insertions, 276 deletions
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 22742b2ad..37eff9207 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -11,6 +11,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 2d9d0073f..b1d10e07a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,9 +13,7 @@ use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -29,6 +27,8 @@ use rustc_target::spec::abi; use std::mem; use std::ops::{Deref, DerefMut}; +use crate::errors::*; + const MORE_EXTERN: &str = "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; @@ -121,30 +121,9 @@ impl<'a> AstValidator<'a> { fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) { let sess = &self.session; if sess.opts.unstable_features.is_nightly_build() { - let err = "`let` expressions are not supported here"; - let mut diag = sess.struct_span_err(expr.span, err); - diag.note("only supported directly in conditions of `if` and `while` expressions"); - match forbidden_let_reason { - ForbiddenLetReason::GenericForbidden => {} - ForbiddenLetReason::NotSupportedOr(span) => { - diag.span_note( - span, - "`||` operators are not supported in let chain expressions", - ); - } - ForbiddenLetReason::NotSupportedParentheses(span) => { - diag.span_note( - span, - "`let`s wrapped in parentheses are not supported in a context with let \ - chains", - ); - } - } - diag.emit(); + sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason }); } else { - sess.struct_span_err(expr.span, "expected expression, found statement (`let`)") - .note("variable declaration using `let` is a statement") - .emit(); + sess.emit_err(ForbiddenLetStable { span: expr.span }); } } @@ -175,7 +154,7 @@ impl<'a> AstValidator<'a> { DEPRECATED_WHERE_CLAUSE_LOCATION, id, where_clauses.0.1, - "where clause not allowed here", + fluent::ast_passes::deprecated_where_clause_location, BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( where_clauses.1.1.shrink_to_hi(), suggestion, @@ -205,10 +184,7 @@ impl<'a> AstValidator<'a> { AssocConstraintKind::Equality { .. } => {} AssocConstraintKind::Bound { .. } => { if self.is_assoc_ty_bound_banned { - self.err_handler().span_err( - constraint.span, - "associated type bounds are not allowed within structs, enums, or unions", - ); + self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span }); } } } @@ -247,11 +223,9 @@ impl<'a> AstValidator<'a> { for (i, segment) in path.segments.iter().enumerate() { // Allow `impl Trait` iff we're on the final path segment if i == path.segments.len() - 1 { - self.visit_path_segment(path.span, segment); + self.visit_path_segment(segment); } else { - self.with_banned_impl_trait(|this| { - this.visit_path_segment(path.span, segment) - }); + self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); } } } @@ -280,38 +254,33 @@ impl<'a> AstValidator<'a> { fn check_lifetime(&self, ident: Ident) { let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); + self.session.emit_err(KeywordLifetime { span: ident.span }); } } fn check_label(&self, ident: Ident) { if ident.without_first_quote().is_reserved() { - self.err_handler() - .span_err(ident.span, &format!("invalid label name `{}`", ident.name)); + self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name }); } } - fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { + fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) { if let VisibilityKind::Inherited = vis.kind { return; } - let mut err = - struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); - if vis.kind.is_pub() { - err.span_label(vis.span, "`pub` not permitted here because it's implied"); - } - if let Some(note) = note { - err.note(note); - } - err.emit(); + self.session.emit_err(InvalidVisibility { + span: vis.span, + implied: if vis.kind.is_pub() { Some(vis.span) } else { None }, + note, + }); } fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) { for Param { pat, .. } in &decl.inputs { match pat.kind { - PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {} - PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => { + PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {} + PatKind::Ident(BindingAnnotation::MUT, ident, None) => { report_err(pat.span, Some(ident), true) } _ => report_err(pat.span, None, false), @@ -319,31 +288,9 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) { - if let Async::Yes { span, .. } = asyncness { - struct_span_err!( - self.session, - fn_span, - E0706, - "functions in traits cannot be declared `async`" - ) - .span_label(span, "`async` because of this") - .note("`async` trait functions are not currently supported") - .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait") - .emit(); - } - } - fn check_trait_fn_not_const(&self, constness: Const) { if let Const::Yes(span) = constness { - struct_span_err!( - self.session, - span, - E0379, - "functions in traits cannot be declared const" - ) - .span_label(span, "functions in traits cannot be const") - .emit(); + self.session.emit_err(TraitFnConst { span }); } } @@ -356,8 +303,7 @@ impl<'a> AstValidator<'a> { GenericParamKind::Lifetime { .. } => { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - self.err_handler() - .span_err(spans, "lifetime bounds cannot be used in this context"); + self.session.emit_err(ForbiddenLifetimeBound { spans }); } None } @@ -365,10 +311,7 @@ impl<'a> AstValidator<'a> { }) .collect(); if !non_lt_param_spans.is_empty() { - self.err_handler().span_err( - non_lt_param_spans, - "only lifetime parameters can be used in this context", - ); + self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans }); } } @@ -385,10 +328,7 @@ impl<'a> AstValidator<'a> { let max_num_args: usize = u16::MAX.into(); if fn_decl.inputs.len() > max_num_args { let Param { span, .. } = fn_decl.inputs[0]; - self.err_handler().span_fatal( - span, - &format!("function can not have more than {} arguments", max_num_args), - ); + self.session.emit_fatal(FnParamTooMany { span, max_num_args }); } } @@ -396,19 +336,13 @@ impl<'a> AstValidator<'a> { match &*fn_decl.inputs { [Param { ty, span, .. }] => { if let TyKind::CVarArgs = ty.kind { - self.err_handler().span_err( - *span, - "C-variadic function must be declared with at least one named argument", - ); + self.session.emit_err(FnParamCVarArgsOnly { span: *span }); } } [ps @ .., _] => { for Param { ty, span, .. } in ps { if let TyKind::CVarArgs = ty.kind { - self.err_handler().span_err( - *span, - "`...` must be the last argument of a C-variadic function", - ); + self.session.emit_err(FnParamCVarArgsNotLast { span: *span }); } } } @@ -435,19 +369,9 @@ impl<'a> AstValidator<'a> { }) .for_each(|attr| { if attr.is_doc_comment() { - self.err_handler() - .struct_span_err( - attr.span, - "documentation comments cannot be applied to function parameters", - ) - .span_label(attr.span, "doc comments are not allowed here") - .emit(); + self.session.emit_err(FnParamDocComment { span: attr.span }); } else { - self.err_handler().span_err( - attr.span, - "allow, cfg, cfg_attr, deny, expect, \ - forbid, and warn are the only allowed built-in attributes in function parameters", - ); + self.session.emit_err(FnParamForbiddenAttr { span: attr.span }); } }); } @@ -455,14 +379,7 @@ impl<'a> AstValidator<'a> { fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { if param.is_self() { - self.err_handler() - .struct_span_err( - param.span, - "`self` parameter is only allowed in associated functions", - ) - .span_label(param.span, "not semantically valid as function parameter") - .note("associated functions are those in `impl` or `trait` definitions") - .emit(); + self.session.emit_err(FnParamForbiddenSelf { span: param.span }); } } } @@ -470,47 +387,20 @@ impl<'a> AstValidator<'a> { fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); - self.err_handler() - .struct_span_err(span, "`default` is only allowed on items in trait impls") - .span_label(def_span, "`default` because of this") - .emit(); + self.session.emit_err(ForbiddenDefault { span, def_span }); } } - fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { - self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ()); - } - - fn error_item_without_body_with_help( - &self, - sp: Span, - ctx: &str, - msg: &str, - sugg: &str, - help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>), - ) { + /// If `sp` ends with a semicolon, returns it as a `Span` + /// Otherwise, returns `sp.shrink_to_hi()` + fn ending_semi_or_hi(&self, sp: Span) -> Span { let source_map = self.session.source_map(); let end = source_map.end_point(sp); - let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { + + if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { end } else { sp.shrink_to_hi() - }; - let mut err = self.err_handler().struct_span_err(sp, msg); - err.span_suggestion( - replace_span, - &format!("provide a definition for the {}", ctx), - sugg, - Applicability::HasPlaceholders, - ); - help(&mut err); - err.emit(); - } - - fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) { - if body.is_none() { - let msg = format!("associated {} in `impl` without body", ctx); - self.error_item_without_body(sp, ctx, &msg, sugg); } } @@ -947,10 +837,10 @@ fn validate_generic_param_order( let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span); let (ord_kind, ident) = match ¶m.kind { GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()), - GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()), + GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()), GenericParamKind::Const { ref ty, kw_span: _, default: _ } => { let ty = pprust::ty_to_string(ty); - (ParamKindOrd::Const, format!("const {}: {}", ident, ty)) + (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty)) } }; param_idents.push((kind, ord_kind, bounds, idx, ident)); @@ -1180,7 +1070,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility( &item.vis, - Some("place qualifiers on individual impl items instead"), + Some(InvalidVisibilityNote::IndividualImplItems), ); if let Unsafe::Yes(span) = unsafety { error(span, "unsafe").code(error_code!(E0197)).emit(); @@ -1203,37 +1093,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_defaultness(item.span, defaultness); if body.is_none() { - let msg = "free function without a body"; - let ext = sig.header.ext; - - let f = |e: &mut DiagnosticBuilder<'_, _>| { - if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext - { - let start_suggestion = if let Extern::Explicit(abi, _) = ext { - format!("extern \"{}\" {{", abi.symbol_unescaped) - } else { - "extern {".to_owned() - }; - - let end_suggestion = " }".to_owned(); - let end_span = item.span.shrink_to_hi(); - - e - .multipart_suggestion( - "if you meant to declare an externally defined function, use an `extern` block", - vec![(*start_span, start_suggestion), (end_span, end_suggestion)], - Applicability::MaybeIncorrect, - ); - } - }; - - self.error_item_without_body_with_help( - item.span, - "function", - msg, - " { <body> }", - f, - ); + self.session.emit_err(FnWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + extern_block_suggestion: match sig.header.ext { + Extern::None => None, + Extern::Implicit(start_span) => Some(ExternBlockSuggestion { + start_span, + end_span: item.span.shrink_to_hi(), + abi: None, + }), + Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion { + start_span, + end_span: item.span.shrink_to_hi(), + abi: Some(abi.symbol_unescaped), + }), + }, + }); } self.visit_vis(&item.vis); @@ -1248,7 +1124,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, - Some("place qualifiers on individual foreign items instead"), + Some(InvalidVisibilityNote::IndividualForeignItems), ); if let Unsafe::Yes(span) = unsafety { self.err_handler().span_err(span, "extern block cannot be declared unsafe"); @@ -1339,12 +1215,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Const(def, .., None) => { self.check_defaultness(item.span, def); - let msg = "free constant item without body"; - self.error_item_without_body(item.span, "constant", msg, " = <expr>;"); + self.session.emit_err(ConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } ItemKind::Static(.., None) => { - let msg = "free static item without body"; - self.error_item_without_body(item.span, "static", msg, " = <expr>;"); + self.session.emit_err(StaticWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } ItemKind::TyAlias(box TyAlias { defaultness, @@ -1355,8 +1235,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }) => { self.check_defaultness(item.span, defaultness); if ty.is_none() { - let msg = "free type alias without body"; - self.error_item_without_body(item.span, "type", msg, " = <type>;"); + self.session.emit_err(TyAliasWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } self.check_type_no_bounds(bounds, "this context"); if where_clauses.1.0 { @@ -1409,7 +1291,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Mirrors `visit::walk_generic_args`, but tracks relevant state. - fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) { + fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) { match *generic_args { GenericArgs::AngleBracketed(ref data) => { self.check_generic_args_before_constraints(data); @@ -1548,25 +1430,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_param_bound(self, bound) } - fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { + 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, m); + 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)) } - fn visit_enum_def( - &mut self, - enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId, - _: Span, - ) { - self.with_banned_assoc_ty_bound(|this| { - visit::walk_enum_def(this, enum_definition, generics, item_id) - }) + fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) { + self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition)) } fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { @@ -1653,7 +1527,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. })) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); - self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span)); + self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk)); } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { @@ -1668,10 +1542,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if ctxt == AssocCtxt::Impl { match &item.kind { AssocItemKind::Const(_, _, body) => { - self.check_impl_item_provided(item.span, body, "constant", " = <expr>;"); + if body.is_none() { + self.session.emit_err(AssocConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::Fn(box Fn { body, .. }) => { - self.check_impl_item_provided(item.span, body, "function", " { <body> }"); + if body.is_none() { + self.session.emit_err(AssocFnWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::TyAlias(box TyAlias { generics, @@ -1681,7 +1565,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ty, .. }) => { - self.check_impl_item_provided(item.span, ty, "type", " = <type>;"); + if ty.is_none() { + self.session.emit_err(AssocTypeWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } self.check_type_no_bounds(bounds, "`impl`s"); if ty.is_some() { self.check_gat_where( @@ -1699,7 +1588,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.invalid_visibility(&item.vis, None); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.check_trait_fn_not_const(sig.header.constness); - self.check_trait_fn_not_async(item.span, sig.header.asyncness); } } @@ -1896,14 +1784,14 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> /// Used to forbid `let` expressions in certain syntactic locations. #[derive(Clone, Copy)] -enum ForbiddenLetReason { +pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator NotSupportedOr(Span), /// A let chain with invalid parentheses /// - /// For exemple, `let 1 = 1 && (expr && expr)` is allowed + /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not NotSupportedParentheses(Span), } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs new file mode 100644 index 000000000..4f3b09c58 --- /dev/null +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -0,0 +1,245 @@ +//! Errors emitted by ast_passes. + +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{Span, Symbol}; + +use crate::ast_validation::ForbiddenLetReason; + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_let)] +#[note] +pub struct ForbiddenLet { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub(crate) reason: ForbiddenLetReason, +} + +impl AddSubdiagnostic for ForbiddenLetReason { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::GenericForbidden => {} + Self::NotSupportedOr(span) => { + diag.span_note(span, fluent::ast_passes::not_supported_or); + } + Self::NotSupportedParentheses(span) => { + diag.span_note(span, fluent::ast_passes::not_supported_parentheses); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_let_stable)] +#[note] +pub struct ForbiddenLetStable { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_assoc_constraint)] +pub struct ForbiddenAssocConstraint { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::keyword_lifetime)] +pub struct KeywordLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::invalid_label)] +pub struct InvalidLabel { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::invalid_visibility, code = "E0449")] +pub struct InvalidVisibility { + #[primary_span] + pub span: Span, + #[label(ast_passes::implied)] + pub implied: Option<Span>, + #[subdiagnostic] + pub note: Option<InvalidVisibilityNote>, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidVisibilityNote { + #[note(ast_passes::individual_impl_items)] + IndividualImplItems, + #[note(ast_passes::individual_foreign_items)] + IndividualForeignItems, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::trait_fn_const, code = "E0379")] +pub struct TraitFnConst { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_lifetime_bound)] +pub struct ForbiddenLifetimeBound { + #[primary_span] + pub spans: Vec<Span>, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_non_lifetime_param)] +pub struct ForbiddenNonLifetimeParam { + #[primary_span] + pub spans: Vec<Span>, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_too_many)] +pub struct FnParamTooMany { + #[primary_span] + pub span: Span, + pub max_num_args: usize, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_c_var_args_only)] +pub struct FnParamCVarArgsOnly { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_c_var_args_not_last)] +pub struct FnParamCVarArgsNotLast { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_doc_comment)] +pub struct FnParamDocComment { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_forbidden_attr)] +pub struct FnParamForbiddenAttr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_forbidden_self)] +#[note] +pub struct FnParamForbiddenSelf { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_default)] +pub struct ForbiddenDefault { + #[primary_span] + pub span: Span, + #[label] + pub def_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::assoc_const_without_body)] +pub struct AssocConstWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = <expr>;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::assoc_fn_without_body)] +pub struct AssocFnWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::assoc_type_without_body)] +pub struct AssocTypeWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = <type>;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::const_without_body)] +pub struct ConstWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = <expr>;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::static_without_body)] +pub struct StaticWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = <expr>;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::ty_alias_without_body)] +pub struct TyAliasWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = <type>;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_without_body)] +pub struct FnWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")] + pub replace_span: Span, + #[subdiagnostic] + pub extern_block_suggestion: Option<ExternBlockSuggestion>, +} + +pub struct ExternBlockSuggestion { + pub start_span: Span, + pub end_span: Span, + pub abi: Option<Symbol>, +} + +impl AddSubdiagnostic for ExternBlockSuggestion { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + let start_suggestion = if let Some(abi) = self.abi { + format!("extern \"{}\" {{", abi) + } else { + "extern {".to_owned() + }; + let end_suggestion = " }".to_owned(); + + diag.multipart_suggestion( + fluent::ast_passes::extern_block_suggestion, + vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)], + Applicability::MaybeIncorrect, + ); + } +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 789eca1f0..aeff73c5b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -2,17 +2,15 @@ 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, VariantData}; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_feature::Features; use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_feature::{Features, GateIssue}; -use rustc_session::parse::{feature_err, feature_err_issue}; +use rustc_session::parse::{feature_err, feature_warn}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; - 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) = @@ -20,9 +18,7 @@ macro_rules! gate_feature_fn { let has_feature: bool = has_feature(visitor.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable($name) { - feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) - .help(help) - .emit(); + feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit(); } }}; ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ @@ -31,8 +27,19 @@ macro_rules! gate_feature_fn { let has_feature: bool = has_feature(visitor.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable($name) { - feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) - .emit(); + feature_err(&visitor.sess.parse_sess, name, span, explain).emit(); + } + }}; + (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ + let (visitor, has_feature, span, name, explain) = + (&*$visitor, $has_feature, $span, $name, $explain); + let has_feature: bool = has_feature(visitor.features); + debug!( + "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)", + name, span, has_feature + ); + if !has_feature && !span.allows_unstable($name) { + feature_warn(&visitor.sess.parse_sess, name, span, explain); } }}; } @@ -44,6 +51,9 @@ macro_rules! gate_feature_post { ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => { gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) }; + (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) + }; } pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) { @@ -330,25 +340,6 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn check_gat(&self, generics: &ast::Generics, span: Span) { - if !generics.params.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "generic associated types are unstable" - ); - } - if !generics.where_clause.predicates.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "where clauses on associated types are unstable" - ); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty) { struct ImplTraitVisitor<'a> { @@ -417,6 +408,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { || attr.has_name(sym::stable) || attr.has_name(sym::rustc_const_unstable) || attr.has_name(sym::rustc_const_stable) + || attr.has_name(sym::rustc_default_body_unstable) { struct_span_err!( self.sess, @@ -562,6 +554,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); } + ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::DynStar, ..) => { + gate_feature_post!(&self, dyn_star, ty.span, "dyn* trait objects are unstable"); + } _ => {} } visit::walk_ty(self, ty) @@ -587,11 +582,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { { // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type // ascription error, but the likely intention was to write a `let` statement. (#78907). - feature_err_issue( + feature_err( &self.sess.parse_sess, sym::type_ascription, lhs.span, - GateIssue::Language, "type ascription is experimental", ).span_suggestion_verbose( lhs.span.shrink_to_lo(), @@ -614,28 +608,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. if self.sess.parse_sess.span_diagnostic.err_count() == 0 { + // To avoid noise about type ascription in common syntax errors, + // only emit if it is the *only* error. gate_feature_post!( &self, type_ascription, e.span, "type ascription is experimental" ); + } else { + // And if it isn't, cancel the early-pass warning. + self.sess + .parse_sess + .span_diagnostic + .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning) + .map(|err| err.cancel()); } } ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } - ast::ExprKind::Block(_, Some(label)) => { - gate_feature_post!( - &self, - label_break_value, - label.ident.span, - "labels on blocks are unstable" - ); - } _ => {} } visit::walk_expr(self, e) @@ -690,7 +683,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); } - visit::walk_fn(self, fn_kind, span) + visit::walk_fn(self, fn_kind) } fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { @@ -708,7 +701,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match i.kind { ast::AssocItemKind::Fn(_) => true, - ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => { + ast::AssocItemKind::TyAlias(box ast::TyAlias { ref ty, .. }) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, @@ -720,7 +713,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(generics, i.span); false } _ => false, @@ -789,14 +781,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). + // We emit an early future-incompatible warning for these. + // New syntax gates should go above here to get a hard error gate. macro_rules! gate_all { ($gate:ident, $msg:literal) => { - // FIXME(eddyb) do something more useful than always - // disabling these uses of early feature-gatings. - if false { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature_post!(&visitor, $gate, *span, $msg); - } + for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { + gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg); } }; } @@ -807,13 +797,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); gate_all!(try_blocks, "`try` blocks are unstable"); - gate_all!(label_break_value, "labels on blocks are unstable"); gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); - // To avoid noise about type ascription in common syntax errors, - // only emit if it is the *only* error. (Also check it last.) - if sess.parse_sess.span_diagnostic.err_count() == 0 { - gate_all!(type_ascription, "type ascription is experimental"); - } + gate_all!(type_ascription, "type ascription is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 9d52c3288..8aa9d57f0 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -9,10 +9,14 @@ #![feature(if_let_guard)] #![feature(iter_is_partitioned)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![recursion_limit = "256"] +#[macro_use] +extern crate tracing; + pub mod ast_validation; +mod errors; pub mod feature_gate; pub mod node_count; pub mod show_span; diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 9c7369c83..fa42f8778 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -63,9 +63,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: visit::FnKind<'_>, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, s) + walk_fn(self, fk) } fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { self.count += 1; @@ -79,9 +79,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) { self.count += 1; - walk_poly_trait_ref(self, t, m) + walk_poly_trait_ref(self, t) } fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; @@ -91,15 +91,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &EnumDef, - generics: &Generics, - item_id: NodeId, - _: Span, - ) { + fn visit_enum_def(&mut self, enum_definition: &EnumDef) { self.count += 1; - walk_enum_def(self, enum_definition, generics, item_id) + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &Variant) { self.count += 1; @@ -121,9 +115,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_use_tree(self, use_tree, id) } - fn visit_generic_args(&mut self, path_span: Span, generic_args: &GenericArgs) { + fn visit_generic_args(&mut self, generic_args: &GenericArgs) { self.count += 1; - walk_generic_args(self, path_span, generic_args) + walk_generic_args(self, generic_args) } fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) { self.count += 1; |