Auto merge of #33794 - petrochenkov:sanity, r=nrc

Add AST validation pass and move some checks to it

The purpose of this pass is to catch constructions that fit into AST data structures, but not permitted by the language. As an example, `impl`s don't have visibilities, but for convenience and uniformity with other items they are represented with a structure `Item` which has `Visibility` field.

This pass is intended to run after expansion of macros and syntax extensions (and before lowering to HIR), so it can catch erroneous constructions that were generated by them. This pass allows to remove ad hoc semantic checks from the parser, which can be overruled by syntax extensions and occasionally macros.

The checks can be put here if they are simple, local, don't require results of any complex analysis like name resolution or type checking and maybe don't logically fall into other passes. I expect most of errors generated by this pass to be non-fatal and allowing the compilation to proceed.

I intend to move some more checks to this pass later and maybe extend it with new checks, like, for example, identifier validity. Given that syntax extensions are going to be stabilized in the measurable future, it's important that they would not be able to subvert usual language rules.

In this patch I've added two new checks - a check for labels named `'static` and a check for lifetimes and labels named `'_`. The first one gives a hard error, the second one - a future compatibility warning.
Fixes https://github.com/rust-lang/rust/issues/33059 ([breaking-change])
cc https://github.com/rust-lang/rfcs/pull/1177

r? @nrc
This commit is contained in:
bors 2016-06-01 06:21:53 -07:00
commit c2cab1fd58
21 changed files with 318 additions and 220 deletions

View file

@ -21,5 +21,5 @@ enum Foo {
}
fn main() {
println!("{}", match Bar { Bar => 1, Baz => 2, Bazar => 3 })
println!("{}", match Bar { Bar => 1, Baz => 2, Bazar => 3 }) //~ ERROR unresolved name `Bar`
}

View file

@ -12,7 +12,7 @@ mod a {
struct A;
impl Default for A {
pub fn default() -> A {
pub fn default() -> A { //~ ERROR unnecessary visibility qualifier
A;
}
}

View file

@ -0,0 +1,15 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {
'static: loop { //~ ERROR invalid label name `'static`
break 'static //~ ERROR invalid label name `'static`
}
}

View file

@ -0,0 +1,27 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(lifetime_underscore)]
fn _f<'_>() //~ ERROR invalid lifetime name `'_`
//~^ WARN this was previously accepted
-> &'_ u8 //~ ERROR invalid lifetime name `'_`
//~^ WARN this was previously accepted
{
panic!();
}
fn main() {
'_: loop { //~ ERROR invalid label name `'_`
//~^ WARN this was previously accepted
break '_ //~ ERROR invalid label name `'_`
//~^ WARN this was previously accepted
}
}

View file

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub extern {
//~^ ERROR unnecessary visibility
pub extern { //~ ERROR unnecessary visibility qualifier
pub fn bar();
}
@ -19,10 +18,10 @@ trait A {
struct B;
pub impl B {} //~ ERROR: unnecessary visibility
pub impl B {} //~ ERROR unnecessary visibility qualifier
pub impl A for B { //~ ERROR: unnecessary visibility
pub fn foo(&self) {} //~ ERROR: unnecessary visibility
pub impl A for B { //~ ERROR unnecessary visibility qualifier
pub fn foo(&self) {} //~ ERROR unnecessary visibility qualifier
}
pub fn main() {}

View file

@ -16,9 +16,11 @@ macro_rules! m {
struct S<T>(T);
m!{ S<u8> } //~ ERROR type or lifetime parameters in visibility path
//~^ ERROR failed to resolve module path. Not a module `S`
mod foo {
struct S(pub(foo<T>) ()); //~ ERROR type or lifetime parameters in visibility path
//~^ ERROR type name `T` is undefined or not in scope
}
fn main() {}

View file

@ -9,10 +9,17 @@
// except according to those terms.
#![feature(rustc_attrs)]
#![allow(unused_imports, dead_code)]
struct S;
struct Z;
mod foo {
use ::super::{S, Z}; //~ WARN global paths cannot start with `super`
//~^ WARN this was previously accepted by the compiler but is being phased out
pub fn g() {
use ::super::main; //~ WARN expected identifier, found keyword `super`
use ::super::main; //~ WARN global paths cannot start with `super`
//~^ WARN this was previously accepted by the compiler but is being phased out
main();
}

View file

@ -15,14 +15,12 @@ pub trait E {
}
impl E for A {
pub fn foo(&self) {} //~ ERROR: unnecessary visibility
pub fn foo(&self) {} //~ ERROR: unnecessary visibility qualifier
}
enum Foo {
V1 { pub f: i32 }, //~ ERROR unnecessary visibility qualifier
//| NOTE visibility qualifiers have no effect on variant fields
V2(pub i32), //~ ERROR unnecessary visibility qualifier
//| NOTE visibility qualifiers have no effect on variant fields
}
fn main() {}