Skip to content

Commit cee0508

Browse files
author
Ariel Ben-Yehuda
authored
Rollup merge of rust-lang#40815 - estebank:issue-40006, r=GuillaumeGomez
Identify missing item category in `impl`s ```rust struct S; impl S { pub hello_method(&self) { println!("Hello"); } } fn main() { S.hello_method(); } ``` ```rust error: missing `fn` for method declaration --> file.rs:3:4 | 3 | pub hello_method(&self) { | ^ missing `fn` ``` Fix rust-lang#40006. r? @pnkfelix CC @jonathandturner @GuillaumeGomez
2 parents a182027 + 8f31e19 commit cee0508

File tree

4 files changed

+95
-15
lines changed

4 files changed

+95
-15
lines changed

src/libsyntax/parse/parser.rs

+42-15
Original file line numberDiff line numberDiff line change
@@ -4657,25 +4657,30 @@ impl<'a> Parser<'a> {
46574657
})
46584658
}
46594659

4660-
fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
4661-
match *visa {
4662-
Visibility::Inherited => (),
4660+
fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) {
4661+
if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) {
4662+
err.emit();
4663+
}
4664+
}
4665+
4666+
fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> {
4667+
match *vis {
4668+
Visibility::Inherited => Ok(()),
46634669
_ => {
46644670
let is_macro_rules: bool = match self.token {
46654671
token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
46664672
_ => false,
46674673
};
46684674
if is_macro_rules {
4669-
self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
4670-
invocation with `pub`")
4671-
.help("did you mean #[macro_export]?")
4672-
.emit();
4675+
let mut err = self.diagnostic()
4676+
.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
4677+
err.help("did you mean #[macro_export]?");
4678+
Err(err)
46734679
} else {
4674-
self.diagnostic().struct_span_err(span, "can't qualify macro \
4675-
invocation with `pub`")
4676-
.help("try adjusting the macro to put `pub` \
4677-
inside the invocation")
4678-
.emit();
4680+
let mut err = self.diagnostic()
4681+
.struct_span_err(sp, "can't qualify macro invocation with `pub`");
4682+
err.help("try adjusting the macro to put `pub` inside the invocation");
4683+
Err(err)
46794684
}
46804685
}
46814686
}
@@ -4686,14 +4691,36 @@ impl<'a> Parser<'a> {
46864691
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
46874692
// code copied from parse_macro_use_or_failure... abstraction!
46884693
if self.token.is_path_start() {
4689-
// method macro.
4694+
// Method macro.
46904695

46914696
let prev_span = self.prev_span;
4692-
self.complain_if_pub_macro(&vis, prev_span);
4697+
// Before complaining about trying to set a macro as `pub`,
4698+
// check if `!` comes after the path.
4699+
let err = self.complain_if_pub_macro_diag(&vis, prev_span);
46934700

46944701
let lo = self.span;
46954702
let pth = self.parse_path(PathStyle::Mod)?;
4696-
self.expect(&token::Not)?;
4703+
let bang_err = self.expect(&token::Not);
4704+
if let Err(mut err) = err {
4705+
if let Err(mut bang_err) = bang_err {
4706+
// Given this code `pub path(`, it seems like this is not setting the
4707+
// visibility of a macro invocation, but rather a mistyped method declaration.
4708+
// Create a diagnostic pointing out that `fn` is missing.
4709+
//
4710+
// x | pub path(&self) {
4711+
// | ^ missing `fn` for method declaration
4712+
4713+
err.cancel();
4714+
bang_err.cancel();
4715+
// pub path(
4716+
// ^^ `sp` below will point to this
4717+
let sp = prev_span.between(self.prev_span);
4718+
err = self.diagnostic()
4719+
.struct_span_err(sp, "missing `fn` for method declaration");
4720+
err.span_label(sp, &"missing `fn`");
4721+
}
4722+
return Err(err);
4723+
}
46974724

46984725
// eat a matched-delimiter token tree:
46994726
let (delim, tts) = self.expect_delimited_token_tree()?;

src/libsyntax_pos/lib.rs

+24
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,30 @@ impl Span {
189189
Span { hi: end.hi, ..self }
190190
}
191191
}
192+
193+
pub fn between(self, end: Span) -> Span {
194+
Span {
195+
lo: self.hi,
196+
hi: end.lo,
197+
ctxt: if end.ctxt == SyntaxContext::empty() {
198+
end.ctxt
199+
} else {
200+
self.ctxt
201+
}
202+
}
203+
}
204+
205+
pub fn until(self, end: Span) -> Span {
206+
Span {
207+
lo: self.lo,
208+
hi: end.lo,
209+
ctxt: if end.ctxt == SyntaxContext::empty() {
210+
end.ctxt
211+
} else {
212+
self.ctxt
213+
}
214+
}
215+
}
192216
}
193217

194218
#[derive(Clone, Debug)]
+21
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: missing `fn` for method declaration
2+
--> $DIR/issue-40006.rs:14:8
3+
|
4+
14 | pub hello_method(&self) {
5+
| ^ missing `fn`
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)