about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late.rs24
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs24
-rw-r--r--tests/ui/delegation/macro-inside-list.rs4
-rw-r--r--tests/ui/delegation/self-hygiene.rs20
-rw-r--r--tests/ui/delegation/self-hygiene.stderr31
5 files changed, 81 insertions, 22 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index b0adc3775f6..fa711d932b6 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3281,17 +3281,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         }
         self.visit_path(&delegation.path, delegation.id);
         if let Some(body) = &delegation.body {
-            // `PatBoundCtx` is not necessary in this context
-            let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-
-            let span = delegation.path.segments.last().unwrap().ident.span;
-            self.fresh_binding(
-                Ident::new(kw::SelfLower, span),
-                delegation.id,
-                PatternSource::FnParam,
-                &mut bindings,
-            );
-            self.visit_block(body);
+            self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
+                // `PatBoundCtx` is not necessary in this context
+                let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+
+                let span = delegation.path.segments.last().unwrap().ident.span;
+                this.fresh_binding(
+                    Ident::new(kw::SelfLower, span),
+                    delegation.id,
+                    PatternSource::FnParam,
+                    &mut bindings,
+                );
+                this.visit_block(body);
+            });
         }
     }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 9eeb0da7ed2..be24755d4c5 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1021,12 +1021,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             },
         );
         let is_assoc_fn = self.self_type_is_available();
+        let self_from_macro = "a `self` parameter, but a macro invocation can only \
+                               access identifiers it receives from parameters";
         if let Some((fn_kind, span)) = &self.diag_metadata.current_function {
             // The current function has a `self` parameter, but we were unable to resolve
             // a reference to `self`. This can only happen if the `self` identifier we
             // are resolving came from a different hygiene context.
             if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {
-                err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
+                err.span_label(*span, format!("this function has {self_from_macro}"));
             } else {
                 let doesnt = if is_assoc_fn {
                     let (span, sugg) = fn_kind
@@ -1068,14 +1070,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
             }
         } else if let Some(item_kind) = self.diag_metadata.current_item {
-            err.span_label(
-                item_kind.ident.span,
-                format!(
-                    "`self` not allowed in {} {}",
-                    item_kind.kind.article(),
-                    item_kind.kind.descr()
-                ),
-            );
+            if matches!(item_kind.kind, ItemKind::Delegation(..)) {
+                err.span_label(item_kind.span, format!("delegation supports {self_from_macro}"));
+            } else {
+                err.span_label(
+                    item_kind.ident.span,
+                    format!(
+                        "`self` not allowed in {} {}",
+                        item_kind.kind.article(),
+                        item_kind.kind.descr()
+                    ),
+                );
+            }
         }
         true
     }
diff --git a/tests/ui/delegation/macro-inside-list.rs b/tests/ui/delegation/macro-inside-list.rs
index 16c74d396ef..d07a4e47dd4 100644
--- a/tests/ui/delegation/macro-inside-list.rs
+++ b/tests/ui/delegation/macro-inside-list.rs
@@ -14,9 +14,9 @@ struct S(u8);
 
 // Macro expansion works inside delegation items.
 macro_rules! u8 { () => { u8 } }
-macro_rules! self_0 { () => { &self.0 } }
+macro_rules! self_0 { ($self:ident) => { &$self.0 } }
 impl Trait for S {
-    reuse <u8!() as Trait>::{foo, bar} { self_0!() }
+    reuse <u8!() as Trait>::{foo, bar} { self_0!(self) }
 }
 
 fn main() {
diff --git a/tests/ui/delegation/self-hygiene.rs b/tests/ui/delegation/self-hygiene.rs
new file mode 100644
index 00000000000..dac6c319416
--- /dev/null
+++ b/tests/ui/delegation/self-hygiene.rs
@@ -0,0 +1,20 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+macro_rules! emit_self { () => { self } }
+//~^ ERROR expected value, found module `self`
+//~| ERROR expected value, found module `self`
+
+struct S;
+impl S {
+    fn method(self) {
+        emit_self!();
+    }
+}
+
+fn foo(arg: u8) {}
+reuse foo as bar {
+    emit_self!()
+}
+
+fn main() {}
diff --git a/tests/ui/delegation/self-hygiene.stderr b/tests/ui/delegation/self-hygiene.stderr
new file mode 100644
index 00000000000..fa64b7d1d7f
--- /dev/null
+++ b/tests/ui/delegation/self-hygiene.stderr
@@ -0,0 +1,31 @@
+error[E0424]: expected value, found module `self`
+  --> $DIR/self-hygiene.rs:4:34
+   |
+LL |   macro_rules! emit_self { () => { self } }
+   |                                    ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+...
+LL | /     fn method(self) {
+LL | |         emit_self!();
+   | |         ------------ in this macro invocation
+LL | |     }
+   | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
+   |
+   = note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0424]: expected value, found module `self`
+  --> $DIR/self-hygiene.rs:4:34
+   |
+LL |   macro_rules! emit_self { () => { self } }
+   |                                    ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+...
+LL | / reuse foo as bar {
+LL | |     emit_self!()
+   | |     ------------ in this macro invocation
+LL | | }
+   | |_- delegation supports a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
+   |
+   = note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0424`.