Skip to content

Commit d745687

Browse files
authored
Merge pull request #1872 from dtolnay/attrrange
Disallow attributes on range expression
2 parents 7a79818 + 350a4ab commit d745687

File tree

3 files changed

+92
-14
lines changed

3 files changed

+92
-14
lines changed

src/expr.rs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ pub(crate) mod parsing {
12131213
use crate::ty::{ReturnType, Type};
12141214
use crate::verbatim;
12151215
#[cfg(feature = "full")]
1216-
use proc_macro2::TokenStream;
1216+
use proc_macro2::{Span, TokenStream};
12171217
use std::mem;
12181218

12191219
// When we're parsing expressions which occur before blocks, like in an if
@@ -1599,7 +1599,18 @@ pub(crate) mod parsing {
15991599

16001600
if let Expr::Verbatim(tokens) = &mut e {
16011601
*tokens = verbatim::between(&begin, input);
1602-
} else {
1602+
} else if !attrs.is_empty() {
1603+
if let Expr::Range(range) = e {
1604+
let spans: &[Span] = match &range.limits {
1605+
RangeLimits::HalfOpen(limits) => &limits.spans,
1606+
RangeLimits::Closed(limits) => &limits.spans,
1607+
};
1608+
return Err(crate::error::new2(
1609+
spans[0],
1610+
*spans.last().unwrap(),
1611+
"attributes are not allowed on range expressions starting with `..`",
1612+
));
1613+
}
16031614
let inner_attrs = e.replace_attrs(Vec::new());
16041615
attrs.extend(inner_attrs);
16051616
e.replace_attrs(attrs);
@@ -3833,18 +3844,37 @@ pub(crate) mod printing {
38333844
}
38343845

38353846
#[cfg(feature = "full")]
3836-
fn print_expr_range(e: &ExprRange, tokens: &mut TokenStream, fixup: FixupContext) {
3847+
fn print_expr_range(e: &ExprRange, tokens: &mut TokenStream, mut fixup: FixupContext) {
38373848
outer_attrs_to_tokens(&e.attrs, tokens);
3838-
if let Some(start) = &e.start {
3839-
let (left_prec, left_fixup) =
3840-
fixup.leftmost_subexpression_with_operator(start, true, false, Precedence::Range);
3841-
print_subexpression(start, left_prec <= Precedence::Range, tokens, left_fixup);
3842-
}
3843-
e.limits.to_tokens(tokens);
3844-
if let Some(end) = &e.end {
3845-
let right_fixup = fixup.rightmost_subexpression_fixup(false, true, Precedence::Range);
3846-
let right_prec = right_fixup.rightmost_subexpression_precedence(end);
3847-
print_subexpression(end, right_prec <= Precedence::Range, tokens, right_fixup);
3849+
3850+
let needs_group = !e.attrs.is_empty();
3851+
if needs_group {
3852+
fixup = FixupContext::NONE;
3853+
}
3854+
3855+
let do_print_expr = |tokens: &mut TokenStream| {
3856+
if let Some(start) = &e.start {
3857+
let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator(
3858+
start,
3859+
true,
3860+
false,
3861+
Precedence::Range,
3862+
);
3863+
print_subexpression(start, left_prec <= Precedence::Range, tokens, left_fixup);
3864+
}
3865+
e.limits.to_tokens(tokens);
3866+
if let Some(end) = &e.end {
3867+
let right_fixup =
3868+
fixup.rightmost_subexpression_fixup(false, true, Precedence::Range);
3869+
let right_prec = right_fixup.rightmost_subexpression_precedence(end);
3870+
print_subexpression(end, right_prec <= Precedence::Range, tokens, right_fixup);
3871+
}
3872+
};
3873+
3874+
if needs_group {
3875+
token::Paren::default().surround(tokens, do_print_expr);
3876+
} else {
3877+
do_print_expr(tokens);
38483878
}
38493879
}
38503880

src/fixup.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ fn scan_right(
612612
Scan::Bailout
613613
}
614614
}
615-
Expr::Range(e) => match &e.end {
615+
Expr::Range(e) if e.attrs.is_empty() => match &e.end {
616616
Some(end) => {
617617
if fail_offset >= 2 {
618618
return Scan::Consume;
@@ -754,6 +754,7 @@ fn scan_right(
754754
| Expr::MethodCall(_)
755755
| Expr::Paren(_)
756756
| Expr::Path(_)
757+
| Expr::Range(_)
757758
| Expr::Repeat(_)
758759
| Expr::Struct(_)
759760
| Expr::Try(_)

tests/test_expr.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,53 @@ fn test_range_precedence() {
424424
syn::parse_str::<Expr>("x .. x ..").unwrap_err();
425425
}
426426

427+
#[test]
428+
fn test_range_attrs() {
429+
// Attributes are not allowed on range expressions starting with `..`
430+
syn::parse_str::<Expr>("#[allow()] ..").unwrap_err();
431+
syn::parse_str::<Expr>("#[allow()] .. hi").unwrap_err();
432+
433+
snapshot!("#[allow()] lo .. hi" as Expr, @r#"
434+
Expr::Range {
435+
start: Some(Expr::Path {
436+
attrs: [
437+
Attribute {
438+
style: AttrStyle::Outer,
439+
meta: Meta::List {
440+
path: Path {
441+
segments: [
442+
PathSegment {
443+
ident: "allow",
444+
},
445+
],
446+
},
447+
delimiter: MacroDelimiter::Paren,
448+
tokens: TokenStream(``),
449+
},
450+
},
451+
],
452+
path: Path {
453+
segments: [
454+
PathSegment {
455+
ident: "lo",
456+
},
457+
],
458+
},
459+
}),
460+
limits: RangeLimits::HalfOpen,
461+
end: Some(Expr::Path {
462+
path: Path {
463+
segments: [
464+
PathSegment {
465+
ident: "hi",
466+
},
467+
],
468+
},
469+
}),
470+
}
471+
"#);
472+
}
473+
427474
#[test]
428475
fn test_ranges_bailout() {
429476
syn::parse_str::<Expr>(".. ?").unwrap_err();

0 commit comments

Comments
 (0)