summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast_passes/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs421
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs234
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs382
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs5
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs22
5 files changed, 453 insertions, 611 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 2d9d0073f..036643244 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,9 +13,8 @@ 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_macros::Subdiagnostic;
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -29,6 +28,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";
@@ -38,6 +39,13 @@ enum SelfSemantic {
No,
}
+/// What is the context that prevents using `~const`?
+enum DisallowTildeConstContext<'a> {
+ TraitObject,
+ ImplTrait,
+ Fn(FnKind<'a>),
+}
+
struct AstValidator<'a> {
session: &'a Session,
@@ -56,7 +64,7 @@ struct AstValidator<'a> {
/// e.g., `impl Iterator<Item = impl Debug>`.
outer_impl_trait: Option<Span>,
- is_tilde_const_allowed: bool,
+ disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
/// or `Foo::Bar<impl Trait>`
@@ -93,18 +101,26 @@ impl<'a> AstValidator<'a> {
self.is_impl_trait_banned = old;
}
- fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
- let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
+ fn with_tilde_const(
+ &mut self,
+ disallowed: Option<DisallowTildeConstContext<'a>>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
f(self);
- self.is_tilde_const_allowed = old;
+ self.disallow_tilde_const = old;
}
fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
- self.with_tilde_const(true, f)
+ self.with_tilde_const(None, f)
}
- fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
- self.with_tilde_const(false, f)
+ fn with_banned_tilde_const(
+ &mut self,
+ ctx: DisallowTildeConstContext<'a>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ self.with_tilde_const(Some(ctx), f)
}
fn with_let_management(
@@ -121,30 +137,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 +170,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,
@@ -193,7 +188,7 @@ impl<'a> AstValidator<'a> {
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer);
if outer.is_some() {
- self.with_banned_tilde_const(f);
+ self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
} else {
f(self);
}
@@ -205,10 +200,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 });
}
}
}
@@ -221,7 +213,10 @@ impl<'a> AstValidator<'a> {
TyKind::ImplTrait(..) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
}
- TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
+ TyKind::TraitObject(..) => self
+ .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
+ visit::walk_ty(this, t)
+ }),
TyKind::Path(ref qself, ref path) => {
// We allow these:
// - `Option<impl Trait>`
@@ -247,11 +242,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));
}
}
}
@@ -259,20 +252,6 @@ impl<'a> AstValidator<'a> {
}
}
- fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
- if let Some(ident) = field.ident {
- if ident.name == kw::Underscore {
- self.visit_vis(&field.vis);
- self.visit_ident(ident);
- self.visit_ty_common(&field.ty);
- self.walk_ty(&field.ty);
- walk_list!(self, visit_attribute, &field.attrs);
- return;
- }
- }
- self.visit_field_def(field);
- }
-
fn err_handler(&self) -> &rustc_errors::Handler {
&self.session.diagnostic()
}
@@ -280,38 +259,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 +293,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 +308,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 +316,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 +333,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 +341,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 +374,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 +384,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 +392,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 +842,10 @@ fn validate_generic_param_order(
let (kind, bounds, span) = (&param.kind, &param.bounds, ident.span);
let (ord_kind, ident) = match &param.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));
@@ -1097,8 +992,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_lifetime(self, lifetime);
}
- fn visit_field_def(&mut self, s: &'a FieldDef) {
- visit::walk_field_def(self, s)
+ fn visit_field_def(&mut self, field: &'a FieldDef) {
+ visit::walk_field_def(self, field)
}
fn visit_item(&mut self, item: &'a Item) {
@@ -1180,7 +1075,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 +1098,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 +1129,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");
@@ -1300,51 +1181,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_mod_file_item_asciionly(item.ident);
}
}
- ItemKind::Struct(ref vdata, ref generics) => match vdata {
- // Duplicating the `Visitor` logic allows catching all cases
- // of `Anonymous(Struct, Union)` outside of a field struct or union.
- //
- // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
- // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
- // it uses `visit_ty_common`, which doesn't contain that specific check.
- VariantData::Struct(ref fields, ..) => {
- self.visit_vis(&item.vis);
- self.visit_ident(item.ident);
- self.visit_generics(generics);
- self.with_banned_assoc_ty_bound(|this| {
- walk_list!(this, visit_struct_field_def, fields);
- });
- walk_list!(self, visit_attribute, &item.attrs);
- return;
- }
- _ => {}
- },
- ItemKind::Union(ref vdata, ref generics) => {
+ ItemKind::Union(ref vdata, ..) => {
if vdata.fields().is_empty() {
self.err_handler().span_err(item.span, "unions cannot have zero fields");
}
- match vdata {
- VariantData::Struct(ref fields, ..) => {
- self.visit_vis(&item.vis);
- self.visit_ident(item.ident);
- self.visit_generics(generics);
- self.with_banned_assoc_ty_bound(|this| {
- walk_list!(this, visit_struct_field_def, fields);
- });
- walk_list!(self, visit_attribute, &item.attrs);
- return;
- }
- _ => {}
- }
}
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 +1208,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 +1264,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);
@@ -1529,13 +1384,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
err.emit();
}
- (_, TraitBoundModifier::MaybeConst) => {
- if !self.is_tilde_const_allowed {
- self.err_handler()
- .struct_span_err(bound.span(), "`~const` is not allowed here")
- .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
- .emit();
- }
+ (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
+ let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
+ match reason {
+ DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
+ DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
+ DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
+ DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
+ };
+ err.emit();
}
(_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler()
@@ -1548,25 +1405,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) {
@@ -1650,10 +1499,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
let tilde_const_allowed =
- matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
+ matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
- self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
+ let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
+
+ self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1668,12 +1519,22 @@ 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 {
+ AssocItemKind::Type(box TyAlias {
generics,
where_clauses,
where_predicates_split,
@@ -1681,7 +1542,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 +1565,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);
}
}
@@ -1708,7 +1573,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
match item.kind {
- AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
+ AssocItemKind::Type(box TyAlias { ref generics, ref bounds, ref ty, .. })
if ctxt == AssocCtxt::Trait =>
{
self.visit_vis(&item.vis);
@@ -1883,7 +1748,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
in_const_trait_impl: false,
has_proc_macro_decls: false,
outer_impl_trait: None,
- is_tilde_const_allowed: false,
+ disallow_tilde_const: None,
is_impl_trait_banned: false,
is_assoc_ty_bound_banned: false,
forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
@@ -1895,15 +1760,17 @@ 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 {
+#[derive(Clone, Copy, Subdiagnostic)]
+pub(crate) enum ForbiddenLetReason {
/// `let` is not valid and the source environment is not important
GenericForbidden,
/// A let chain with the `||` operator
- NotSupportedOr(Span),
+ #[note(not_supported_or)]
+ NotSupportedOr(#[primary_span] 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),
+ #[note(not_supported_parentheses)]
+ NotSupportedParentheses(#[primary_span] 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..59f582f10
--- /dev/null
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -0,0 +1,234 @@
+//! Errors emitted by ast_passes.
+
+use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_span::{Span, Symbol};
+
+use crate::ast_validation::ForbiddenLetReason;
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_let)]
+#[note]
+pub struct ForbiddenLet {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub(crate) reason: ForbiddenLetReason,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_let_stable)]
+#[note]
+pub struct ForbiddenLetStable {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_assoc_constraint)]
+pub struct ForbiddenAssocConstraint {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_keyword_lifetime)]
+pub struct KeywordLifetime {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_invalid_label)]
+pub struct InvalidLabel {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_invalid_visibility, code = "E0449")]
+pub struct InvalidVisibility {
+ #[primary_span]
+ pub span: Span,
+ #[label(implied)]
+ pub implied: Option<Span>,
+ #[subdiagnostic]
+ pub note: Option<InvalidVisibilityNote>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum InvalidVisibilityNote {
+ #[note(individual_impl_items)]
+ IndividualImplItems,
+ #[note(individual_foreign_items)]
+ IndividualForeignItems,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_trait_fn_const, code = "E0379")]
+pub struct TraitFnConst {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_lifetime_bound)]
+pub struct ForbiddenLifetimeBound {
+ #[primary_span]
+ pub spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_non_lifetime_param)]
+pub struct ForbiddenNonLifetimeParam {
+ #[primary_span]
+ pub spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_too_many)]
+pub struct FnParamTooMany {
+ #[primary_span]
+ pub span: Span,
+ pub max_num_args: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_c_var_args_only)]
+pub struct FnParamCVarArgsOnly {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_c_var_args_not_last)]
+pub struct FnParamCVarArgsNotLast {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_doc_comment)]
+pub struct FnParamDocComment {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_forbidden_attr)]
+pub struct FnParamForbiddenAttr {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_forbidden_self)]
+#[note]
+pub struct FnParamForbiddenSelf {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_default)]
+pub struct ForbiddenDefault {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub def_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[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(Diagnostic)]
+#[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(Diagnostic)]
+#[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(Diagnostic)]
+#[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(Diagnostic)]
+#[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(Diagnostic)]
+#[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(Diagnostic)]
+#[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 AddToDiagnostic for ExternBlockSuggestion {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ 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::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..546010135 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,17 +1,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_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
-use rustc_feature::{Features, GateIssue};
-use rustc_session::parse::{feature_err, feature_err_issue};
+use rustc_ast::{PatKind, RangeEnd};
+use rustc_errors::{struct_span_err, 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;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
use rustc_span::Span;
-
-use tracing::debug;
+use rustc_target::spec::abi;
macro_rules! gate_feature_fn {
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
@@ -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) {
@@ -74,210 +84,26 @@ impl<'a> PostExpansionVisitor<'a> {
}
}
- match symbol_unescaped.as_str() {
- // Stable
- "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
- | "system" => {}
- "rust-intrinsic" => {
- gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change");
- }
- "platform-intrinsic" => {
- gate_feature_post!(
- &self,
- platform_intrinsics,
- span,
- "platform intrinsics are experimental and possibly buggy"
- );
- }
- "vectorcall" => {
- gate_feature_post!(
- &self,
- abi_vectorcall,
- span,
- "vectorcall is experimental and subject to change"
- );
- }
- "thiscall" => {
- gate_feature_post!(
- &self,
- abi_thiscall,
- span,
- "thiscall is experimental and subject to change"
- );
- }
- "rust-call" => {
- gate_feature_post!(
- &self,
- unboxed_closures,
- span,
- "rust-call ABI is subject to change"
- );
- }
- "rust-cold" => {
- gate_feature_post!(
- &self,
- rust_cold_cc,
- span,
- "rust-cold is experimental and subject to change"
- );
- }
- "ptx-kernel" => {
- gate_feature_post!(
- &self,
- abi_ptx,
- span,
- "PTX ABIs are experimental and subject to change"
- );
- }
- "unadjusted" => {
- gate_feature_post!(
- &self,
- abi_unadjusted,
- span,
- "unadjusted ABI is an implementation detail and perma-unstable"
- );
- }
- "msp430-interrupt" => {
- gate_feature_post!(
- &self,
- abi_msp430_interrupt,
- span,
- "msp430-interrupt ABI is experimental and subject to change"
- );
- }
- "x86-interrupt" => {
- gate_feature_post!(
- &self,
- abi_x86_interrupt,
- span,
- "x86-interrupt ABI is experimental and subject to change"
- );
- }
- "amdgpu-kernel" => {
- gate_feature_post!(
- &self,
- abi_amdgpu_kernel,
- span,
- "amdgpu-kernel ABI is experimental and subject to change"
- );
- }
- "avr-interrupt" | "avr-non-blocking-interrupt" => {
- gate_feature_post!(
- &self,
- abi_avr_interrupt,
- span,
- "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change"
- );
- }
- "efiapi" => {
- gate_feature_post!(
- &self,
- abi_efiapi,
- span,
- "efiapi ABI is experimental and subject to change"
- );
- }
- "C-cmse-nonsecure-call" => {
- gate_feature_post!(
- &self,
- abi_c_cmse_nonsecure_call,
- span,
- "C-cmse-nonsecure-call ABI is experimental and subject to change"
- );
- }
- "C-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "C-unwind ABI is experimental and subject to change"
- );
- }
- "stdcall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "stdcall-unwind ABI is experimental and subject to change"
- );
- }
- "system-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "system-unwind ABI is experimental and subject to change"
- );
- }
- "thiscall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "thiscall-unwind ABI is experimental and subject to change"
- );
- }
- "cdecl-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "cdecl-unwind ABI is experimental and subject to change"
- );
- }
- "fastcall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "fastcall-unwind ABI is experimental and subject to change"
- );
- }
- "vectorcall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
+ match abi::is_enabled(&self.features, span, symbol_unescaped.as_str()) {
+ Ok(()) => (),
+ Err(abi::AbiDisabled::Unstable { feature, explain }) => {
+ feature_err_issue(
+ &self.sess.parse_sess,
+ feature,
span,
- "vectorcall-unwind ABI is experimental and subject to change"
- );
- }
- "aapcs-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "aapcs-unwind ABI is experimental and subject to change"
- );
- }
- "win64-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "win64-unwind ABI is experimental and subject to change"
- );
- }
- "sysv64-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "sysv64-unwind ABI is experimental and subject to change"
- );
- }
- "wasm" => {
- gate_feature_post!(
- &self,
- wasm_abi,
- span,
- "wasm ABI is experimental and subject to change"
- );
+ GateIssue::Language,
+ explain,
+ )
+ .emit();
}
- abi => {
+ Err(abi::AbiDisabled::Unrecognized) => {
if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
self.sess.parse_sess.span_diagnostic.delay_span_bug(
span,
- &format!("unrecognized ABI not caught in lowering: {}", abi),
+ &format!(
+ "unrecognized ABI not caught in lowering: {}",
+ symbol_unescaped.as_str()
+ ),
);
}
}
@@ -290,65 +116,6 @@ impl<'a> PostExpansionVisitor<'a> {
}
}
- fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
- let has_fields = variants.iter().any(|variant| match variant.data {
- VariantData::Tuple(..) | VariantData::Struct(..) => true,
- VariantData::Unit(..) => false,
- });
-
- let discriminant_spans = variants
- .iter()
- .filter(|variant| match variant.data {
- VariantData::Tuple(..) | VariantData::Struct(..) => false,
- VariantData::Unit(..) => true,
- })
- .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
- .collect::<Vec<_>>();
-
- if !discriminant_spans.is_empty() && has_fields {
- let mut err = feature_err(
- &self.sess.parse_sess,
- sym::arbitrary_enum_discriminant,
- discriminant_spans.clone(),
- "custom discriminant values are not allowed in enums with tuple or struct variants",
- );
- for sp in discriminant_spans {
- err.span_label(sp, "disallowed custom discriminant");
- }
- for variant in variants.iter() {
- match &variant.data {
- VariantData::Struct(..) => {
- err.span_label(variant.span, "struct variant defined here");
- }
- VariantData::Tuple(..) => {
- err.span_label(variant.span, "tuple variant defined here");
- }
- VariantData::Unit(..) => {}
- }
- }
- err.emit();
- }
- }
-
- 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 +184,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,
@@ -465,26 +233,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
- ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
- for variant in variants {
- match (&variant.data, &variant.disr_expr) {
- (ast::VariantData::Unit(..), _) => {}
- (_, Some(disr_expr)) => gate_feature_post!(
- &self,
- arbitrary_enum_discriminant,
- disr_expr.value.span,
- "discriminants on non-unit variants are experimental"
- ),
- _ => {}
- }
- }
-
- let has_feature = self.features.arbitrary_enum_discriminant;
- if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
- self.maybe_report_invalid_custom_discriminants(&variants);
- }
- }
-
ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
@@ -562,6 +310,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 +338,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 +364,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)
@@ -652,7 +401,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
gate_feature_post!(
&self,
- half_open_range_patterns,
+ half_open_range_patterns_in_slices,
pat.span,
"`X..` patterns in slices are experimental"
);
@@ -690,7 +439,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 +457,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::Type(box ast::TyAlias { ref ty, .. }) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
@@ -720,7 +469,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,
@@ -781,7 +529,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(generators, "yield syntax is experimental");
gate_all!(raw_ref_op, "raw address of syntax is experimental");
gate_all!(const_trait_impl, "const trait impls are experimental");
- gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
+ gate_all!(
+ half_open_range_patterns_in_slices,
+ "half-open range patterns in slices are unstable"
+ );
gate_all!(inline_const, "inline-const is experimental");
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
gate_all!(associated_const_equality, "associated const equality is incomplete");
@@ -789,14 +540,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 +556,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..f58fffc91 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -9,10 +9,13 @@
#![feature(if_let_guard)]
#![feature(iter_is_partitioned)]
#![feature(let_chains)]
-#![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;