1
Fork 0

Identify missing item category in impls

```rust
struct S;
impl S {
    pub hello_method(&self) {
        println!("Hello");
    }
}
fn main() { S.hello_method(); }
```

```rust
error: can't qualify macro invocation with `pub`
 --> file.rs:3:4
  |
3 |     pub hello_method(&self) {
  |     ^^^-            - expected `!` here for a macro invocation
  |        |
  |        did you mean to write `fn` here for a method declaration?
  |
  = help: try adjusting the macro to put `pub` inside the invocation
```
This commit is contained in:
Esteban Küber 2017-03-24 23:00:21 -07:00
parent c62e532f3d
commit 57009caabd
3 changed files with 80 additions and 15 deletions

View file

@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> {
})
}
fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
match *visa {
Visibility::Inherited => (),
fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) {
if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) {
err.emit();
}
}
fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> {
match *vis {
Visibility::Inherited => Ok(()),
_ => {
let is_macro_rules: bool = match self.token {
token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
_ => false,
};
if is_macro_rules {
self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
invocation with `pub`")
.help("did you mean #[macro_export]?")
.emit();
let mut err = self.diagnostic()
.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
err.help("did you mean #[macro_export]?");
Err(err)
} else {
self.diagnostic().struct_span_err(span, "can't qualify macro \
invocation with `pub`")
.help("try adjusting the macro to put `pub` \
inside the invocation")
.emit();
let mut err = self.diagnostic()
.struct_span_err(sp, "can't qualify macro invocation with `pub`");
err.help("try adjusting the macro to put `pub` inside the invocation");
Err(err)
}
}
}
@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> {
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
// code copied from parse_macro_use_or_failure... abstraction!
if self.token.is_path_start() {
// method macro.
// Method macro.
let prev_span = self.prev_span;
self.complain_if_pub_macro(&vis, prev_span);
// Before complaining about trying to set a macro as `pub`,
// check if `!` comes after the path.
let err = self.complain_if_pub_macro_diag(&vis, prev_span);
let lo = self.span.lo;
let pth = self.parse_path(PathStyle::Mod)?;
self.expect(&token::Not)?;
let bang_err = self.expect(&token::Not);
if let Err(mut err) = err {
if let Err(mut bang_err) = bang_err {
// Given this code `pub path(`, it seems like this is not setting the
// visibility of a macro invocation, but rather a mistyped method declaration.
// Keep the macro diagnostic, but also provide a hint that `fn` might be
// missing. Don't complain about the missing `!` as a separate diagnostic, add
// label in the appropriate place as part of one unified diagnostic.
//
// x | pub path(&self) {
// | ^^^- - expected `!` here for a macro invocation
// | |
// | did you mean to write `fn` here for a method declaration?
bang_err.cancel();
err.span_label(self.span, &"expected `!` here for a macro invocation");
// pub path(
// ^^ `sp` below will point to this
let sp = mk_sp(prev_span.hi, self.prev_span.lo);
err.span_label(sp,
&"did you mean to write `fn` here for a method declaration?");
}
return Err(err);
} else if let Err(bang_err) = bang_err {
return Err(bang_err);
}
// eat a matched-delimiter token tree:
let (delim, tts) = self.expect_delimited_token_tree()?;