Skip to content

Commit af5ef92

Browse files
authored
Rollup merge of rust-lang#103430 - cjgillot:receiver-attrs, r=petrochenkov
Workaround unstable stmt_expr_attributes for method receiver expressions Fixes rust-lang#103244 cc `@Mark-Simulacrum` `@ehuss`
2 parents ccd39fd + 74d4eef commit af5ef92

File tree

9 files changed

+121
-19
lines changed

9 files changed

+121
-19
lines changed

compiler/rustc_ast/src/mut_visit.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ pub trait MutVisitor: Sized {
152152
noop_visit_expr(e, self);
153153
}
154154

155+
/// This method is a hack to workaround unstable of `stmt_expr_attributes`.
156+
/// It can be removed once that feature is stabilized.
157+
fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) {
158+
self.visit_expr(ex)
159+
}
160+
155161
fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
156162
noop_filter_map_expr(e, self)
157163
}
@@ -1301,7 +1307,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
13011307
vis.visit_ident(ident);
13021308
vis.visit_id(id);
13031309
visit_opt(args, |args| vis.visit_generic_args(args));
1304-
vis.visit_expr(receiver);
1310+
vis.visit_method_receiver_expr(receiver);
13051311
visit_exprs(exprs, vis);
13061312
vis.visit_span(span);
13071313
}
@@ -1589,3 +1595,9 @@ impl DummyAstNode for Crate {
15891595
}
15901596
}
15911597
}
1598+
1599+
impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNodeWrapper<N, T> {
1600+
fn dummy() -> Self {
1601+
crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy())
1602+
}
1603+
}

compiler/rustc_ast/src/visit.rs

+5
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized {
140140
fn visit_expr(&mut self, ex: &'ast Expr) {
141141
walk_expr(self, ex)
142142
}
143+
/// This method is a hack to workaround unstable of `stmt_expr_attributes`.
144+
/// It can be removed once that feature is stabilized.
145+
fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) {
146+
self.visit_expr(ex)
147+
}
143148
fn visit_expr_post(&mut self, _ex: &'ast Expr) {}
144149
fn visit_ty(&mut self, t: &'ast Ty) {
145150
walk_ty(self, t)

compiler/rustc_builtin_macros/src/cfg_eval.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,15 @@ impl CfgEval<'_, '_> {
210210
}
211211

212212
impl MutVisitor for CfgEval<'_, '_> {
213+
#[instrument(level = "trace", skip(self))]
213214
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
214-
self.cfg.configure_expr(expr);
215+
self.cfg.configure_expr(expr, false);
216+
mut_visit::noop_visit_expr(expr, self);
217+
}
218+
219+
#[instrument(level = "trace", skip(self))]
220+
fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
221+
self.cfg.configure_expr(expr, true);
215222
mut_visit::noop_visit_expr(expr, self);
216223
}
217224

compiler/rustc_expand/src/config.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ impl<'a> StripUnconfigured<'a> {
469469
}
470470

471471
/// If attributes are not allowed on expressions, emit an error for `attr`
472+
#[instrument(level = "trace", skip(self))]
472473
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
473474
if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
474475
let mut err = feature_err(
@@ -486,9 +487,12 @@ impl<'a> StripUnconfigured<'a> {
486487
}
487488
}
488489

489-
pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
490-
for attr in expr.attrs.iter() {
491-
self.maybe_emit_expr_attr_err(attr);
490+
#[instrument(level = "trace", skip(self))]
491+
pub fn configure_expr(&self, expr: &mut P<ast::Expr>, method_receiver: bool) {
492+
if !method_receiver {
493+
for attr in expr.attrs.iter() {
494+
self.maybe_emit_expr_attr_err(attr);
495+
}
492496
}
493497

494498
// If an expr is valid to cfg away it will have been removed by the

compiler/rustc_expand/src/expand.rs

+63
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,23 @@ macro_rules! ast_fragments {
5050
/// Can also serve as an input and intermediate result for macro expansion operations.
5151
pub enum AstFragment {
5252
OptExpr(Option<P<ast::Expr>>),
53+
MethodReceiverExpr(P<ast::Expr>),
5354
$($Kind($AstTy),)*
5455
}
5556

5657
/// "Discriminant" of an AST fragment.
5758
#[derive(Copy, Clone, PartialEq, Eq)]
5859
pub enum AstFragmentKind {
5960
OptExpr,
61+
MethodReceiverExpr,
6062
$($Kind,)*
6163
}
6264

6365
impl AstFragmentKind {
6466
pub fn name(self) -> &'static str {
6567
match self {
6668
AstFragmentKind::OptExpr => "expression",
69+
AstFragmentKind::MethodReceiverExpr => "expression",
6770
$(AstFragmentKind::$Kind => $kind_name,)*
6871
}
6972
}
@@ -72,6 +75,8 @@ macro_rules! ast_fragments {
7275
match self {
7376
AstFragmentKind::OptExpr =>
7477
result.make_expr().map(Some).map(AstFragment::OptExpr),
78+
AstFragmentKind::MethodReceiverExpr =>
79+
result.make_expr().map(AstFragment::MethodReceiverExpr),
7580
$(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
7681
}
7782
}
@@ -98,6 +103,13 @@ macro_rules! ast_fragments {
98103
}
99104
}
100105

106+
pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
107+
match self {
108+
AstFragment::MethodReceiverExpr(expr) => expr,
109+
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
110+
}
111+
}
112+
101113
$(pub fn $make_ast(self) -> $AstTy {
102114
match self {
103115
AstFragment::$Kind(ast) => ast,
@@ -120,6 +132,7 @@ macro_rules! ast_fragments {
120132
}
121133
});
122134
}
135+
AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
123136
$($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
124137
$($(AstFragment::$Kind(ast) =>
125138
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
@@ -130,6 +143,7 @@ macro_rules! ast_fragments {
130143
match *self {
131144
AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
132145
AstFragment::OptExpr(None) => {}
146+
AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr),
133147
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
134148
$($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
135149
visitor.$visit_ast_elt(ast_elt, $($args)*);
@@ -222,6 +236,7 @@ impl AstFragmentKind {
222236
match self {
223237
AstFragmentKind::OptExpr
224238
| AstFragmentKind::Expr
239+
| AstFragmentKind::MethodReceiverExpr
225240
| AstFragmentKind::Stmts
226241
| AstFragmentKind::Ty
227242
| AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },
@@ -285,6 +300,9 @@ impl AstFragmentKind {
285300
AstFragmentKind::Expr => AstFragment::Expr(
286301
items.next().expect("expected exactly one expression").expect_expr(),
287302
),
303+
AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(
304+
items.next().expect("expected exactly one expression").expect_expr(),
305+
),
288306
AstFragmentKind::OptExpr => {
289307
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
290308
}
@@ -893,6 +911,7 @@ pub fn parse_ast_fragment<'a>(
893911
AstFragment::Stmts(stmts)
894912
}
895913
AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?),
914+
AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?),
896915
AstFragmentKind::OptExpr => {
897916
if this.token != token::Eof {
898917
AstFragment::OptExpr(Some(this.parse_expr()?))
@@ -1477,6 +1496,42 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
14771496
}
14781497
}
14791498

1499+
/// This struct is a hack to workaround unstable of `stmt_expr_attributes`.
1500+
/// It can be removed once that feature is stabilized.
1501+
struct MethodReceiverTag;
1502+
impl DummyAstNode for MethodReceiverTag {
1503+
fn dummy() -> MethodReceiverTag {
1504+
MethodReceiverTag
1505+
}
1506+
}
1507+
impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
1508+
type OutputTy = Self;
1509+
type AttrsTy = ast::AttrVec;
1510+
const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr;
1511+
fn descr() -> &'static str {
1512+
"an expression"
1513+
}
1514+
fn to_annotatable(self) -> Annotatable {
1515+
Annotatable::Expr(self.wrapped)
1516+
}
1517+
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
1518+
AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
1519+
}
1520+
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
1521+
noop_visit_expr(&mut self.wrapped, visitor)
1522+
}
1523+
fn is_mac_call(&self) -> bool {
1524+
matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
1525+
}
1526+
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
1527+
let node = self.wrapped.into_inner();
1528+
match node.kind {
1529+
ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
1530+
_ => unreachable!(),
1531+
}
1532+
}
1533+
}
1534+
14801535
struct InvocationCollector<'a, 'b> {
14811536
cx: &'a mut ExtCtxt<'b>,
14821537
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
@@ -1840,6 +1895,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
18401895
self.visit_node(node)
18411896
}
18421897

1898+
fn visit_method_receiver_expr(&mut self, node: &mut P<ast::Expr>) {
1899+
visit_clobber(node, |node| {
1900+
let mut wrapper = AstNodeWrapper::new(node, MethodReceiverTag);
1901+
self.visit_node(&mut wrapper);
1902+
wrapper.wrapped
1903+
})
1904+
}
1905+
18431906
fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
18441907
self.flat_map_node(AstNodeWrapper::new(node, OptExprTag))
18451908
}

compiler/rustc_expand/src/placeholders.rs

+8
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub fn placeholder(
5555
}),
5656
AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
5757
AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
58+
AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()),
5859
AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
5960
id,
6061
span,
@@ -296,6 +297,13 @@ impl MutVisitor for PlaceholderExpander {
296297
}
297298
}
298299

