1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // Validate AST before lowering it to HIR
13 // This pass is supposed to catch things that fit into AST data structures,
14 // but not permitted by the language. It runs after expansion when AST is frozen,
15 // so it can check for erroneous constructions produced by syntax extensions.
16 // This pass is supposed to perform only simple checks not requiring name resolution
17 // or type checking or some other kind of complex analysis.
20 use rustc::session::Session;
23 use syntax::codemap::Spanned;
24 use syntax::parse::token;
25 use syntax::symbol::keywords;
26 use syntax::visit::{self, Visitor};
30 struct AstValidator<'a> {
34 impl<'a> AstValidator<'a> {
35 fn err_handler(&self) -> &errors::Handler {
36 &self.session.parse_sess.span_diagnostic
39 fn check_label(&self, label: Ident, span: Span) {
40 if label.name == keywords::StaticLifetime.name() || label.name == "'_" {
41 self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name));
45 fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
46 let has_non_exhaustive = variant.node.attrs.iter()
47 .any(|attr| attr.check_name("non_exhaustive"));
48 if has_non_exhaustive {
49 self.err_handler().span_err(variant.span,
50 "#[non_exhaustive] is not yet supported on variants");
54 fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) {
55 if vis != &Visibility::Inherited {
56 let mut err = struct_span_err!(self.session,
59 "unnecessary visibility qualifier");
60 if vis == &Visibility::Public {
61 err.span_label(span, "`pub` not needed here");
63 if let Some(note) = note {
70 fn check_decl_no_pat<ReportFn: Fn(Span, bool)>(&self, decl: &FnDecl, report_err: ReportFn) {
71 for arg in &decl.inputs {
73 PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
75 PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) =>
76 report_err(arg.pat.span, true),
77 _ => report_err(arg.pat.span, false),
82 fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
83 match constness.node {
85 struct_span_err!(self.session, constness.span, E0379,
86 "trait fns cannot be declared const")
87 .span_label(constness.span, "trait fns cannot be const")
94 fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) {
96 if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound {
97 let mut err = self.err_handler().struct_span_err(poly.span,
98 &format!("`?Trait` is not permitted in {}", where_));
100 err.note(&format!("traits are `?{}` by default", poly.trait_ref.path));
107 /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus),
108 /// or path for ranges.
110 /// FIXME: do we want to allow expr -> pattern conversion to create path expressions?
111 /// That means making this work:
113 /// ```rust,ignore (FIXME)
122 fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
124 ExprKind::Lit(..) => {}
125 ExprKind::Path(..) if allow_paths => {}
126 ExprKind::Unary(UnOp::Neg, ref inner)
127 if match inner.node { ExprKind::Lit(_) => true, _ => false } => {}
128 _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \
134 impl<'a> Visitor<'a> for AstValidator<'a> {
135 fn visit_expr(&mut self, expr: &'a Expr) {
137 ExprKind::While(.., Some(ident)) |
138 ExprKind::Loop(_, Some(ident)) |
139 ExprKind::WhileLet(.., Some(ident)) |
140 ExprKind::ForLoop(.., Some(ident)) |
141 ExprKind::Break(Some(ident), _) |
142 ExprKind::Continue(Some(ident)) => {
143 self.check_label(ident.node, ident.span);
148 visit::walk_expr(self, expr)
151 fn visit_ty(&mut self, ty: &'a Ty) {
153 TyKind::BareFn(ref bfty) => {
154 self.check_decl_no_pat(&bfty.decl, |span, _| {
155 struct_span_err!(self.session, span, E0561,
156 "patterns aren't allowed in function pointer types").emit();
159 TyKind::TraitObject(ref bounds, ..) => {
160 let mut any_lifetime_bounds = false;
161 for bound in bounds {
162 if let RegionTyParamBound(ref lifetime) = *bound {
163 if any_lifetime_bounds {
164 span_err!(self.session, lifetime.span, E0226,
165 "only a single explicit lifetime bound is permitted");
168 any_lifetime_bounds = true;
171 self.no_questions_in_bounds(bounds, "trait object types", false);
173 TyKind::ImplTrait(ref bounds) => {
175 .any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
176 self.err_handler().span_err(ty.span, "at least one trait must be specified");
182 visit::walk_ty(self, ty)
185 fn visit_path(&mut self, path: &'a Path, _: NodeId) {
186 if path.segments.len() >= 2 && path.is_global() {
187 let ident = path.segments[1].identifier;
188 if token::Ident(ident).is_path_segment_keyword() {
190 .span_err(path.span, &format!("global paths cannot start with `{}`", ident));
194 visit::walk_path(self, path)
197 fn visit_item(&mut self, item: &'a Item) {
199 ItemKind::Use(ref view_path) => {
200 let path = view_path.node.path();
201 path.segments.iter().find(|segment| segment.parameters.is_some()).map(|segment| {
202 self.err_handler().span_err(segment.parameters.as_ref().unwrap().span(),
203 "generic arguments in import path");
206 ItemKind::Impl(.., Some(..), _, ref impl_items) => {
207 self.invalid_visibility(&item.vis, item.span, None);
208 for impl_item in impl_items {
209 self.invalid_visibility(&impl_item.vis, impl_item.span, None);
210 if let ImplItemKind::Method(ref sig, _) = impl_item.node {
211 self.check_trait_fn_not_const(sig.constness);
215 ItemKind::Impl(.., None, _, _) => {
216 self.invalid_visibility(&item.vis,
218 Some("place qualifiers on individual impl items instead"));
220 ItemKind::AutoImpl(..) => {
221 self.invalid_visibility(&item.vis, item.span, None);
223 ItemKind::ForeignMod(..) => {
224 self.invalid_visibility(&item.vis,
226 Some("place qualifiers on individual foreign items \
229 ItemKind::Enum(ref def, _) => {
230 for variant in &def.variants {
231 self.invalid_non_exhaustive_attribute(variant);
232 for field in variant.node.data.fields() {
233 self.invalid_visibility(&field.vis, field.span, None);
237 ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
238 if is_auto == IsAuto::Yes {
239 // Auto traits cannot have generics, super traits nor contain items.
240 if !generics.ty_params.is_empty() {
241 self.err_handler().span_err(item.span,
242 "auto traits cannot have generics");
244 if !bounds.is_empty() {
245 self.err_handler().span_err(item.span,
246 "auto traits cannot have super traits");
248 if !trait_items.is_empty() {
249 self.err_handler().span_err(item.span,
250 "auto traits cannot contain items");
253 self.no_questions_in_bounds(bounds, "supertraits", true);
254 for trait_item in trait_items {
255 if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
256 self.check_trait_fn_not_const(sig.constness);
258 self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
260 self.session.buffer_lint(
261 lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
263 "patterns aren't allowed in methods without bodies");
265 struct_span_err!(self.session, span, E0642,
266 "patterns aren't allowed in methods without bodies").emit();
273 ItemKind::Mod(_) => {
274 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
275 attr::first_attr_value_str_by_name(&item.attrs, "path");
276 if item.attrs.iter().any(|attr| attr.check_name("warn_directory_ownership")) {
277 let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
278 let msg = "cannot declare a new module at this location";
279 self.session.buffer_lint(lint, item.id, item.span, msg);
282 ItemKind::Union(ref vdata, _) => {
283 if !vdata.is_struct() {
284 self.err_handler().span_err(item.span,
285 "tuple and unit unions are not permitted");
287 if vdata.fields().len() == 0 {
288 self.err_handler().span_err(item.span,
289 "unions cannot have zero fields");
295 visit::walk_item(self, item)
298 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
300 ForeignItemKind::Fn(ref decl, _) => {
301 self.check_decl_no_pat(decl, |span, _| {
302 struct_span_err!(self.session, span, E0130,
303 "patterns aren't allowed in foreign function declarations")
304 .span_label(span, "pattern not allowed in foreign function").emit();
307 ForeignItemKind::Static(..) | ForeignItemKind::Ty => {}
310 visit::walk_foreign_item(self, fi)
313 fn visit_vis(&mut self, vis: &'a Visibility) {
315 Visibility::Restricted { ref path, .. } => {
316 path.segments.iter().find(|segment| segment.parameters.is_some()).map(|segment| {
317 self.err_handler().span_err(segment.parameters.as_ref().unwrap().span(),
318 "generic arguments in visibility path");
324 visit::walk_vis(self, vis)
327 fn visit_generics(&mut self, g: &'a Generics) {
328 let mut seen_default = None;
329 for ty_param in &g.ty_params {
330 if ty_param.default.is_some() {
331 seen_default = Some(ty_param.span);
332 } else if let Some(span) = seen_default {
334 .span_err(span, "type parameters with a default must be trailing");
338 for predicate in &g.where_clause.predicates {
339 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
340 self.err_handler().span_err(predicate.span, "equality constraints are not yet \
341 supported in where clauses (#20041)");
344 visit::walk_generics(self, g)
347 fn visit_pat(&mut self, pat: &'a Pat) {
349 PatKind::Lit(ref expr) => {
350 self.check_expr_within_pat(expr, false);
352 PatKind::Range(ref start, ref end, _) => {
353 self.check_expr_within_pat(start, true);
354 self.check_expr_within_pat(end, true);
359 visit::walk_pat(self, pat)
363 pub fn check_crate(session: &Session, krate: &Crate) {
364 visit::walk_crate(&mut AstValidator { session: session }, krate)