Skip to content

Commit 57009ca

Browse files
committed
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 ```
1 parent c62e532 commit 57009ca

File tree

3 files changed

+80
-15
lines changed

3 files changed

+80
-15
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> {
46604660
})
46614661
}
46624662

4663-
fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
4664-
match *visa {
4665-
Visibility::Inherited => (),
4663+
fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) {
4664+
if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) {
4665+
err.emit();
4666+
}
4667+
}
4668+
4669+
fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> {
4670+
match *vis {
4671+
Visibility::Inherited => Ok(()),
46664672
_ => {
46674673
let is_macro_rules: bool = match self.token {
46684674
token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
46694675
_ => false,
46704676
};
46714677
if is_macro_rules {
4672-
self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
4673-
invocation with `pub`")
4674-
.help("did you mean #[macro_export]?")
4675-
.emit();
4678+
let mut err = self.diagnostic()
4679+
.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
4680+
err.help("did you mean #[macro_export]?");
4681+
Err(err)
46764682
} else {
4677-
self.diagnostic().struct_span_err(span, "can't qualify macro \
4678-
invocation with `pub`")
4679-
.help("try adjusting the macro to put `pub` \
4680-
inside the invocation")
4681-
.emit();
4683+
let mut err = self.diagnostic()
4684+
.struct_span_err(sp, "can't qualify macro invocation with `pub`");
4685+
err.help("try adjusting the macro to put `pub` inside the invocation");
4686+
Err(err)
46824687
}
46834688
}
46844689
}
@@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> {
46894694
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
46904695
// code copied from parse_macro_use_or_failure... abstraction!
46914696
if self.token.is_path_start() {
4692-
// method macro.
4697+
// Method macro.
46934698

46944699
let prev_span = self.prev_span;
4695-
self.complain_if_pub_macro(&vis, prev_span);
4700+
// Before complaining about trying to set a macro as `pub`,
4701+
// check if `!` comes after the path.
4702+
let err = self.complain_if_pub_macro_diag(&vis, prev_span);
46964703

46974704
let lo = self.span.lo;
46984705
let pth = self.parse_path(PathStyle::Mod)?;
4699-
self.expect(&token::Not)?;
4706+
let bang_err = self.expect(&token::Not);
4707+
if let Err(mut err) = err {
4708+
if let Err(mut bang_err) = bang_err {
4709+
// Given this code `pub path(`, it seems like this is not setting the
4710+
// visibility of a macro invocation, but rather a mistyped method declaration.
4711+
// Keep the macro diagnostic, but also provide a hint that `fn` might be
4712+
// missing. Don't complain about the missing `!` as a separate diagnostic, add
4713+
// label in the appropriate place as part of one unified diagnostic.
4714+
//
4715+
// x | pub path(&self) {
4716+
// | ^^^- - expected `!` here for a macro invocation
4717+
// | |
4718+
// | did you mean to write `fn` here for a method declaration?
4719+
4720+
bang_err.cancel();
4721+
err.span_label(self.span, &"expected `!` here for a macro invocation");
4722+
// pub path(
4723+
// ^^ `sp` below will point to this
4724+
let sp = mk_sp(prev_span.hi, self.prev_span.lo);
4725+
err.span_label(sp,
4726+
&"did you mean to write `fn` here for a method declaration?");
4727+
}
4728+
return Err(err);
4729+
} else if let Err(bang_err) = bang_err {
4730+
return Err(bang_err);
4731+
}
47004732

47014733
// eat a matched-delimiter token tree:
47024734
let (delim, tts) = self.expect_delimited_token_tree()?;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 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.
4+
//
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.
10+
11+
struct S;
12+
13+
impl S {
14+
pub hello_method(&self) {
15+
println!("Hello");
16+
}
17+
}
18+
19+
fn main() {
20+
S.hello_method();
21+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: can't qualify macro invocation with `pub`
2+
--> $DIR/issue-40006.rs:14:5
3+
|
4+
14 | pub hello_method(&self) {
5+
| ^^^- - expected `!` here for a macro invocation
6+
| |
7+
| did you mean to write `fn` here for a method declaration?
8+
|
9+
= help: try adjusting the macro to put `pub` inside the invocation
10+
11+
error: aborting due to previous error
12+

0 commit comments

Comments
 (0)