]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_ast_passes/src/ast_validation.rs
Rollup merge of #103543 - ehuss:update-books, r=ehuss
[rust.git] / compiler / rustc_ast_passes / src / ast_validation.rs
index 1dc8b85d7e6e770e7f52d8fcfb865b6e6a2bfd88..0366432440445e46e3f750aeddbd021aeff9a047 100644 (file)
@@ -39,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,
 
@@ -57,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>`
@@ -94,18 +101,26 @@ fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
         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(
@@ -155,7 +170,7 @@ fn check_gat_where(
                 DEPRECATED_WHERE_CLAUSE_LOCATION,
                 id,
                 where_clauses.0.1,
-                fluent::ast_passes::deprecated_where_clause_location,
+                fluent::ast_passes_deprecated_where_clause_location,
                 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
                     where_clauses.1.1.shrink_to_hi(),
                     suggestion,
@@ -173,7 +188,7 @@ fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
     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);
         }
@@ -198,7 +213,10 @@ fn walk_ty(&mut self, t: &'a Ty) {
             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>`
@@ -234,20 +252,6 @@ fn walk_ty(&mut self, t: &'a Ty) {
         }
     }
 
-    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()
     }
@@ -988,8 +992,8 @@ fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
         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) {
@@ -1177,42 +1181,10 @@ fn visit_item(&mut self, item: &'a Item) {
                     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);
@@ -1412,13 +1384,15 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
                     );
                     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 functions, traits' associated types and functions, 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()
@@ -1524,10 +1498,13 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
             });
         }
 
-        let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { .. }))
-            || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+        let tilde_const_allowed =
+            matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
+                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+
+        let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
 
-        self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
+        self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1771,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),
@@ -1788,12 +1765,12 @@ pub(crate) enum ForbiddenLetReason {
     /// `let` is not valid and the source environment is not important
     GenericForbidden,
     /// A let chain with the `||` operator
-    #[note(ast_passes::not_supported_or)]
+    #[note(not_supported_or)]
     NotSupportedOr(#[primary_span] Span),
     /// A let chain with invalid parentheses
     ///
     /// For example, `let 1 = 1 && (expr && expr)` is allowed
     /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
-    #[note(ast_passes::not_supported_parentheses)]
+    #[note(not_supported_parentheses)]
     NotSupportedParentheses(#[primary_span] Span),
 }