From 54062cff4cf06334bc49288afc2391b7dc204e65 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 22 Dec 2025 12:51:59 -0500 Subject: [PATCH 1/6] move a ui test to coretests unit test It only tests the usage and formatting of `fmt::Pointer`. --- library/coretests/tests/fmt/mod.rs | 19 +++++++++++++++++++ tests/ui/traits/fmt-pointer-trait.rs | 24 ------------------------ 2 files changed, 19 insertions(+), 24 deletions(-) delete mode 100644 tests/ui/traits/fmt-pointer-trait.rs diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index 0fb099ef41911..67ba49db4d919 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -76,6 +76,25 @@ fn test_fmt_debug_of_mut_reference() { assert_eq!(format!("{:?}", &mut x), "0"); } +#[test] +fn test_fmt_pointer() { + use std::rc::Rc; + use std::sync::Arc; + let p: *const u8 = std::ptr::null(); + let rc = Rc::new(1usize); + let arc = Arc::new(1usize); + let b = Box::new("hi"); + + let _ = format!("{rc:p}{arc:p}{b:p}"); + + if cfg!(target_pointer_width = "32") { + assert_eq!(format!("{:#p}", p), "0x00000000"); + } else { + assert_eq!(format!("{:#p}", p), "0x0000000000000000"); + } + assert_eq!(format!("{:p}", p), "0x0"); +} + #[test] fn test_default_write_impls() { use core::fmt::Write; diff --git a/tests/ui/traits/fmt-pointer-trait.rs b/tests/ui/traits/fmt-pointer-trait.rs deleted file mode 100644 index edf734597f50a..0000000000000 --- a/tests/ui/traits/fmt-pointer-trait.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -use std::ptr; -use std::rc::Rc; -use std::sync::Arc; - -fn main() { - let p: *const u8 = ptr::null(); - let rc = Rc::new(1usize); - let arc = Arc::new(1usize); - let b = Box::new("hi"); - - let _ = format!("{:p}{:p}{:p}", - rc, arc, b); - - if cfg!(target_pointer_width = "32") { - assert_eq!(format!("{:#p}", p), - "0x00000000"); - } else { - assert_eq!(format!("{:#p}", p), - "0x0000000000000000"); - } - assert_eq!(format!("{:p}", p), - "0x0"); -} From 2c0f14cb0c108ac72ea23645694a4abee75babd8 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Tue, 23 Dec 2025 03:33:20 +0000 Subject: [PATCH 2/6] bugfix: Fix compilation error in hermit-abi time.rs Fixes time.rs by updating the MIN and MAX structs appropriately. Signed-off-by: John Nunley --- library/std/src/sys/pal/hermit/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 53b1f9292b3d4..734ad2540a180 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -213,9 +213,9 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { - pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + pub const MAX: SystemTime = SystemTime(Timespec::MAX); - pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + pub const MIN: SystemTime = SystemTime(Timespec::MIN); pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) From ffd4da296e9238db0379433f111de2a38a50200f Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 22 Dec 2025 23:33:04 -0600 Subject: [PATCH 3/6] remove unsupported pipe module from VEXos pal --- library/std/src/sys/pal/vexos/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 3a37c8f2d4885..049b435905d43 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,6 +1,4 @@ pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod time; #[expect(dead_code)] From ffbb9a59322f57f1e38fe7b992e7b03ad2d00edd Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 18:42:41 +0100 Subject: [PATCH 4/6] compiletest: Add `LineNumber` newtype to avoid `+1` magic here and there Start small. If it works well we can increase usage bit by bit as time passes. Note that we keep using "0" to represent "no specific line" because changing to `Option` everywhere is much bigger and noisier change. That can be done later if wanted. --- src/tools/compiletest/src/directives.rs | 4 +++- src/tools/compiletest/src/directives/file.rs | 3 ++- src/tools/compiletest/src/directives/line.rs | 6 ++++-- .../compiletest/src/directives/line_number.rs | 21 +++++++++++++++++++ src/tools/compiletest/src/directives/tests.rs | 7 ++++--- src/tools/compiletest/src/runtest/debugger.rs | 18 +++++++--------- 6 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 src/tools/compiletest/src/directives/line_number.rs diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index c154886ebcdec..d1e0c5d95001c 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -29,6 +29,8 @@ mod directive_names; mod file; mod handlers; mod line; +mod line_number; +pub(crate) use line_number::LineNumber; mod needs; #[cfg(test)] mod tests; @@ -591,7 +593,7 @@ fn iter_directives( ]; // Process the extra implied directives, with a dummy line number of 0. for directive_str in extra_directives { - let directive_line = line_directive(testfile, 0, directive_str) + let directive_line = line_directive(testfile, LineNumber::ZERO, directive_str) .unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}")); it(&directive_line); } diff --git a/src/tools/compiletest/src/directives/file.rs b/src/tools/compiletest/src/directives/file.rs index 82819ac0c8f06..57186faa56b87 100644 --- a/src/tools/compiletest/src/directives/file.rs +++ b/src/tools/compiletest/src/directives/file.rs @@ -1,5 +1,6 @@ use camino::Utf8Path; +use crate::directives::LineNumber; use crate::directives::line::{DirectiveLine, line_directive}; pub(crate) struct FileDirectives<'a> { @@ -11,7 +12,7 @@ impl<'a> FileDirectives<'a> { pub(crate) fn from_file_contents(path: &'a Utf8Path, file_contents: &'a str) -> Self { let mut lines = vec![]; - for (line_number, ln) in (1..).zip(file_contents.lines()) { + for (line_number, ln) in LineNumber::enumerate().zip(file_contents.lines()) { let ln = ln.trim(); if let Some(directive_line) = line_directive(path, line_number, ln) { diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs index 16dd9a8de1c03..9cc24c98a859d 100644 --- a/src/tools/compiletest/src/directives/line.rs +++ b/src/tools/compiletest/src/directives/line.rs @@ -2,13 +2,15 @@ use std::fmt; use camino::Utf8Path; +use crate::directives::LineNumber; + const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; /// If the given line begins with the appropriate comment prefix for a directive, /// returns a struct containing various parts of the directive. pub(crate) fn line_directive<'a>( file_path: &'a Utf8Path, - line_number: usize, + line_number: LineNumber, original_line: &'a str, ) -> Option> { // Ignore lines that don't start with the comment prefix. @@ -60,7 +62,7 @@ pub(crate) struct DirectiveLine<'a> { /// Mostly used for diagnostics, but some directives (e.g. `//@ pp-exact`) /// also use it to compute a value based on the filename. pub(crate) file_path: &'a Utf8Path, - pub(crate) line_number: usize, + pub(crate) line_number: LineNumber, /// Some test directives start with a revision name in square brackets /// (e.g. `[foo]`), and only apply to that revision of the test. diff --git a/src/tools/compiletest/src/directives/line_number.rs b/src/tools/compiletest/src/directives/line_number.rs new file mode 100644 index 0000000000000..ce5f200f470c8 --- /dev/null +++ b/src/tools/compiletest/src/directives/line_number.rs @@ -0,0 +1,21 @@ +/// A line number in a file. Internally the first line has index 1. +/// If it is 0 it means "no specific line" (used e.g. for implied directives). +/// When `Display`:ed, the first line is `1`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct LineNumber(usize); + +impl LineNumber { + /// This represents "no specific line" (used e.g. for implied directives). + pub(crate) const ZERO: Self = Self(0); + + /// A never ending iterator over line numbers starting from the first line. + pub(crate) fn enumerate() -> impl Iterator { + (1..).map(LineNumber) + } +} + +impl std::fmt::Display for LineNumber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 90e2cb77e304c..dfc733cf4e322 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -6,8 +6,8 @@ use semver::Version; use crate::common::{Config, Debugger, TestMode}; use crate::directives::{ self, AuxProps, DIRECTIVE_HANDLERS_MAP, DirectivesCache, EarlyProps, Edition, EditionRange, - FileDirectives, KNOWN_DIRECTIVE_NAMES_SET, extract_llvm_version, extract_version_range, - line_directive, parse_edition, parse_normalize_rule, + FileDirectives, KNOWN_DIRECTIVE_NAMES_SET, LineNumber, extract_llvm_version, + extract_version_range, line_directive, parse_edition, parse_normalize_rule, }; use crate::executor::{CollectedTestDesc, ShouldFail}; @@ -1000,7 +1000,8 @@ fn parse_edition_range(line: &str) -> Option { let config = cfg().build(); let line_with_comment = format!("//@ {line}"); - let line = line_directive(Utf8Path::new("tmp.rs"), 0, &line_with_comment).unwrap(); + let line = + line_directive(Utf8Path::new("tmp.rs"), LineNumber::ZERO, &line_with_comment).unwrap(); super::parse_edition_range(&config, &line) } diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 00935ab57d1c3..c83e00c1006e4 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,6 +4,7 @@ use std::io::{BufRead, BufReader}; use camino::{Utf8Path, Utf8PathBuf}; +use crate::directives::LineNumber; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -11,9 +12,9 @@ pub(super) struct DebuggerCommands { /// Commands for the debuuger pub commands: Vec, /// Lines to insert breakpoints at - pub breakpoint_lines: Vec, + pub breakpoint_lines: Vec, /// Contains the source line number to check and the line itself - check_lines: Vec<(usize, String)>, + check_lines: Vec<(LineNumber, String)>, /// Source file name file: Utf8PathBuf, } @@ -26,15 +27,13 @@ impl DebuggerCommands { let mut breakpoint_lines = vec![]; let mut commands = vec![]; let mut check_lines = vec![]; - let mut counter = 0; let reader = BufReader::new(File::open(file.as_std_path()).unwrap()); - for (line_no, line) in reader.lines().enumerate() { - counter += 1; + for (line_number, line) in LineNumber::enumerate().zip(reader.lines()) { let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?; // Breakpoints appear on lines with actual code, typically at the end of the line. if line.contains("#break") { - breakpoint_lines.push(counter); + breakpoint_lines.push(line_number); continue; } @@ -46,7 +45,7 @@ impl DebuggerCommands { commands.push(command); } if let Some(pattern) = parse_name_value(&line, &check_directive) { - check_lines.push((line_no, pattern)); + check_lines.push((line_number, pattern)); } } @@ -88,15 +87,14 @@ impl DebuggerCommands { ); for (src_lineno, err_line) in missing { - write!(msg, "\n ({fname}:{num}) `{err_line}`", num = src_lineno + 1).unwrap(); + write!(msg, "\n ({fname}:{src_lineno}) `{err_line}`").unwrap(); } if !found.is_empty() { let init = "\nthe following subset of check directive(s) was found successfully:"; msg.push_str(init); for (src_lineno, found_line) in found { - write!(msg, "\n ({fname}:{num}) `{found_line}`", num = src_lineno + 1) - .unwrap(); + write!(msg, "\n ({fname}:{src_lineno}) `{found_line}`").unwrap(); } } From 1de1885a63804bd5e0538ba76ab27278b6acf01f Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 23 Dec 2025 10:34:23 +0300 Subject: [PATCH 5/6] Support syntax for one-line trait reuse --- compiler/rustc_parse/messages.ftl | 2 + compiler/rustc_parse/src/errors.rs | 7 + compiler/rustc_parse/src/parser/item.rs | 144 +++++++-- tests/pretty/delegation-impl-reuse.pp | 46 +++ tests/pretty/delegation-impl-reuse.rs | 18 ++ tests/ui/delegation/impl-reuse-bad-path.rs | 31 ++ .../ui/delegation/impl-reuse-bad-path.stderr | 52 ++++ tests/ui/delegation/impl-reuse-empty-glob.rs | 14 + .../delegation/impl-reuse-empty-glob.stderr | 8 + .../delegation/impl-reuse-illegal-places.rs | 51 +++ .../impl-reuse-illegal-places.stderr | 92 ++++++ .../delegation/impl-reuse-negative-traits.rs | 19 ++ .../impl-reuse-negative-traits.stderr | 9 + .../delegation/impl-reuse-non-reuse-items.rs | 32 ++ .../impl-reuse-non-reuse-items.stderr | 60 ++++ .../impl-reuse-non-trait-impl-cfg-false.rs | 10 + ...impl-reuse-non-trait-impl-cfg-false.stderr | 8 + .../delegation/impl-reuse-non-trait-impl.rs | 9 + .../impl-reuse-non-trait-impl.stderr | 8 + tests/ui/delegation/impl-reuse-pass.rs | 292 ++++++++++++++++++ 20 files changed, 879 insertions(+), 33 deletions(-) create mode 100644 tests/pretty/delegation-impl-reuse.pp create mode 100644 tests/pretty/delegation-impl-reuse.rs create mode 100644 tests/ui/delegation/impl-reuse-bad-path.rs create mode 100644 tests/ui/delegation/impl-reuse-bad-path.stderr create mode 100644 tests/ui/delegation/impl-reuse-empty-glob.rs create mode 100644 tests/ui/delegation/impl-reuse-empty-glob.stderr create mode 100644 tests/ui/delegation/impl-reuse-illegal-places.rs create mode 100644 tests/ui/delegation/impl-reuse-illegal-places.stderr create mode 100644 tests/ui/delegation/impl-reuse-negative-traits.rs create mode 100644 tests/ui/delegation/impl-reuse-negative-traits.stderr create mode 100644 tests/ui/delegation/impl-reuse-non-reuse-items.rs create mode 100644 tests/ui/delegation/impl-reuse-non-reuse-items.stderr create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl.rs create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl.stderr create mode 100644 tests/ui/delegation/impl-reuse-pass.rs diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 87d1173c0d486..747895c804697 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -162,6 +162,8 @@ parse_default_not_followed_by_item = `default` is not followed by an item .label = the `default` qualifier .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` +parse_delegation_non_trait_impl_reuse = only trait impls can be reused + parse_do_catch_syntax_removed = found removed `do catch` syntax .note = following RFC #2388, the new non-placeholder syntax is `try` .suggestion = replace with the new syntax diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 698d8f76aaa64..3b72c9802afd3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3671,3 +3671,10 @@ pub(crate) struct VarargsWithoutPattern { #[suggestion(code = "_: ...", applicability = "machine-applicable")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_delegation_non_trait_impl_reuse)] +pub(crate) struct ImplReuseInherentImpl { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 33913fd351a18..fb8b76e322090 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -117,6 +117,11 @@ impl<'a> Parser<'a> { } } +enum ReuseKind { + Path, + Impl, +} + impl<'a> Parser<'a> { pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option>> { let fn_parse_mode = @@ -249,9 +254,9 @@ impl<'a> Parser<'a> { } else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? - } else if self.check_impl_frontmatter() { + } else if self.check_impl_frontmatter(0) { // IMPL ITEM - self.parse_item_impl(attrs, def_())? + self.parse_item_impl(attrs, def_(), false)? } else if let Const::Yes(const_span) = self.parse_constness(case) { // CONST ITEM self.recover_const_mut(const_span); @@ -265,8 +270,8 @@ impl<'a> Parser<'a> { rhs, define_opaque: None, })) - } else if self.is_reuse_path_item() { - self.parse_item_delegation()? + } else if let Some(kind) = self.is_reuse_item() { + self.parse_item_delegation(attrs, def_(), kind)? } else if self.check_keyword_case(exp!(Mod), case) || self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod]) { @@ -367,16 +372,25 @@ impl<'a> Parser<'a> { /// When parsing a statement, would the start of a path be an item? pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` - || self.is_reuse_path_item() + || self.is_reuse_item().is_some() // yes: `reuse impl Trait for Struct { self.0 }`, yes: `reuse some_path::foo;` || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } - fn is_reuse_path_item(&mut self) -> bool { + fn is_reuse_item(&mut self) -> Option { + if !self.token.is_keyword(kw::Reuse) { + return None; + } + // no: `reuse ::path` for compatibility reasons with macro invocations - self.token.is_keyword(kw::Reuse) - && self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) + if self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) { + Some(ReuseKind::Path) + } else if self.check_impl_frontmatter(1) { + Some(ReuseKind::Impl) + } else { + None + } } /// Are we sure this could not possibly be a macro invocation? @@ -560,6 +574,7 @@ impl<'a> Parser<'a> { &mut self, attrs: &mut AttrVec, defaultness: Defaultness, + is_reuse: bool, ) -> PResult<'a, ItemKind> { let mut constness = self.parse_constness(Case::Sensitive); let safety = self.parse_safety(Case::Sensitive); @@ -628,7 +643,11 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; - let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?; + let impl_items = if is_reuse { + Default::default() + } else { + self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))? + }; let (of_trait, self_ty) = match ty_second { Some(ty_second) => { @@ -699,10 +718,76 @@ impl<'a> Parser<'a> { Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, constness })) } - fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> { + fn parse_item_delegation( + &mut self, + attrs: &mut AttrVec, + defaultness: Defaultness, + kind: ReuseKind, + ) -> PResult<'a, ItemKind> { let span = self.token.span; self.expect_keyword(exp!(Reuse))?; + let item_kind = match kind { + ReuseKind::Path => self.parse_path_like_delegation(), + ReuseKind::Impl => self.parse_impl_delegation(span, attrs, defaultness), + }?; + + self.psess.gated_spans.gate(sym::fn_delegation, span.to(self.prev_token.span)); + + Ok(item_kind) + } + + fn parse_delegation_body(&mut self) -> PResult<'a, Option>> { + Ok(if self.check(exp!(OpenBrace)) { + Some(self.parse_block()?) + } else { + self.expect(exp!(Semi))?; + None + }) + } + + fn parse_impl_delegation( + &mut self, + span: Span, + attrs: &mut AttrVec, + defaultness: Defaultness, + ) -> PResult<'a, ItemKind> { + let mut impl_item = self.parse_item_impl(attrs, defaultness, true)?; + let ItemKind::Impl(Impl { items, of_trait, .. }) = &mut impl_item else { unreachable!() }; + + let until_expr_span = span.to(self.prev_token.span); + + let Some(of_trait) = of_trait else { + return Err(self + .dcx() + .create_err(errors::ImplReuseInherentImpl { span: until_expr_span })); + }; + + let body = self.parse_delegation_body()?; + let whole_reuse_span = span.to(self.prev_token.span); + + items.push(Box::new(AssocItem { + id: DUMMY_NODE_ID, + attrs: Default::default(), + span: whole_reuse_span, + tokens: None, + vis: Visibility { + kind: VisibilityKind::Inherited, + span: whole_reuse_span, + tokens: None, + }, + kind: AssocItemKind::DelegationMac(Box::new(DelegationMac { + qself: None, + prefix: of_trait.trait_ref.path.clone(), + suffixes: None, + body, + })), + })); + + Ok(impl_item) + } + + fn parse_path_like_delegation(&mut self) -> PResult<'a, ItemKind> { let (qself, path) = if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; (Some(qself), path) @@ -713,43 +798,35 @@ impl<'a> Parser<'a> { let rename = |this: &mut Self| { Ok(if this.eat_keyword(exp!(As)) { Some(this.parse_ident()?) } else { None }) }; - let body = |this: &mut Self| { - Ok(if this.check(exp!(OpenBrace)) { - Some(this.parse_block()?) - } else { - this.expect(exp!(Semi))?; - None - }) - }; - let item_kind = if self.eat_path_sep() { + Ok(if self.eat_path_sep() { let suffixes = if self.eat(exp!(Star)) { None } else { let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?)); Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0) }; - let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? }; - ItemKind::DelegationMac(Box::new(deleg)) + + ItemKind::DelegationMac(Box::new(DelegationMac { + qself, + prefix: path, + suffixes, + body: self.parse_delegation_body()?, + })) } else { let rename = rename(self)?; let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); - let deleg = Delegation { + + ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, ident, rename, - body: body(self)?, + body: self.parse_delegation_body()?, from_glob: false, - }; - ItemKind::Delegation(Box::new(deleg)) - }; - - let span = span.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::fn_delegation, span); - - Ok(item_kind) + })) + }) } fn parse_item_list( @@ -2594,7 +2671,7 @@ impl<'a> Parser<'a> { Ok(body) } - fn check_impl_frontmatter(&mut self) -> bool { + fn check_impl_frontmatter(&mut self, look_ahead: usize) -> bool { const ALL_QUALS: &[Symbol] = &[kw::Const, kw::Unsafe]; // In contrast to the loop below, this call inserts `impl` into the // list of expected tokens shown in diagnostics. @@ -2603,7 +2680,7 @@ impl<'a> Parser<'a> { } let mut i = 0; while i < ALL_QUALS.len() { - let action = self.look_ahead(i, |token| { + let action = self.look_ahead(i + look_ahead, |token| { if token.is_keyword(kw::Impl) { return Some(true); } @@ -2618,6 +2695,7 @@ impl<'a> Parser<'a> { } i += 1; } + self.is_keyword_ahead(i, &[kw::Impl]) } diff --git a/tests/pretty/delegation-impl-reuse.pp b/tests/pretty/delegation-impl-reuse.pp new file mode 100644 index 0000000000000..72f62de0eacbf --- /dev/null +++ b/tests/pretty/delegation-impl-reuse.pp @@ -0,0 +1,46 @@ +#![feature(prelude_import)] +#![no_std] +//@ pretty-compare-only +//@ pretty-mode:expanded +//@ pp-exact:delegation-impl-reuse.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[macro_use] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} + fn baz(&self) {} +} + +struct S; + +impl Trait<{ + struct S; + 0 + }> for S { + reuse Trait<{ + struct S; + 0 + }>::foo { + self.0 + } + reuse Trait<{ + struct S; + 0 + }>::bar { + self.0 + } + reuse Trait<{ + struct S; + 0 + }>::baz { + self.0 + } +} + +fn main() {} diff --git a/tests/pretty/delegation-impl-reuse.rs b/tests/pretty/delegation-impl-reuse.rs new file mode 100644 index 0000000000000..9265ea18a76f0 --- /dev/null +++ b/tests/pretty/delegation-impl-reuse.rs @@ -0,0 +1,18 @@ +//@ pretty-compare-only +//@ pretty-mode:expanded +//@ pp-exact:delegation-impl-reuse.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} + fn baz(&self) {} +} + +struct S; + +reuse impl Trait<{ struct S; 0 }> for S { self.0 } + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-bad-path.rs b/tests/ui/delegation/impl-reuse-bad-path.rs new file mode 100644 index 0000000000000..19eb51153468d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-bad-path.rs @@ -0,0 +1,31 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod unresolved { + struct S; + reuse impl unresolved for S { self.0 } + //~^ ERROR failed to resolve: use of unresolved module or unlinked crate `unresolved` + //~| ERROR cannot find trait `unresolved` in this scope + + trait T {} + reuse impl T for unresolved { self.0 } + //~^ ERROR empty glob delegation is not supported + //~| ERROR cannot find type `unresolved` in this scope +} + +mod wrong_entities { + trait T {} + struct Trait; + struct S; + + reuse impl Trait for S { self.0 } + //~^ ERROR expected trait, found struct `Trait` + //~| ERROR expected trait, found struct `Trait` + + mod TraitModule {} + reuse impl TraitModule for S { self.0 } + //~^ ERROR expected trait, found module `TraitModule` + //~| ERROR expected trait, found module `TraitModule` +} + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-bad-path.stderr b/tests/ui/delegation/impl-reuse-bad-path.stderr new file mode 100644 index 0000000000000..5fadd719ae4da --- /dev/null +++ b/tests/ui/delegation/impl-reuse-bad-path.stderr @@ -0,0 +1,52 @@ +error: empty glob delegation is not supported + --> $DIR/impl-reuse-bad-path.rs:11:5 + | +LL | reuse impl T for unresolved { self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected trait, found struct `Trait` + --> $DIR/impl-reuse-bad-path.rs:21:16 + | +LL | reuse impl Trait for S { self.0 } + | ^^^^^ not a trait + +error: expected trait, found module `TraitModule` + --> $DIR/impl-reuse-bad-path.rs:26:16 + | +LL | reuse impl TraitModule for S { self.0 } + | ^^^^^^^^^^^ not a trait + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `unresolved` + --> $DIR/impl-reuse-bad-path.rs:6:16 + | +LL | reuse impl unresolved for S { self.0 } + | ^^^^^^^^^^ use of unresolved module or unlinked crate `unresolved` + +error[E0405]: cannot find trait `unresolved` in this scope + --> $DIR/impl-reuse-bad-path.rs:6:16 + | +LL | reuse impl unresolved for S { self.0 } + | ^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find type `unresolved` in this scope + --> $DIR/impl-reuse-bad-path.rs:11:22 + | +LL | reuse impl T for unresolved { self.0 } + | ^^^^^^^^^^ not found in this scope + +error[E0404]: expected trait, found struct `Trait` + --> $DIR/impl-reuse-bad-path.rs:21:16 + | +LL | reuse impl Trait for S { self.0 } + | ^^^^^ not a trait + +error[E0404]: expected trait, found module `TraitModule` + --> $DIR/impl-reuse-bad-path.rs:26:16 + | +LL | reuse impl TraitModule for S { self.0 } + | ^^^^^^^^^^^ not a trait + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0404, E0405, E0425, E0433. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/delegation/impl-reuse-empty-glob.rs b/tests/ui/delegation/impl-reuse-empty-glob.rs new file mode 100644 index 0000000000000..3f1314c47da62 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-empty-glob.rs @@ -0,0 +1,14 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod empty_glob { + trait T {} + + struct S; + + reuse impl T for S { self.0 } + //~^ ERROR empty glob delegation is not supported +} + + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-empty-glob.stderr b/tests/ui/delegation/impl-reuse-empty-glob.stderr new file mode 100644 index 0000000000000..bf6bb58763519 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-empty-glob.stderr @@ -0,0 +1,8 @@ +error: empty glob delegation is not supported + --> $DIR/impl-reuse-empty-glob.rs:9:5 + | +LL | reuse impl T for S { self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/impl-reuse-illegal-places.rs b/tests/ui/delegation/impl-reuse-illegal-places.rs new file mode 100644 index 0000000000000..361331d41315d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-illegal-places.rs @@ -0,0 +1,51 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait T { + fn f(&self) {} +} + +struct S; +impl T for S {} + +struct F(S); + +struct X { + reuse impl T for F { self.0 } + //~^ ERROR expected `:`, found keyword `impl` +} + +impl X { + reuse impl T for F { self.0 } + //~^ ERROR implementation is not supported in `trait`s or `impl`s +} + +trait Trait { + reuse impl T for F { self.0 } + //~^ ERROR implementation is not supported in `trait`s or `impl`s +} + +extern "C" { + reuse impl T for F { self.0 } + //~^ ERROR implementation is not supported in `extern` blocks +} + +mod m { + mod inner { + pub fn foo() {} + } + + reuse inner::{ + reuse impl T for F { self.0 } + //~^ ERROR expected identifier, found keyword `impl` + //~| ERROR expected one of `,`, `as`, or `}`, found keyword `impl` + //~| ERROR expected one of `,`, `as`, or `}`, found `T` + //~| ERROR expected identifier, found keyword `for` + //~| ERROR expected one of `,`, `as`, or `}`, found keyword `for` + //~| ERROR expected one of `,`, `as`, or `}`, found `F` + //~| ERROR expected one of `,`, `as`, or `}`, found `{` + } +} +//~^ ERROR expected item, found `}` + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-illegal-places.stderr b/tests/ui/delegation/impl-reuse-illegal-places.stderr new file mode 100644 index 0000000000000..fb17ebdd6cee1 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-illegal-places.stderr @@ -0,0 +1,92 @@ +error: expected `:`, found keyword `impl` + --> $DIR/impl-reuse-illegal-places.rs:14:11 + | +LL | struct X { + | - while parsing this struct +LL | reuse impl T for F { self.0 } + | ^^^^ expected `:` + +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/impl-reuse-illegal-places.rs:19:5 + | +LL | reuse impl T for F { self.0 } + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider moving the implementation out to a nearby module scope + +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/impl-reuse-illegal-places.rs:24:5 + | +LL | reuse impl T for F { self.0 } + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider moving the implementation out to a nearby module scope + +error: implementation is not supported in `extern` blocks + --> $DIR/impl-reuse-illegal-places.rs:29:5 + | +LL | reuse impl T for F { self.0 } + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider moving the implementation out to a nearby module scope + +error: expected identifier, found keyword `impl` + --> $DIR/impl-reuse-illegal-places.rs:39:15 + | +LL | reuse impl T for F { self.0 } + | ^^^^ expected identifier, found keyword + +error: expected one of `,`, `as`, or `}`, found keyword `impl` + --> $DIR/impl-reuse-illegal-places.rs:39:15 + | +LL | reuse impl T for F { self.0 } + | -^^^^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected one of `,`, `as`, or `}`, found `T` + --> $DIR/impl-reuse-illegal-places.rs:39:20 + | +LL | reuse impl T for F { self.0 } + | -^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected identifier, found keyword `for` + --> $DIR/impl-reuse-illegal-places.rs:39:22 + | +LL | reuse impl T for F { self.0 } + | ^^^ expected identifier, found keyword + +error: expected one of `,`, `as`, or `}`, found keyword `for` + --> $DIR/impl-reuse-illegal-places.rs:39:22 + | +LL | reuse impl T for F { self.0 } + | -^^^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected one of `,`, `as`, or `}`, found `F` + --> $DIR/impl-reuse-illegal-places.rs:39:26 + | +LL | reuse impl T for F { self.0 } + | -^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected one of `,`, `as`, or `}`, found `{` + --> $DIR/impl-reuse-illegal-places.rs:39:28 + | +LL | reuse impl T for F { self.0 } + | ^ expected one of `,`, `as`, or `}` + +error: expected item, found `}` + --> $DIR/impl-reuse-illegal-places.rs:48:1 + | +LL | } + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 12 previous errors + diff --git a/tests/ui/delegation/impl-reuse-negative-traits.rs b/tests/ui/delegation/impl-reuse-negative-traits.rs new file mode 100644 index 0000000000000..7bcbc82f03db8 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-negative-traits.rs @@ -0,0 +1,19 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#![feature(negative_impls)] + +trait Trait { + fn foo(&self); + //~^ ERROR negative impls cannot have any items [E0749] +} + +struct S; +impl Trait for S { + fn foo(&self) {} +} + +struct F(S); + +reuse impl !Trait for F { &self.0 } + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-negative-traits.stderr b/tests/ui/delegation/impl-reuse-negative-traits.stderr new file mode 100644 index 0000000000000..1be6ef715920d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-negative-traits.stderr @@ -0,0 +1,9 @@ +error[E0749]: negative impls cannot have any items + --> $DIR/impl-reuse-negative-traits.rs:6:8 + | +LL | fn foo(&self); + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0749`. diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.rs b/tests/ui/delegation/impl-reuse-non-reuse-items.rs new file mode 100644 index 0000000000000..de7c92279218d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.rs @@ -0,0 +1,32 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod non_delegatable_items { + trait Trait { + fn method(&self); + const CONST: u8; + type Type; + #[allow(non_camel_case_types)] + type method; + } + + struct F; + impl Trait for F { + fn method(&self) {} + const CONST: u8 = 0; + type Type = u8; + type method = u8; + } + + struct S(F); + + reuse impl Trait for S { &self.0 } + //~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait` + //~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait` + //~| ERROR duplicate definitions with name `method` + //~| ERROR expected function, found associated constant `Trait::CONST` + //~| ERROR expected function, found associated type `Trait::Type` + //~| ERROR not all trait items implemented, missing: `CONST`, `Type`, `method` +} + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.stderr b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr new file mode 100644 index 0000000000000..9d6b0f6381367 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr @@ -0,0 +1,60 @@ +error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait` + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | const CONST: u8; + | ---------------- item in trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait` + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | type Type; + | ---------- item in trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | fn method(&self); + | ----------------- item in trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | duplicate definition + | previous definition here + +error[E0423]: expected function, found associated constant `Trait::CONST` + --> $DIR/impl-reuse-non-reuse-items.rs:23:16 + | +LL | reuse impl Trait for S { &self.0 } + | ^^^^^ not a function + +error[E0423]: expected function, found associated type `Trait::Type` + --> $DIR/impl-reuse-non-reuse-items.rs:23:16 + | +LL | reuse impl Trait for S { &self.0 } + | ^^^^^ not a function + +error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method` + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | const CONST: u8; + | --------------- `CONST` from trait +LL | type Type; + | --------- `Type` from trait +LL | #[allow(non_camel_case_types)] +LL | type method; + | ----------- `method` from trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0046, E0201, E0324, E0423. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs new file mode 100644 index 0000000000000..51ef1dc14ba86 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +struct Trait(usize); + +#[cfg(false)] +reuse impl Trait { self.0 } +//~^ ERROR only trait impls can be reused + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr new file mode 100644 index 0000000000000..24a138016116c --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr @@ -0,0 +1,8 @@ +error: only trait impls can be reused + --> $DIR/impl-reuse-non-trait-impl-cfg-false.rs:7:1 + | +LL | reuse impl Trait { self.0 } + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl.rs b/tests/ui/delegation/impl-reuse-non-trait-impl.rs new file mode 100644 index 0000000000000..c7a9813250db9 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +struct Trait(usize); + +reuse impl Trait { self.0 } +//~^ ERROR only trait impls can be reused + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl.stderr b/tests/ui/delegation/impl-reuse-non-trait-impl.stderr new file mode 100644 index 0000000000000..3987042104c38 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl.stderr @@ -0,0 +1,8 @@ +error: only trait impls can be reused + --> $DIR/impl-reuse-non-trait-impl.rs:6:1 + | +LL | reuse impl Trait { self.0 } + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/impl-reuse-pass.rs b/tests/ui/delegation/impl-reuse-pass.rs new file mode 100644 index 0000000000000..90060b03f9efd --- /dev/null +++ b/tests/ui/delegation/impl-reuse-pass.rs @@ -0,0 +1,292 @@ +//@ check-pass + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#![feature(const_trait_impl)] +#![allow(warnings)] + +mod default { + trait T { + fn foo(&self) {} + fn bar(&self) {} + fn goo(&self) {} + } + + struct S; + impl T for S {} + + struct F(S); + reuse impl T for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + f.goo(); + } +} + +mod dyn_traits { + trait T { + fn foo(&self) -> Box; + } + + trait SecondTrait { + fn bar(&self); + } + + reuse impl SecondTrait for dyn T { self.foo().as_ref() } +} + +mod complex_path { + pub mod first { + pub mod second { + pub trait T { + fn foo(&self, x: usize); + } + } + } + + struct S; + impl first::second::T for S { + fn foo(&self, x: usize) { } + } + + struct F(S); + reuse impl first::second::T for F { self.0 } + + fn f() { + use complex_path::first::second::T; + + let f = F(S{}); + + f.foo(1); + } +} + +mod no_body_reuse { + trait T { + fn foo(&self) {} + fn bar(&mut self) {} + } + + struct F; + + reuse impl T for F; + + fn foo() { + let mut f = F{}; + + f.foo(); + f.bar(); + } +} + +mod unsafe_trait { + unsafe trait UnsafeTrait { + fn foo(&self) {} + fn bar(&self) {} + fn goo(&self) {} + } + + struct S; + unsafe impl UnsafeTrait for S {} + + struct F(S); + reuse unsafe impl UnsafeTrait for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + f.goo(); + } +} + +mod const_trait { + const trait ConstTrait { + fn foo(&self) -> usize { 0 } + fn bar(&self) -> usize { 1 } + } + + struct S; + const impl ConstTrait for S {} + + struct F(S); + reuse const impl ConstTrait for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + } +} + +mod different_selves { + trait T: Sized { + fn foo(&self) {} + fn boo(self) {} + fn goo(&mut self) {} + } + + struct S; + impl T for S {} + + struct F(S); + reuse impl T for F { self.0 } + + struct D(S); + macro_rules! self_0 { ($self:ident) => { $self.0 } } + + reuse impl T for D { self_0!(self) } + + fn f() { + let mut f = F(S{}); + f.foo(); + f.goo(); + f.boo(); + + let mut d = D(S{}); + d.foo(); + d.goo(); + d.boo(); + } +} + +mod macros { + trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } + } + + impl Trait for u8 {} + struct S(u8); + + macro_rules! self_0_ref { ($self:ident) => { &$self.0 } } + + reuse impl Trait for S { self_0_ref!(self) } + + struct M(u8); + macro_rules! m { () => { M } } + reuse impl Trait for m!() { self_0_ref!(self) } + + struct S1(u8); + macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } } + one_line_reuse!(self); + + struct S2(u8); + macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } } + one_line_reuse_expr!(self.0); + + struct S3(u8); + macro_rules! s3 { () => { S3 } } + macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } } + one_line_reuse_expr2!(self.0); + + fn f() { + let s = S(1); + s.foo(); + s.bar(); + + let m = M(41); + m.foo(); + m.bar(); + + let s1 = S1(2); + s1.foo(); + s1.bar(); + + let s2 = S2(4); + s2.foo(); + s2.bar(); + + let s3 = S3(5); + s3.foo(); + s3.bar(); + } +} + +mod generics { + trait Trait<'a, 'b, A, B, C> { + fn foo(&self, a: &A) {} + fn bar(&self, b: &B) {} + fn goo(&self, c: &C) {} + } + + struct S; + impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for S {} + + struct F(S); + reuse impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for F { &self.0 } + + struct S1; + struct F1(S1); + impl<'c, B> Trait<'static, 'c, usize, B, String> for S1 {} + reuse impl<'d, B> Trait<'static, 'd, usize, B, String> for F1 { &self.0 } + + struct S2; + struct F2(S2); + impl Trait<'static, 'static, u8, u16, u32> for S2 {} + reuse impl Trait<'static, 'static, u8, u16, u32> for F2 { &self.0 } + + fn f<'a, 'b, 'c, A, B, C>(a: A, b: B, c: C) { + let f = F(S{}); + + >::foo(&f, &a); + >::bar(&f, &b); + >::goo(&f, &c); + + let f = F1(S1{}); + >::foo(&f, &123); + >::bar(&f, &b); + >::goo(&f, &"s".to_string()); + + let f = F2(S2{}); + >::foo(&f, &1); + >::bar(&f, &2); + >::goo(&f, &3); + } +} + +mod reuse_in_different_places { + trait T { + fn foo(&self, x: usize) {} + } + + struct S; + impl T for S {} + + struct F1(S); + reuse impl T for F1 { + struct F2(S, S, S); + reuse impl T for F2 { self.1 } + + let f2 = F2(S{}, S{}, S{}); + f2.foo(123); + + &self.0 + } + + fn foo() { + struct F(S); + reuse impl T for F { self.0 } + + let f = F(S{}); + f.foo(1); + } + + fn bar() { + || { + struct F(S); + reuse impl T for F { self.0 } + + let f = F(S{}); + f.foo(1); + }; + } +} + +fn main() {} From f289ccf207ede543f23d5998bf5ee6a0b793bdf2 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 22 Dec 2025 23:49:11 -0800 Subject: [PATCH 6/6] `target_features::Stability`: tweak docs of `requires_nightly()` * No method named `allow_toggle()` exists on the type, but based on the documentation of both `requires_nightly()` and `toggle_allowed()` it seems that `toggle_allowed()` is the intended method to mention. * Add `()` to the mention of `in_cfg()` to make it clear that a method is being referred to, and to match the presence of `()` in the mention of `toggle_allowed()`. --- compiler/rustc_target/src/target_features.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 35cfeba2bffd1..85c473c5abb23 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -62,8 +62,8 @@ impl Stability { /// the feature gate to actually be enabled when using a nightly compiler.) /// /// Before calling this, ensure the feature is even permitted for this use: - /// - for `#[target_feature]`/`-Ctarget-feature`, check `allow_toggle()` - /// - for `cfg(target_feature)`, check `in_cfg` + /// - for `#[target_feature]`/`-Ctarget-feature`, check `toggle_allowed()` + /// - for `cfg(target_feature)`, check `in_cfg()` pub fn requires_nightly(&self) -> Option { match *self { Stability::Unstable(nightly_feature) => Some(nightly_feature),