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
::{self, keywords}
;
25 use syntax
::visit
::{self, Visitor}
;
29 struct AstValidator
<'a
> {
33 impl<'a
> AstValidator
<'a
> {
34 fn err_handler(&self) -> &errors
::Handler
{
35 &self.session
.parse_sess
.span_diagnostic
38 fn check_label(&self, label
: Ident
, span
: Span
, id
: NodeId
) {
39 if label
.name
== keywords
::StaticLifetime
.name() {
40 self.err_handler().span_err(span
, &format
!("invalid label name `{}`", label
.name
));
42 if label
.name
.as_str() == "'_" {
43 self.session
.add_lint(lint
::builtin
::LIFETIME_UNDERSCORE
,
46 format
!("invalid label name `{}`", label
.name
));
50 fn invalid_visibility(&self, vis
: &Visibility
, span
: Span
, note
: Option
<&str>) {
51 if vis
!= &Visibility
::Inherited
{
52 let mut err
= struct_span_err
!(self.session
,
55 "unnecessary visibility qualifier");
56 if vis
== &Visibility
::Public
{
57 err
.span_label(span
, &format
!("`pub` not needed here"));
59 if let Some(note
) = note
{
66 fn check_decl_no_pat
<ReportFn
: Fn(Span
, bool
)>(&self, decl
: &FnDecl
, report_err
: ReportFn
) {
67 for arg
in &decl
.inputs
{
69 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Immutable
), _
, None
) |
71 PatKind
::Ident(..) => report_err(arg
.pat
.span
, true),
72 _
=> report_err(arg
.pat
.span
, false),
77 fn check_trait_fn_not_const(&self, constness
: Spanned
<Constness
>) {
78 match constness
.node
{
80 struct_span_err
!(self.session
, constness
.span
, E0379
,
81 "trait fns cannot be declared const")
82 .span_label(constness
.span
, &format
!("trait fns cannot be const"))
90 impl<'a
> Visitor
for AstValidator
<'a
> {
91 fn visit_lifetime(&mut self, lt
: &Lifetime
) {
92 if lt
.name
.as_str() == "'_" {
93 self.session
.add_lint(lint
::builtin
::LIFETIME_UNDERSCORE
,
96 format
!("invalid lifetime name `{}`", lt
.name
));
99 visit
::walk_lifetime(self, lt
)
102 fn visit_expr(&mut self, expr
: &Expr
) {
104 ExprKind
::While(.., Some(ident
)) |
105 ExprKind
::Loop(_
, Some(ident
)) |
106 ExprKind
::WhileLet(.., Some(ident
)) |
107 ExprKind
::ForLoop(.., Some(ident
)) |
108 ExprKind
::Break(Some(ident
)) |
109 ExprKind
::Continue(Some(ident
)) => {
110 self.check_label(ident
.node
, ident
.span
, expr
.id
);
115 visit
::walk_expr(self, expr
)
118 fn visit_ty(&mut self, ty
: &Ty
) {
120 TyKind
::BareFn(ref bfty
) => {
121 self.check_decl_no_pat(&bfty
.decl
, |span
, _
| {
122 let mut err
= struct_span_err
!(self.session
,
125 "patterns aren't allowed in function pointer \
128 "this is a recent error, see issue #35203 for more details");
135 visit
::walk_ty(self, ty
)
138 fn visit_path(&mut self, path
: &Path
, id
: NodeId
) {
139 if path
.global
&& path
.segments
.len() > 0 {
140 let ident
= path
.segments
[0].identifier
;
141 if token
::Ident(ident
).is_path_segment_keyword() {
142 self.session
.add_lint(lint
::builtin
::SUPER_OR_SELF_IN_GLOBAL_PATH
,
145 format
!("global paths cannot start with `{}`", ident
));
149 visit
::walk_path(self, path
)
152 fn visit_item(&mut self, item
: &Item
) {
154 ItemKind
::Use(ref view_path
) => {
155 let path
= view_path
.node
.path();
156 if !path
.segments
.iter().all(|segment
| segment
.parameters
.is_empty()) {
158 .span_err(path
.span
, "type or lifetime parameters in import path");
161 ItemKind
::Impl(.., Some(..), _
, ref impl_items
) => {
162 self.invalid_visibility(&item
.vis
, item
.span
, None
);
163 for impl_item
in impl_items
{
164 self.invalid_visibility(&impl_item
.vis
, impl_item
.span
, None
);
165 if let ImplItemKind
::Method(ref sig
, _
) = impl_item
.node
{
166 self.check_trait_fn_not_const(sig
.constness
);
170 ItemKind
::Impl(.., None
, _
, _
) => {
171 self.invalid_visibility(&item
.vis
,
173 Some("place qualifiers on individual impl items instead"));
175 ItemKind
::DefaultImpl(..) => {
176 self.invalid_visibility(&item
.vis
, item
.span
, None
);
178 ItemKind
::ForeignMod(..) => {
179 self.invalid_visibility(&item
.vis
,
181 Some("place qualifiers on individual foreign items \
184 ItemKind
::Enum(ref def
, _
) => {
185 for variant
in &def
.variants
{
186 for field
in variant
.node
.data
.fields() {
187 self.invalid_visibility(&field
.vis
, field
.span
, None
);
191 ItemKind
::Trait(.., ref trait_items
) => {
192 for trait_item
in trait_items
{
193 if let TraitItemKind
::Method(ref sig
, ref block
) = trait_item
.node
{
194 self.check_trait_fn_not_const(sig
.constness
);
196 self.check_decl_no_pat(&sig
.decl
, |span
, _
| {
197 self.session
.add_lint(lint
::builtin
::PATTERNS_IN_FNS_WITHOUT_BODY
,
199 "patterns aren't allowed in methods \
200 without bodies".to_string());
206 ItemKind
::Mod(_
) => {
207 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
208 attr
::first_attr_value_str_by_name(&item
.attrs
, "path");
210 ItemKind
::Union(ref vdata
, _
) => {
211 if !vdata
.is_struct() {
212 self.err_handler().span_err(item
.span
,
213 "tuple and unit unions are not permitted");
215 if vdata
.fields().len() == 0 {
216 self.err_handler().span_err(item
.span
,
217 "unions cannot have zero fields");
223 visit
::walk_item(self, item
)
226 fn visit_foreign_item(&mut self, fi
: &ForeignItem
) {
228 ForeignItemKind
::Fn(ref decl
, _
) => {
229 self.check_decl_no_pat(decl
, |span
, is_recent
| {
230 let mut err
= struct_span_err
!(self.session
,
233 "patterns aren't allowed in foreign function \
235 err
.span_label(span
, &format
!("pattern not allowed in foreign function"));
238 "this is a recent error, see issue #35203 for more details");
243 ForeignItemKind
::Static(..) => {}
246 visit
::walk_foreign_item(self, fi
)
249 fn visit_vis(&mut self, vis
: &Visibility
) {
251 Visibility
::Restricted { ref path, .. }
=> {
252 if !path
.segments
.iter().all(|segment
| segment
.parameters
.is_empty()) {
254 .span_err(path
.span
, "type or lifetime parameters in visibility path");
260 visit
::walk_vis(self, vis
)
264 pub fn check_crate(session
: &Session
, krate
: &Crate
) {
265 visit
::walk_crate(&mut AstValidator { session: session }
, krate
)