Skip to content

Commit dd8d7a1

Browse files
Rollup merge of #81294 - pnkfelix:issue-81211-use-ufcs-in-derive-debug, r=oli-obk
Use ufcs in derive(Debug) Cc #81211. (Arguably this *is* the fix for it.)
2 parents b3f474b + 24149d7 commit dd8d7a1

File tree

6 files changed

+287
-19
lines changed

6 files changed

+287
-19
lines changed

compiler/rustc_builtin_macros/src/deriving/debug.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
88
use rustc_span::symbol::{sym, Ident};
99
use rustc_span::{Span, DUMMY_SP};
1010

11+
fn make_mut_borrow(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<Expr>) -> P<Expr> {
12+
cx.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Mut, expr))
13+
}
14+
1115
pub fn expand_deriving_debug(
1216
cx: &mut ExtCtxt<'_>,
1317
span: Span,
@@ -67,34 +71,34 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
6771
let fmt = substr.nonself_args[0].clone();
6872

6973
let mut stmts = Vec::with_capacity(fields.len() + 2);
74+
let fn_path_finish;
7075
match vdata {
7176
ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
7277
// tuple struct/"normal" variant
73-
let expr =
74-
cx.expr_method_call(span, fmt, Ident::new(sym::debug_tuple, span), vec![name]);
78+
let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
79+
let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
7580
stmts.push(cx.stmt_let(span, true, builder, expr));
7681

7782
for field in fields {
7883
// Use double indirection to make sure this works for unsized types
7984
let field = cx.expr_addr_of(field.span, field.self_.clone());
8085
let field = cx.expr_addr_of(field.span, field);
8186

82-
let expr = cx.expr_method_call(
83-
span,
84-
builder_expr.clone(),
85-
Ident::new(sym::field, span),
86-
vec![field],
87-
);
87+
let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::field]);
88+
let builder_recv = make_mut_borrow(cx, span, builder_expr.clone());
89+
let expr = cx.expr_call_global(span, fn_path_field, vec![builder_recv, field]);
8890

8991
// Use `let _ = expr;` to avoid triggering the
9092
// unused_results lint.
9193
stmts.push(stmt_let_underscore(cx, span, expr));
9294
}
95+
96+
fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::finish]);
9397
}
9498
ast::VariantData::Struct(..) => {
9599
// normal struct/struct variant
96-
let expr =
97-
cx.expr_method_call(span, fmt, Ident::new(sym::debug_struct, span), vec![name]);
100+
let fn_path_debug_struct = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_struct]);
101+
let expr = cx.expr_call_global(span, fn_path_debug_struct, vec![fmt, name]);
98102
stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
99103

100104
for field in fields {
@@ -104,20 +108,20 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
104108
);
105109

106110
// Use double indirection to make sure this works for unsized types
111+
let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::field]);
107112
let field = cx.expr_addr_of(field.span, field.self_.clone());
108113
let field = cx.expr_addr_of(field.span, field);
109-
let expr = cx.expr_method_call(
110-
span,
111-
builder_expr.clone(),
112-
Ident::new(sym::field, span),
113-
vec![name, field],
114-
);
114+
let builder_recv = make_mut_borrow(cx, span, builder_expr.clone());
115+
let expr =
116+
cx.expr_call_global(span, fn_path_field, vec![builder_recv, name, field]);
115117
stmts.push(stmt_let_underscore(cx, span, expr));
116118
}
119+
fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::finish]);
117120
}
118121
}
119122

120-
let expr = cx.expr_method_call(span, builder_expr, Ident::new(sym::finish, span), vec![]);
123+
let builder_recv = make_mut_borrow(cx, span, builder_expr);
124+
let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_recv]);
121125

