From ed6a78ca868625faa50c66409037df66bff3e5bd Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Wed, 19 Nov 2025 15:50:40 +0000 Subject: [PATCH 1/2] Fix error message for calling a non-tuple struct --- .../rustc_resolve/src/late/diagnostics.rs | 40 +++++++++++++------ ...ession-struct-called-as-function-148919.rs | 10 +++++ ...on-struct-called-as-function-148919.stderr | 9 +++++ 3 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 tests/ui/resolve/regression-struct-called-as-function-148919.rs create mode 100644 tests/ui/resolve/regression-struct-called-as-function-148919.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0b4c52d68b6ff..74afae7996b24 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -823,8 +823,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } if let Some(Res::Def(DefKind::Struct, def_id)) = res { - self.update_err_for_private_tuple_struct_fields(err, &source, def_id); - err.note("constructor is not visible here due to private fields"); + if self.has_private_fields(def_id) { + self.update_err_for_private_tuple_struct_fields(err, &source, def_id); + err.note("constructor is not visible here due to private fields"); + } } else { err.span_suggestion( call_span, @@ -1642,6 +1644,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn has_tuple_fields(&mut self, def_id: DefId) -> bool { + // As we cannot name a field "0", this is an indictation + // that we are looking at a tuple struct + if let Some(fields) = self.r.field_idents(def_id) { + if let Some(first_field) = fields.get(0) { + return first_field.name.as_str() == "0"; + } + } + false + } + fn update_err_for_private_tuple_struct_fields( &mut self, err: &mut Diag<'_>, @@ -1664,17 +1677,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { span: call_span, .. })) => { - err.primary_message( - "cannot initialize a tuple struct which contains private fields", - ); - self.suggest_alternative_construction_methods( - def_id, - err, - path.span, - *call_span, - &args[..], - ); - // Use spans of the tuple struct definition. + if self.has_tuple_fields(def_id) { + err.primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + self.suggest_alternative_construction_methods( + def_id, + err, + path.span, + *call_span, + &args[..], + ); + } self.r .field_idents(def_id) .map(|fields| fields.iter().map(|f| f.span).collect::>()) diff --git a/tests/ui/resolve/regression-struct-called-as-function-148919.rs b/tests/ui/resolve/regression-struct-called-as-function-148919.rs new file mode 100644 index 0000000000000..7358e1716c11a --- /dev/null +++ b/tests/ui/resolve/regression-struct-called-as-function-148919.rs @@ -0,0 +1,10 @@ +struct Bar {} + +impl Bar { + fn into_self(self) -> Bar { + Bar(self) + //~^ ERROR expected function, tuple struct or tuple variant, found struct `Bar` [E0423] + } +} + +fn main() {} diff --git a/tests/ui/resolve/regression-struct-called-as-function-148919.stderr b/tests/ui/resolve/regression-struct-called-as-function-148919.stderr new file mode 100644 index 0000000000000..d3e62b3a5a987 --- /dev/null +++ b/tests/ui/resolve/regression-struct-called-as-function-148919.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected function, tuple struct or tuple variant, found struct `Bar` + --> $DIR/regression-struct-called-as-function-148919.rs:5:9 + | +LL | Bar(self) + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0423`. From 3d3394200adbb6749b58cfe5238ea9a853a5fb68 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Thu, 20 Nov 2025 11:27:18 +0000 Subject: [PATCH 2/2] Use less brittle way for updating error message --- .../rustc_resolve/src/late/diagnostics.rs | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 74afae7996b24..da58c923695dd 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -823,8 +823,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } if let Some(Res::Def(DefKind::Struct, def_id)) = res { - if self.has_private_fields(def_id) { + let private_fields = self.has_private_fields(def_id); + let adjust_error_message = + private_fields && self.is_struct_with_fn_ctor(def_id); + if adjust_error_message { self.update_err_for_private_tuple_struct_fields(err, &source, def_id); + } + + if private_fields { err.note("constructor is not visible here due to private fields"); } } else { @@ -1644,15 +1650,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - fn has_tuple_fields(&mut self, def_id: DefId) -> bool { - // As we cannot name a field "0", this is an indictation - // that we are looking at a tuple struct - if let Some(fields) = self.r.field_idents(def_id) { - if let Some(first_field) = fields.get(0) { - return first_field.name.as_str() == "0"; - } - } - false + fn is_struct_with_fn_ctor(&mut self, def_id: DefId) -> bool { + def_id + .as_local() + .and_then(|local_id| self.r.struct_constructors.get(&local_id)) + .map(|struct_ctor| { + matches!( + struct_ctor.0, + def::Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), _) + ) + }) + .unwrap_or(false) } fn update_err_for_private_tuple_struct_fields( @@ -1677,18 +1685,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { span: call_span, .. })) => { - if self.has_tuple_fields(def_id) { - err.primary_message( - "cannot initialize a tuple struct which contains private fields", - ); - self.suggest_alternative_construction_methods( - def_id, - err, - path.span, - *call_span, - &args[..], - ); - } + err.primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + self.suggest_alternative_construction_methods( + def_id, + err, + path.span, + *call_span, + &args[..], + ); + self.r .field_idents(def_id) .map(|fields| fields.iter().map(|f| f.span).collect::>())