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
)