Skip to content

Commit 8674efd

Browse files
committed
parser: move restrictions re. self to ast_validation.
1 parent cdd41ea commit 8674efd

File tree

9 files changed

+426
-56
lines changed

9 files changed

+426
-56
lines changed

src/librustc_ast_passes/ast_validation.rs

+36-8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ use syntax::print::pprust;
2323
use syntax::visit::{self, Visitor};
2424
use syntax::walk_list;
2525

26+
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
27+
enum SelfSemantic {
28+
Yes,
29+
No,
30+
}
31+
2632
/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
2733
#[derive(Clone, Copy)]
2834
enum BoundContext {
@@ -302,7 +308,13 @@ impl<'a> AstValidator<'a> {
302308
}
303309
}
304310

305-
fn check_fn_decl(&self, fn_decl: &FnDecl) {
311+
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
312+
self.check_decl_cvaradic_pos(fn_decl);
313+
self.check_decl_attrs(fn_decl);
314+
self.check_decl_self_param(fn_decl, self_semantic);
315+
}
316+
317+
fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
306318
match &*fn_decl.inputs {
307319
[Param { ty, span, .. }] => {
308320
if let TyKind::CVarArgs = ty.kind {
@@ -324,7 +336,9 @@ impl<'a> AstValidator<'a> {
324336
}
325337
_ => {}
326338
}
339+
}
327340

341+
fn check_decl_attrs(&self, fn_decl: &FnDecl) {
328342
fn_decl
329343
.inputs
330344
.iter()
@@ -352,6 +366,21 @@ impl<'a> AstValidator<'a> {
352366
});
353367
}
354368

