From 7e70a63e615d399072c8b8c2054d8d61844240d6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 2 Jul 2017 01:37:47 +0200 Subject: [PATCH] Throw errors when doc comments are added where they're unused --- src/librustc/hir/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 41 ++++++++++++++++++++--- src/test/compile-fail/issue-34222.rs | 2 +- src/test/compile-fail/useless_comment.rs | 26 ++++++++++++++ src/test/compile-fail/useless_comment2.rs | 25 ++++++++++++++ src/test/compile-fail/useless_comment3.rs | 22 ++++++++++++ 6 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/useless_comment.rs create mode 100644 src/test/compile-fail/useless_comment2.rs create mode 100644 src/test/compile-fail/useless_comment3.rs diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fd79ec3b6b9..1b14caad3c8 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1679,7 +1679,7 @@ pub struct Item { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Item_ { - /// An`extern crate` item, with optional original crate name, + /// An `extern crate` item, with optional original crate name, /// /// e.g. `extern crate foo` or `extern crate foo_bar as foo` ItemExternCrate(Option), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index af9a198b983..047f4b979d9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2131,14 +2131,14 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P> { } else { Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) } - }, + } token::OpenDelim(token::Brace) => { return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); - }, - token::BinOp(token::Or) | token::OrOr => { + } + token::BinOp(token::Or) | token::OrOr => { let lo = self.span; return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs); - }, + } token::OpenDelim(token::Bracket) => { self.bump(); @@ -2387,7 +2387,6 @@ fn parse_or_use_outer_attributes(&mut self, pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode, outer_attrs: ThinVec) -> PResult<'a, P> { - self.expect(&token::OpenDelim(token::Brace))?; let mut attrs = outer_attrs; @@ -2421,6 +2420,12 @@ pub fn parse_dot_or_call_expr_with(&mut self, expr.map(|mut expr| { attrs.extend::>(expr.attrs.into()); expr.attrs = attrs; + if if let Some(ref doc) = expr.attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + true + } else { false } { + return expr; + } match expr.node { ExprKind::If(..) | ExprKind::IfLet(..) => { if !expr.attrs.is_empty() { @@ -3105,6 +3110,9 @@ pub fn parse_lambda_expr(&mut self, // `else` token already eaten pub fn parse_else_expr(&mut self) -> PResult<'a, P> { + if self.prev_token_kind == PrevTokenKind::DocComment { + return Err(self.span_fatal_err(self.span, Error::UselessDocComment)); + } if self.eat_keyword(keywords::If) { return self.parse_if_expr(ThinVec::new()); } else { @@ -3118,6 +3126,9 @@ pub fn parse_for_expr(&mut self, opt_ident: Option, span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { // Parse: `for in ` + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } let pat = self.parse_pat()?; self.expect_keyword(keywords::In)?; @@ -3133,6 +3144,9 @@ pub fn parse_for_expr(&mut self, opt_ident: Option, pub fn parse_while_expr(&mut self, opt_ident: Option, span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); } @@ -3161,6 +3175,9 @@ pub fn parse_while_let_expr(&mut self, opt_ident: Option, pub fn parse_loop_expr(&mut self, opt_ident: Option, span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let span = span_lo.to(body.span); @@ -3171,6 +3188,9 @@ pub fn parse_loop_expr(&mut self, opt_ident: Option, pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) @@ -3178,6 +3198,9 @@ pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec) // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } let match_span = self.prev_span; let lo = self.prev_span; let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, @@ -3215,6 +3238,9 @@ pub fn parse_arm(&mut self) -> PResult<'a, Arm> { maybe_whole!(self, NtArm, |x| x); let attrs = self.parse_outer_attributes()?; + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } let pats = self.parse_pats()?; let guard = if self.eat_keyword(keywords::If) { Some(self.parse_expr()?) @@ -3669,6 +3695,9 @@ fn parse_pat_ident(&mut self, /// Parse a local variable declaration fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { + if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) { + self.span_fatal_err(doc.span, Error::UselessDocComment).emit(); + } let lo = self.span; let pat = self.parse_pat()?; @@ -4158,6 +4187,8 @@ fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo3() -> i32 { + let mut x = 12; + /// z //~ ERROR E0585 + while x < 1 { + /// x //~ ERROR E0585 + //~^ ERROR attributes on non-item statements and expressions are experimental + x += 1; + } + /// d //~ ERROR E0585 + return x; +} + +fn main() { + /// e //~ ERROR E0585 + foo3(); +} diff --git a/src/test/compile-fail/useless_comment2.rs b/src/test/compile-fail/useless_comment2.rs new file mode 100644 index 00000000000..52ac7b6a769 --- /dev/null +++ b/src/test/compile-fail/useless_comment2.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { + /// a //~ ERROR E0585 + let x = 12; + + /// b //~ ERROR E0585 + match x { + /// c //~ ERROR E0585 + 1 => {}, + _ => {} + } +} + +fn main() { + foo(); +} \ No newline at end of file diff --git a/src/test/compile-fail/useless_comment3.rs b/src/test/compile-fail/useless_comment3.rs new file mode 100644 index 00000000000..c26031b5eb6 --- /dev/null +++ b/src/test/compile-fail/useless_comment3.rs @@ -0,0 +1,22 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { + let x = 13; + /// x //~ ERROR E0585 + if x == 12 { + /// y + println!("hello"); + } +} + +fn main() { + foo(); +}