122126
stmts.push(cx.stmt_expr(expr));
123127
let block = cx.block(span, stmts);

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ symbols! {
133133
Copy,
134134
Count,
135135
Debug,
136+
DebugStruct,
137+
DebugTuple,
136138
Decodable,
137139
Decoder,
138140
Default,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// run-pass
2+
#![allow(warnings)]
3+
4+
#[derive(Debug)]
5+
pub struct Bar { pub t: () }
6+
7+
impl<T> Access for T {}
8+
pub trait Access {
9+
fn field(&self, _: impl Sized, _: impl Sized) {
10+
panic!("got into Access::field");
11+
}
12+
13+
fn finish(&self) -> Result<(), std::fmt::Error> {
14+
panic!("got into Access::finish");
15+
}
16+
17+
fn debug_struct(&self, _: impl Sized, _: impl Sized) {
18+
panic!("got into Access::debug_struct");
19+
}
20+
}
21+
22+
impl<T> MutAccess for T {}
23+
pub trait MutAccess {
24+
fn field(&mut self, _: impl Sized, _: impl Sized) {
25+
panic!("got into MutAccess::field");
26+
}
27+
28+
fn finish(&mut self) -> Result<(), std::fmt::Error> {
29+
panic!("got into MutAccess::finish");
30+
}
31+
32+
fn debug_struct(&mut self, _: impl Sized, _: impl Sized) {
33+
panic!("got into MutAccess::debug_struct");
34+
}
35+
}
36+
37+
fn main() {
38+
let bar = Bar { t: () };
39+
assert_eq!("Bar { t: () }", format!("{:?}", bar));
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// run-pass
2+
#![allow(warnings)]
3+
4+
#[derive(Debug)]
5+
pub struct Foo<T>(pub T);
6+
7+
use std::fmt;
8+
9+
impl<T> Field for T {}
10+
impl<T> Finish for T {}
11+
impl Dt for &mut fmt::Formatter<'_> {}
12+
13+
pub trait Field {
14+
fn field(&self, _: impl Sized) {
15+
panic!("got into field");
16+
}
17+
}
18+
pub trait Finish {
19+
fn finish(&self) -> Result<(), std::fmt::Error> {
20+
panic!("got into finish");
21+
}
22+
}
23+
pub trait Dt {
24+
fn debug_tuple(&self, _: &str) {
25+
panic!("got into debug_tuple");
26+
}
27+
}
28+
29+
fn main() {
30+
let foo = Foo(());
31+
assert_eq!("Foo(())", format!("{:?}", foo));
32+
}
+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// ignore-tidy-linelength
2+
3+
// run-pass
4+
5+
// There are five cfg's below. I explored the set of all non-empty combinations
6+
// of the below five cfg's, which is 2^5 - 1 = 31 combinations.
7+
//
8+
// Of the 31, 11 resulted in ambiguous method resolutions; while it may be good
9+
// to have a test for all of the eleven variations of that error, I am not sure
10+
// this particular test is the best way to encode it. So they are skipped in
11+
// this revisions list (but not in the expansion mapping the binary encoding to
12+
// the corresponding cfg flags).
13+
//
14+
// Notable, here are the cases that will be incompatible if something does not override them first:
15+
// {bar_for_foo, valbar_for_et_foo}: these are higher precedent than the `&mut self` method on `Foo`, and so no case matching bx1x1x is included.
16+
// {mutbar_for_foo, valbar_for_etmut_foo} (which are lower precedent than the inherent `&mut self` method on `Foo`; e.g. b10101 *is* included.
17+
18+
// revisions: b00001 b00010 b00011 b00100 b00101 b00110 b00111 b01000 b01001 b01100 b01101 b10000 b10001 b10010 b10011 b10101 b10111 b11000 b11001 b11101
19+
20+
//[b00001]compile-flags: --cfg inherent_mut
21+
//[b00010]compile-flags: --cfg bar_for_foo
22+
//[b00011]compile-flags: --cfg inherent_mut --cfg bar_for_foo
23+
//[b00100]compile-flags: --cfg mutbar_for_foo
24+
//[b00101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo
25+
//[b00110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo
26+
//[b00111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo
27+
//[b01000]compile-flags: --cfg valbar_for_et_foo
28+
//[b01001]compile-flags: --cfg inherent_mut --cfg valbar_for_et_foo
29+
//[b01010]compile-flags: --cfg bar_for_foo --cfg valbar_for_et_foo
30+
//[b01011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_et_foo
31+
//[b01100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_et_foo
32+
//[b01101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_et_foo
33+
//[b01110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo
34+
//[b01111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo
35+
//[b10000]compile-flags: --cfg valbar_for_etmut_foo
36+
//[b10001]compile-flags: --cfg inherent_mut --cfg valbar_for_etmut_foo
37+
//[b10010]compile-flags: --cfg bar_for_foo --cfg valbar_for_etmut_foo
38+
//[b10011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_etmut_foo
39+
//[b10100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
40+
//[b10101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
41+
//[b10110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
42+
//[b10111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
43+
//[b11000]compile-flags: --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
44+
//[b11001]compile-flags: --cfg inherent_mut --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
45+
//[b11010]compile-flags: --cfg bar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
46+
//[b11011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
47+
//[b11100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
48+
//[b11101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
49+
//[b11110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
50+
//[b11111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
51+
52+
struct Foo {}
53+
54+
type S = &'static str;
55+
56+
trait Bar {
57+
fn bar(&self, _: &str) -> S;
58+
}
59+
60+
trait MutBar {
61+
fn bar(&mut self, _: &str) -> S;
62+
}
63+
64+
trait ValBar {
65+
fn bar(self, _: &str) -> S;
66+
}
67+
68+
#[cfg(inherent_mut)]
69+
impl Foo {
70+
fn bar(&mut self, _: &str) -> S {
71+
"In struct impl!"
72+
}
73+
}
74+
75+
#[cfg(bar_for_foo)]
76+
impl Bar for Foo {
77+
fn bar(&self, _: &str) -> S {
78+
"In trait &self impl!"
79+
}
80+
}
81+
82+
#[cfg(mutbar_for_foo)]
83+
impl MutBar for Foo {
84+
fn bar(&mut self, _: &str) -> S {
85+
"In trait &mut self impl!"
86+
}
87+
}
88+
89+
#[cfg(valbar_for_et_foo)]
90+
impl ValBar for &Foo {
91+
fn bar(self, _: &str) -> S {
92+
"In trait self impl for &Foo!"
93+
}
94+
}
95+
96+
#[cfg(valbar_for_etmut_foo)]
97+
impl ValBar for &mut Foo {
98+
fn bar(self, _: &str) -> S {
99+
"In trait self impl for &mut Foo!"
100+
}
101+
}
102+
103+
fn main() {
104+
#![allow(unused_mut)] // some of the impls above will want it.
105+
106+
#![allow(unreachable_patterns)] // the cfg-coding pattern below generates unreachable patterns.
107+
108+
{
109+
macro_rules! all_variants_on_value {
110+
($e:expr) => {
111+
match $e {
112+
#[cfg(bar_for_foo)]
113+
x => assert_eq!(x, "In trait &self impl!"),
114+
115+
#[cfg(valbar_for_et_foo)]
116+
x => assert_eq!(x, "In trait self impl for &Foo!"),
117+
118+
#[cfg(inherent_mut)]
119+
x => assert_eq!(x, "In struct impl!"),
120+
121+
#[cfg(mutbar_for_foo)]
122+
x => assert_eq!(x, "In trait &mut self impl!"),
123+
124+
#[cfg(valbar_for_etmut_foo)]
125+
x => assert_eq!(x, "In trait self impl for &mut Foo!"),
126+
}
127+
}
128+
}
129+
130+
let mut f = Foo {};
131+
all_variants_on_value!(f.bar("f.bar"));
132+
133+
let f_mr = &mut Foo {};
134+
all_variants_on_value!((*f_mr).bar("(*f_mr).bar"));
135+
}
136+
137+
// This is sort of interesting: `&mut Foo` ends up with a significantly
138+
// different resolution order than what was devised above. Presumably this
139+
// is because we can get to a `&self` method by first a deref of the given
140+
// `&mut Foo` and then an autoref, and that is a longer path than a mere
141+
// auto-ref of a `Foo`.
142+
143+
{
144+
let f_mr = &mut Foo {};
145+
146+
match f_mr.bar("f_mr.bar") {
147+
#[cfg(inherent_mut)]
148+
x => assert_eq!(x, "In struct impl!"),
149+
150+
#[cfg(valbar_for_etmut_foo)]
151+
x => assert_eq!(x, "In trait self impl for &mut Foo!"),
152+
153+
#[cfg(mutbar_for_foo)]
154+
x => assert_eq!(x, "In trait &mut self impl!"),
155+
156+
#[cfg(valbar_for_et_foo)]
157+
x => assert_eq!(x, "In trait self impl for &Foo!"),
158+
159+
#[cfg(bar_for_foo)]
160+
x => assert_eq!(x, "In trait &self impl!"),
161+
}
162+
}
163+
164+
165+
// Note that this isn't actually testing a resolution order; if both of these are
166+
// enabled, it yields an ambiguous method resolution error. The test tries to embed
167+
// that fact by testing *both* orders (and so the only way that can be right is if
168+
// they are not actually compatible).
169+
#[cfg(any(bar_for_foo, valbar_for_et_foo))]
170+
{
171+
let f_r = &Foo {};
172+
173+
match f_r.bar("f_r.bar") {
174+
#[cfg(bar_for_foo)]
175+
x => assert_eq!(x, "In trait &self impl!"),
176+
177+
#[cfg(valbar_for_et_foo)]
178+
x => assert_eq!(x, "In trait self impl for &Foo!"),
179+
}
180+
181+
match f_r.bar("f_r.bar") {
182+
#[cfg(valbar_for_et_foo)]
183+
x => assert_eq!(x, "In trait self impl for &Foo!"),
184+
185+
#[cfg(bar_for_foo)]
186+
x => assert_eq!(x, "In trait &self impl!"),
187+
}
188+
}
189+
190+
}

src/test/ui/panic-handler/weak-lang-item.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ help: you can use `as` to change the binding name of the import
1010
LL | extern crate core as other_core;
1111
|
1212

13-
error: language item required, but not found: `eh_personality`
14-
1513
error: `#[panic_handler]` function required, but not found
1614

15+
error: language item required, but not found: `eh_personality`
16+
1717
error: aborting due to 3 previous errors
1818

1919
For more information about this error, try `rustc --explain E0259`.

0 commit comments

Comments
 (0)