369+
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
370+
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
371+
if param.is_self() {
372+
self.err_handler()
373+
.struct_span_err(
374+
param.span,
375+
"`self` parameter only allowed in associated `fn`s",
376+
)
377+
.span_label(param.span, "not semantically valid as function parameter")
378+
.note("associated `fn`s are those in `impl` or `trait` definitions")
379+
.emit();
380+
}
381+
}
382+
}
383+
355384
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
356385
if let Defaultness::Default = defaultness {
357386
self.err_handler()
@@ -504,7 +533,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
504533
fn visit_expr(&mut self, expr: &'a Expr) {
505534
match &expr.kind {
506535
ExprKind::Closure(_, _, _, fn_decl, _, _) => {
507-
self.check_fn_decl(fn_decl);
536+
self.check_fn_decl(fn_decl, SelfSemantic::No);
508537
}
509538
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
510539
struct_span_err!(
@@ -524,7 +553,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
524553
fn visit_ty(&mut self, ty: &'a Ty) {
525554
match ty.kind {
526555
TyKind::BareFn(ref bfty) => {
527-
self.check_fn_decl(&bfty.decl);
556+
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
528557
Self::check_decl_no_pat(&bfty.decl, |span, _| {
529558
struct_span_err!(
530559
self.session,
@@ -685,7 +714,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
685714
}
686715
ItemKind::Fn(ref sig, ref generics, _) => {
687716
self.visit_fn_header(&sig.header);
688-
self.check_fn_decl(&sig.decl);
717+
self.check_fn_decl(&sig.decl, SelfSemantic::No);
689718
// We currently do not permit const generics in `const fn`, as
690719
// this is tantamount to allowing compile-time dependent typing.
691720
if sig.header.constness.node == Constness::Const {
@@ -793,7 +822,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
793822
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
794823
match fi.kind {
795824
ForeignItemKind::Fn(ref decl, _) => {
796-
self.check_fn_decl(decl);
825+
self.check_fn_decl(decl, SelfSemantic::No);
797826
Self::check_decl_no_pat(decl, |span, _| {
798827
struct_span_err!(
799828
self.session,
@@ -987,9 +1016,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9871016
AssocItemKind::Const(_, body) => {
9881017
self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
9891018
}
990-
AssocItemKind::Fn(sig, body) => {
1019+
AssocItemKind::Fn(_, body) => {
9911020
self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
992-
self.check_fn_decl(&sig.decl);
9931021
}
9941022
AssocItemKind::TyAlias(bounds, body) => {
9951023
self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
@@ -1005,7 +1033,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10051033
self.check_defaultness(ti.span, ti.defaultness);
10061034

10071035
if let AssocItemKind::Fn(sig, block) = &ti.kind {
1008-
self.check_fn_decl(&sig.decl);
10091036
self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
10101037
self.check_trait_fn_not_const(sig.header.constness);
10111038
if block.is_none() {
@@ -1035,6 +1062,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10351062

10361063
fn visit_assoc_item(&mut self, item: &'a AssocItem) {
10371064
if let AssocItemKind::Fn(sig, _) = &item.kind {
1065+
self.check_fn_decl(&sig.decl, SelfSemantic::Yes);
10381066
self.check_c_varadic_type(&sig.decl);
10391067
}
10401068
visit::walk_assoc_item(self, item);

src/librustc_parse/parser/diagnostics.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,8 @@ impl<'a> Parser<'a> {
13361336
err: &mut DiagnosticBuilder<'_>,
13371337
pat: P<ast::Pat>,
13381338
require_name: bool,
1339-
is_self_allowed: bool,
1340-
is_trait_item: bool,
1339+
is_self_semantic: bool,
1340+
in_assoc_item: bool,
13411341
) -> Option<Ident> {
13421342
// If we find a pattern followed by an identifier, it could be an (incorrect)
13431343
// C-style parameter declaration.
@@ -1357,13 +1357,13 @@ impl<'a> Parser<'a> {
13571357
return Some(ident);
13581358
} else if let PatKind::Ident(_, ident, _) = pat.kind {
13591359
if require_name
1360-
&& (is_trait_item
1360+
&& (in_assoc_item
13611361
|| self.token == token::Comma
13621362
|| self.token == token::Lt
13631363
|| self.token == token::CloseDelim(token::Paren))
13641364
{
13651365
// `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}`
1366-
if is_self_allowed {
1366+
if is_self_semantic {
13671367
err.span_suggestion(
13681368
pat.span,
13691369
"if this is a `self` type, give it a parameter name",
@@ -1423,12 +1423,12 @@ impl<'a> Parser<'a> {
14231423
pub(super) fn recover_bad_self_param(
14241424
&mut self,
14251425
mut param: ast::Param,
1426-
is_trait_item: bool,
1426+
in_assoc_item: bool,
14271427
) -> PResult<'a, ast::Param> {
14281428
let sp = param.pat.span;
14291429
param.ty.kind = TyKind::Err;
14301430
let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function");
1431-
if is_trait_item {
1431+
if in_assoc_item {
14321432
err.span_label(sp, "must be the first associated function parameter");
14331433
} else {
14341434
err.span_label(sp, "not valid as function parameter");

src/librustc_parse/parser/item.rs

+26-34
Original file line numberDiff line numberDiff line change
@@ -1715,8 +1715,9 @@ impl<'a> Parser<'a> {
17151715

17161716
/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
17171717
pub(super) struct ParamCfg {
1718-
/// Is `self` is allowed as the first parameter?
1719-
pub is_self_allowed: bool,
1718+
/// Is `self` is *semantically* allowed as the first parameter?
1719+
/// This is only used for diagnostics.
1720+
pub in_assoc_item: bool,
17201721
/// `is_name_required` decides if, per-parameter,
17211722
/// the parameter must have a pattern or just a type.
17221723
pub is_name_required: fn(&token::Token) -> bool,
@@ -1732,8 +1733,8 @@ impl<'a> Parser<'a> {
17321733
attrs: Vec<Attribute>,
17331734
header: FnHeader,
17341735
) -> PResult<'a, Option<P<Item>>> {
1735-
let (ident, decl, generics) =
1736-
self.parse_fn_sig(ParamCfg { is_self_allowed: false, is_name_required: |_| true })?;
1736+
let cfg = ParamCfg { in_assoc_item: false, is_name_required: |_| true };
1737+
let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
17371738
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
17381739
let kind = ItemKind::Fn(FnSig { decl, header }, generics, body);
17391740
self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
@@ -1747,20 +1748,13 @@ impl<'a> Parser<'a> {
17471748
attrs: Vec<Attribute>,
17481749
extern_sp: Span,
17491750
) -> PResult<'a, P<ForeignItem>> {
1751+
let cfg = ParamCfg { in_assoc_item: false, is_name_required: |_| true };
17501752
self.expect_keyword(kw::Fn)?;
1751-
let (ident, decl, generics) =
1752-
self.parse_fn_sig(ParamCfg { is_self_allowed: false, is_name_required: |_| true })?;
1753+
let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
17531754
let span = lo.to(self.token.span);
17541755
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
1755-
Ok(P(ast::ForeignItem {
1756-
ident,
1757-
attrs,
1758-
kind: ForeignItemKind::Fn(decl, generics),
1759-
id: DUMMY_NODE_ID,
1760-
span,
1761-
vis,
1762-
tokens: None,
1763-
}))
1756+
let kind = ForeignItemKind::Fn(decl, generics);
1757+
Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None }))
17641758
}
17651759

17661760
fn parse_assoc_fn(
@@ -1769,9 +1763,9 @@ impl<'a> Parser<'a> {
17691763
attrs: &mut Vec<Attribute>,
17701764
is_name_required: fn(&token::Token) -> bool,
17711765
) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
1766+
let cfg = ParamCfg { in_assoc_item: true, is_name_required };
17721767
let header = self.parse_fn_front_matter()?;
1773-
let (ident, decl, generics) =
1774-
self.parse_fn_sig(ParamCfg { is_self_allowed: true, is_name_required })?;
1768+
let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
17751769
let sig = FnSig { header, decl };
17761770
let body = self.parse_assoc_fn_body(at_end, attrs)?;
17771771
Ok((ident, AssocItemKind::Fn(sig, body), generics))
@@ -1847,7 +1841,7 @@ impl<'a> Parser<'a> {
18471841
}
18481842

18491843
/// Parse the "signature", including the identifier, parameters, and generics of a function.
1850-
fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
1844+
fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
18511845
let ident = self.parse_ident()?;
18521846
let mut generics = self.parse_generics()?;
18531847
let decl = self.parse_fn_decl(cfg, true)?;
@@ -1858,7 +1852,7 @@ impl<'a> Parser<'a> {
18581852
/// Parses the parameter list and result type of a function declaration.
18591853
pub(super) fn parse_fn_decl(
18601854
&mut self,
1861-
cfg: ParamCfg,
1855+
cfg: &ParamCfg,
18621856
ret_allow_plus: bool,
18631857
) -> PResult<'a, P<FnDecl>> {
18641858
Ok(P(FnDecl {
@@ -1868,11 +1862,11 @@ impl<'a> Parser<'a> {
18681862
}
18691863

18701864
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
1871-
fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
1872-
let is_trait_item = cfg.is_self_allowed;
1873-
// Parse the arguments, starting out with `self` being possibly allowed...
1865+
fn parse_fn_params(&mut self, cfg: &ParamCfg) -> PResult<'a, Vec<Param>> {
1866+
let mut first_param = true;
1867+
// Parse the arguments, starting out with `self` being allowed...
18741868
let (mut params, _) = self.parse_paren_comma_seq(|p| {
1875-
let param = p.parse_param_general(&cfg, is_trait_item).or_else(|mut e| {
1869+
let param = p.parse_param_general(&cfg, first_param).or_else(|mut e| {
18761870
e.emit();
18771871
let lo = p.prev_span;
18781872
// Skip every token until next possible arg or end.
@@ -1881,28 +1875,28 @@ impl<'a> Parser<'a> {
18811875
Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_span))))
18821876
});
18831877
// ...now that we've parsed the first argument, `self` is no longer allowed.
1884-
cfg.is_self_allowed = false;
1878+
first_param = false;
18851879
param
18861880
})?;
18871881
// Replace duplicated recovered params with `_` pattern to avoid unnecessary errors.
18881882
self.deduplicate_recovered_params_names(&mut params);
18891883
Ok(params)
18901884
}
18911885

1892-
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
1893-
/// error.
1894-
/// This version of parse param doesn't necessarily require identifier names.
1895-
fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
1886+
/// Parses a single function parameter.
1887+
///
1888+
/// - `self` is syntactically allowed when `first_param` holds.
1889+
fn parse_param_general(&mut self, cfg: &ParamCfg, first_param: bool) -> PResult<'a, Param> {
18961890
let lo = self.token.span;
18971891
let attrs = self.parse_outer_attributes()?;
18981892

18991893
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
19001894
if let Some(mut param) = self.parse_self_param()? {
19011895
param.attrs = attrs.into();
1902-
return if cfg.is_self_allowed {
1896+
return if first_param {
19031897
Ok(param)
19041898
} else {
1905-
self.recover_bad_self_param(param, is_trait_item)
1899+
self.recover_bad_self_param(param, cfg.in_assoc_item)
19061900
};
19071901
}
19081902

@@ -1919,8 +1913,8 @@ impl<'a> Parser<'a> {
19191913
&mut err,
19201914
pat,
19211915
is_name_required,
1922-
cfg.is_self_allowed,
1923-
is_trait_item,
1916+
first_param && cfg.in_assoc_item,
1917+
cfg.in_assoc_item,
19241918
) {
19251919
err.emit();
19261920
Ok(dummy_arg(ident))
@@ -1975,8 +1969,6 @@ impl<'a> Parser<'a> {
19751969
}
19761970

19771971
/// Returns the parsed optional self parameter and whether a self shortcut was used.
1978-
///
1979-
/// See `parse_self_param_with_attrs` to collect attributes.
19801972
fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
19811973
// Extract an identifier *after* having confirmed that the token is one.
19821974
let expect_self_ident = |this: &mut Self| {

src/librustc_parse/parser/ty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ impl<'a> Parser<'a> {
288288
let unsafety = self.parse_unsafety();
289289
let ext = self.parse_extern()?;
290290
self.expect_keyword(kw::Fn)?;
291-
let cfg = ParamCfg { is_self_allowed: false, is_name_required: |_| false };
292-
let decl = self.parse_fn_decl(cfg, false)?;
291+
let cfg = ParamCfg { in_assoc_item: false, is_name_required: |_| false };
292+
let decl = self.parse_fn_decl(&cfg, false)?;
293293
Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
294294
}
295295

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn a(&self) { }
2-
//~^ ERROR unexpected `self` parameter in function
3-
//~| NOTE not valid as function parameter
4-
//~| NOTE `self` is only valid as the first parameter of an associated function
2+
//~^ ERROR `self` parameter only allowed in associated `fn`s
3+
//~| NOTE not semantically valid as function parameter
4+
//~| NOTE associated `fn`s are those in `impl` or `trait` definitions
55

66
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: unexpected `self` parameter in function
1+
error: `self` parameter only allowed in associated `fn`s
22
--> $DIR/bare-fn-start.rs:1:6
33
|
44
LL | fn a(&self) { }
5-
| ^^^^^ not valid as function parameter
5+
| ^^^^^ not semantically valid as function parameter
66
|
7-
= note: `self` is only valid as the first parameter of an associated function
7+
= note: associated `fn`s are those in `impl` or `trait` definitions
88

99
error: aborting due to previous error
1010

0 commit comments

Comments
 (0)