300+
fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
301+
match expr.kind {
302+
ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
303+
_ => noop_visit_expr(expr, self),
304+
}
305+
}
306+
299307
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
300308
match expr.kind {
301309
ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// check-pass
2+
3+
macro_rules! foo {
4+
() => {
5+
#[allow(unreachable_patterns)]
6+
{
7+
123i32
8+
}
9+
};
10+
}
11+
12+
fn main() {
13+
let _ = foo!().abs();
14+
}

src/test/ui/cfg/cfg-method-receiver.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@ macro_rules! cbor_map {
77

88
fn main() {
99
cbor_map! { #[cfg(test)] 4};
10-
//~^ ERROR attributes on expressions are experimental
11-
//~| ERROR removing an expression is not supported in this position
10+
//~^ ERROR removing an expression is not supported in this position
1211
}

src/test/ui/cfg/cfg-method-receiver.stderr

+2-12
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
error[E0658]: attributes on expressions are experimental
2-
--> $DIR/cfg-method-receiver.rs:9:17
3-
|
4-
LL | cbor_map! { #[cfg(test)] 4};
5-
| ^^^^^^^^^^^^
6-
|
7-
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
8-
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
9-
101
error: removing an expression is not supported in this position
112
--> $DIR/cfg-method-receiver.rs:9:17
123
|
@@ -28,7 +19,6 @@ help: you must specify a concrete type for this numeric value, like `i32`
2819
LL | cbor_map! { #[cfg(test)] 4_i32};
2920
| ~~~~~
3021

31-
error: aborting due to 3 previous errors
22+
error: aborting due to 2 previous errors
3223

33-
Some errors have detailed explanations: E0658, E0689.
34-
For more information about an error, try `rustc --explain E0658`.
24+
For more information about this error, try `rustc --explain E0689`.

0 commit comments

Comments
 (0)