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_visibility(&self, vis
: &Visibility
, span
: Span
, note
: Option
<&str>) {
46 if vis
!= &Visibility
::Inherited
{
47 let mut err
= struct_span_err
!(self.session
,
50 "unnecessary visibility qualifier");
51 if vis
== &Visibility
::Public
{
52 err
.span_label(span
, "`pub` not needed here");
54 if let Some(note
) = note
{
61 fn check_decl_no_pat
<ReportFn
: Fn(Span
, bool
)>(&self, decl
: &FnDecl
, report_err
: ReportFn
) {
62 for arg
in &decl
.inputs
{
64 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Immutable
), _
, None
) |
66 PatKind
::Ident(..) => report_err(arg
.pat
.span
, true),
67 _
=> report_err(arg
.pat
.span
, false),
72 fn check_trait_fn_not_const(&self, constness
: Spanned
<Constness
>) {
73 match constness
.node
{
75 struct_span_err
!(self.session
, constness
.span
, E0379
,
76 "trait fns cannot be declared const")
77 .span_label(constness
.span
, "trait fns cannot be const")
84 fn no_questions_in_bounds(&self, bounds
: &TyParamBounds
, where_
: &str, is_trait
: bool
) {
86 if let TraitTyParamBound(ref poly
, TraitBoundModifier
::Maybe
) = *bound
{
87 let mut err
= self.err_handler().struct_span_err(poly
.span
,
88 &format
!("`?Trait` is not permitted in {}", where_
));
90 err
.note(&format
!("traits are `?{}` by default", poly
.trait_ref
.path
));
98 impl<'a
> Visitor
<'a
> for AstValidator
<'a
> {
99 fn visit_lifetime(&mut self, lt
: &'a Lifetime
) {
100 if lt
.ident
.name
== "'_" {
101 self.err_handler().span_err(lt
.span
, &format
!("invalid lifetime name `{}`", lt
.ident
));
104 visit
::walk_lifetime(self, lt
)
107 fn visit_expr(&mut self, expr
: &'a Expr
) {
109 ExprKind
::While(.., Some(ident
)) |
110 ExprKind
::Loop(_
, Some(ident
)) |
111 ExprKind
::WhileLet(.., Some(ident
)) |
112 ExprKind
::ForLoop(.., Some(ident
)) |
113 ExprKind
::Break(Some(ident
), _
) |
114 ExprKind
::Continue(Some(ident
)) => {
115 self.check_label(ident
.node
, ident
.span
);
120 visit
::walk_expr(self, expr
)
123 fn visit_ty(&mut self, ty
: &'a Ty
) {
125 TyKind
::BareFn(ref bfty
) => {
126 self.check_decl_no_pat(&bfty
.decl
, |span
, _
| {
127 let mut err
= struct_span_err
!(self.session
,
130 "patterns aren't allowed in function pointer \
133 "this is a recent error, see issue #35203 for more details");
137 TyKind
::TraitObject(ref bounds
) => {
138 let mut any_lifetime_bounds
= false;
139 for bound
in bounds
{
140 if let RegionTyParamBound(ref lifetime
) = *bound
{
141 if any_lifetime_bounds
{
142 span_err
!(self.session
, lifetime
.span
, E0226
,
143 "only a single explicit lifetime bound is permitted");
146 any_lifetime_bounds
= true;
149 self.no_questions_in_bounds(bounds
, "trait object types", false);
151 TyKind
::ImplTrait(ref bounds
) => {
153 .any(|b
| if let TraitTyParamBound(..) = *b { true }
else { false }
) {
154 self.err_handler().span_err(ty
.span
, "at least one trait must be specified");
160 visit
::walk_ty(self, ty
)
163 fn visit_path(&mut self, path
: &'a Path
, _
: NodeId
) {
164 if path
.segments
.len() >= 2 && path
.is_global() {
165 let ident
= path
.segments
[1].identifier
;
166 if token
::Ident(ident
).is_path_segment_keyword() {
168 .span_err(path
.span
, &format
!("global paths cannot start with `{}`", ident
));
172 visit
::walk_path(self, path
)
175 fn visit_item(&mut self, item
: &'a Item
) {
177 ItemKind
::Use(ref view_path
) => {
178 let path
= view_path
.node
.path();
179 if path
.segments
.iter().any(|segment
| segment
.parameters
.is_some()) {
181 .span_err(path
.span
, "type or lifetime parameters in import path");
184 ItemKind
::Impl(.., Some(..), _
, ref impl_items
) => {
185 self.invalid_visibility(&item
.vis
, item
.span
, None
);
186 for impl_item
in impl_items
{
187 self.invalid_visibility(&impl_item
.vis
, impl_item
.span
, None
);
188 if let ImplItemKind
::Method(ref sig
, _
) = impl_item
.node
{
189 self.check_trait_fn_not_const(sig
.constness
);
193 ItemKind
::Impl(.., None
, _
, _
) => {
194 self.invalid_visibility(&item
.vis
,
196 Some("place qualifiers on individual impl items instead"));
198 ItemKind
::DefaultImpl(..) => {
199 self.invalid_visibility(&item
.vis
, item
.span
, None
);
201 ItemKind
::ForeignMod(..) => {
202 self.invalid_visibility(&item
.vis
,
204 Some("place qualifiers on individual foreign items \
207 ItemKind
::Enum(ref def
, _
) => {
208 for variant
in &def
.variants
{
209 for field
in variant
.node
.data
.fields() {
210 self.invalid_visibility(&field
.vis
, field
.span
, None
);
214 ItemKind
::Trait(.., ref bounds
, ref trait_items
) => {
215 self.no_questions_in_bounds(bounds
, "supertraits", true);
216 for trait_item
in trait_items
{
217 if let TraitItemKind
::Method(ref sig
, ref block
) = trait_item
.node
{
218 self.check_trait_fn_not_const(sig
.constness
);
220 self.check_decl_no_pat(&sig
.decl
, |span
, _
| {
221 self.session
.add_lint(lint
::builtin
::PATTERNS_IN_FNS_WITHOUT_BODY
,
223 "patterns aren't allowed in methods \
224 without bodies".to_string());
230 ItemKind
::Mod(_
) => {
231 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
232 attr
::first_attr_value_str_by_name(&item
.attrs
, "path");
233 if item
.attrs
.iter().any(|attr
| attr
.check_name("warn_directory_ownership")) {
234 let lint
= lint
::builtin
::LEGACY_DIRECTORY_OWNERSHIP
;
235 let msg
= "cannot declare a new module at this location";
236 self.session
.add_lint(lint
, item
.id
, item
.span
, msg
.to_string());
239 ItemKind
::Union(ref vdata
, _
) => {
240 if !vdata
.is_struct() {
241 self.err_handler().span_err(item
.span
,
242 "tuple and unit unions are not permitted");
244 if vdata
.fields().len() == 0 {
245 self.err_handler().span_err(item
.span
,
246 "unions cannot have zero fields");
252 visit
::walk_item(self, item
)
255 fn visit_foreign_item(&mut self, fi
: &'a ForeignItem
) {
257 ForeignItemKind
::Fn(ref decl
, _
) => {
258 self.check_decl_no_pat(decl
, |span
, is_recent
| {
259 let mut err
= struct_span_err
!(self.session
,
262 "patterns aren't allowed in foreign function \
264 err
.span_label(span
, "pattern not allowed in foreign function");
267 "this is a recent error, see issue #35203 for more details");
272 ForeignItemKind
::Static(..) => {}
275 visit
::walk_foreign_item(self, fi
)
278 fn visit_vis(&mut self, vis
: &'a Visibility
) {
280 Visibility
::Restricted { ref path, .. }
=> {
281 if !path
.segments
.iter().all(|segment
| segment
.parameters
.is_none()) {
283 .span_err(path
.span
, "type or lifetime parameters in visibility path");
289 visit
::walk_vis(self, vis
)
292 fn visit_generics(&mut self, g
: &'a Generics
) {
293 let mut seen_default
= None
;
294 for ty_param
in &g
.ty_params
{
295 if ty_param
.default.is_some() {
296 seen_default
= Some(ty_param
.span
);
297 } else if let Some(span
) = seen_default
{
299 .span_err(span
, "type parameters with a default must be trailing");
303 for predicate
in &g
.where_clause
.predicates
{
304 if let WherePredicate
::EqPredicate(ref predicate
) = *predicate
{
305 self.err_handler().span_err(predicate
.span
, "equality constraints are not yet \
306 supported in where clauses (#20041)");
309 visit
::walk_generics(self, g
)
313 pub fn check_crate(session
: &Session
, krate
: &Crate
) {
314 visit
::walk_crate(&mut AstValidator { session: session }
, krate
)