diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index efcf95ec706b8..672ef108969e5 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -362,7 +362,11 @@ impl Default for Generics { fn default() -> Generics { Generics { params: Vec::new(), - where_clause: WhereClause { predicates: Vec::new(), span: DUMMY_SP }, + where_clause: WhereClause { + has_where_token: false, + predicates: Vec::new(), + span: DUMMY_SP, + }, span: DUMMY_SP, } } @@ -371,6 +375,11 @@ impl Default for Generics { /// A where-clause in a definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereClause { + /// `true` if we ate a `where` token: this can happen + /// if we parsed no predicates (e.g. `struct Foo where {} + /// This allows us to accurately pretty-print + /// in `nt_to_tokenstream` + pub has_where_token: bool, pub predicates: Vec, pub span: Span, } diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 7ececb814a6a3..66b8d7f97f0ed 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -786,7 +786,7 @@ pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) } pub fn noop_visit_where_clause(wc: &mut WhereClause, vis: &mut T) { - let WhereClause { predicates, span } = wc; + let WhereClause { has_where_token: _, predicates, span } = wc; visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); vis.visit_span(span); } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 872126646f33d..8ff80df527ce7 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -2593,7 +2593,7 @@ impl<'a> State<'a> { } crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) { - if where_clause.predicates.is_empty() { + if where_clause.predicates.is_empty() && !where_clause.has_where_token { return; } @@ -2739,7 +2739,11 @@ impl<'a> State<'a> { } let generics = ast::Generics { params: Vec::new(), - where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP }, + where_clause: ast::WhereClause { + has_where_token: false, + predicates: Vec::new(), + span: rustc_span::DUMMY_SP, + }, span: rustc_span::DUMMY_SP, }; let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; diff --git a/src/librustc_builtin_macros/deriving/generic/ty.rs b/src/librustc_builtin_macros/deriving/generic/ty.rs index 62cbdb19a8894..609feb6f259d6 100644 --- a/src/librustc_builtin_macros/deriving/generic/ty.rs +++ b/src/librustc_builtin_macros/deriving/generic/ty.rs @@ -216,7 +216,11 @@ fn mk_ty_param( } fn mk_generics(params: Vec, span: Span) -> Generics { - Generics { params, where_clause: ast::WhereClause { predicates: Vec::new(), span }, span } + Generics { + params, + where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span }, + span, + } } /// Lifetimes and bounds on type parameters diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs index 8e8f864728ce6..04b64d93c70dd 100644 --- a/src/librustc_parse/parser/generics.rs +++ b/src/librustc_parse/parser/generics.rs @@ -157,6 +157,7 @@ impl<'a> Parser<'a> { Ok(ast::Generics { params, where_clause: WhereClause { + has_where_token: false, predicates: Vec::new(), span: self.prev_token.span.shrink_to_hi(), }, @@ -170,12 +171,16 @@ impl<'a> Parser<'a> { /// where T : Trait + 'b, 'a : 'b /// ``` pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { - let mut where_clause = - WhereClause { predicates: Vec::new(), span: self.prev_token.span.shrink_to_hi() }; + let mut where_clause = WhereClause { + has_where_token: false, + predicates: Vec::new(), + span: self.prev_token.span.shrink_to_hi(), + }; if !self.eat_keyword(kw::Where) { return Ok(where_clause); } + where_clause.has_where_token = true; let lo = self.prev_token.span; // We are considering adding generics to the `where` keyword as an alternative higher-rank diff --git a/src/test/ui/proc-macro/empty-where-clause.rs b/src/test/ui/proc-macro/empty-where-clause.rs new file mode 100644 index 0000000000000..719555c092a78 --- /dev/null +++ b/src/test/ui/proc-macro/empty-where-clause.rs @@ -0,0 +1,18 @@ +// aux-build:test-macros.rs + +extern crate test_macros; +use test_macros::recollect_attr; + +#[recollect_attr] +struct FieldStruct where { + field: MissingType1 //~ ERROR cannot find +} + +#[recollect_attr] +struct TupleStruct(MissingType2) where; //~ ERROR cannot find + +enum MyEnum where { + Variant(MissingType3) //~ ERROR cannot find +} + +fn main() {} diff --git a/src/test/ui/proc-macro/empty-where-clause.stderr b/src/test/ui/proc-macro/empty-where-clause.stderr new file mode 100644 index 0000000000000..192a2b30f0dcd --- /dev/null +++ b/src/test/ui/proc-macro/empty-where-clause.stderr @@ -0,0 +1,21 @@ +error[E0412]: cannot find type `MissingType1` in this scope + --> $DIR/empty-where-clause.rs:8:12 + | +LL | field: MissingType1 + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `MissingType2` in this scope + --> $DIR/empty-where-clause.rs:12:20 + | +LL | struct TupleStruct(MissingType2) where; + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `MissingType3` in this scope + --> $DIR/empty-where-clause.rs:15:13 + | +LL | Variant(MissingType3) + | ^^^^^^^^^^^^ not found in this scope + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0412`.