Skip to content

Commit 6c49da4

Browse files
committed
Auto merge of #59550 - Centril:rollup, r=Centril
Rollup of 10 pull requests Successful merges: - #59376 (RFC 2008: Enum Variants) - #59453 (Recover from parse error in tuple syntax) - #59455 (Account for short-hand field syntax when suggesting borrow) - #59499 (Fix broken download link in the armhf-gnu image) - #59512 (implement `AsRawFd` for stdio locks) - #59525 (Whitelist some rustc attrs) - #59528 (Improve the dbg! macro docs ) - #59532 (In doc examples, don't ignore read/write results) - #59534 (rustdoc: collapse blanket impls in the same way as normal impls) - #59537 (Fix OnceWith docstring.) Failed merges: r? @ghost
2 parents 709b72e + 62a78c4 commit 6c49da4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+722
-281
lines changed

src/ci/docker/armhf-gnu/Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c
7171
RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
7272

7373
# TODO: What is this?!
74-
RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb
74+
# Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb
75+
RUN curl -O https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/vexpress-v2p-ca15-tc1.dtb
7576

7677
COPY scripts/sccache.sh /scripts/
7778
RUN sh /scripts/sccache.sh

src/doc/unstable-book/src/language-features/non-exhaustive.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109]
77
------------------------
88

99
The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute
10-
on structs and enums. When applied within a crate, users of the crate will need
11-
to use the `_` pattern when matching enums and use the `..` pattern when
12-
matching structs. Structs marked as `non_exhaustive` will not be able to be
13-
created normally outside of the defining crate. This is demonstrated below:
10+
on structs, enums and enum variants. When applied within a crate, users of the
11+
crate will need to use the `_` pattern when matching enums and use the `..`
12+
pattern when matching structs. Enum variants cannot be matched against.
13+
Structs and enum variants marked as `non_exhaustive` will not be able to
14+
be created normally outside of the defining crate. This is demonstrated
15+
below:
1416

1517
```rust,ignore (pseudo-Rust)
1618
use std::error::Error as StdError;
@@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 };
7274
// when marked non_exhaustive.
7375
let &Config { window_width, window_height, .. } = config;
7476
```
75-

src/libcore/iter/sources.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,8 @@ pub fn once<T>(value: T) -> Once<T> {
375375
Once { inner: Some(value).into_iter() }
376376
}
377377

378-
/// An iterator that repeats elements of type `A` endlessly by
379-
/// applying the provided closure `F: FnMut() -> A`.
378+
/// An iterator that yields a single element of type `A` by
379+
/// applying the provided closure `F: FnOnce() -> A`.
380380
///
381381
/// This `struct` is created by the [`once_with`] function.
382382
/// See its documentation for more.

src/librustc/ty/mod.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
18691869
if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
18701870
debug!("found non-exhaustive field list for {:?}", parent_did);
18711871
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
1872+
} else if let Some(variant_did) = variant_did {
1873+
if tcx.has_attr(variant_did, "non_exhaustive") {
1874+
debug!("found non-exhaustive field list for {:?}", variant_did);
1875+
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
1876+
}
18721877
}
18731878

18741879
VariantDef {
@@ -2146,6 +2151,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
21462151
debug!("found non-exhaustive variant list for {:?}", did);
21472152
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
21482153
}
2154+
21492155
flags |= match kind {
21502156
AdtKind::Enum => AdtFlags::IS_ENUM,
21512157
AdtKind::Union => AdtFlags::IS_UNION,
@@ -2299,21 +2305,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
22992305
self.variants.iter().all(|v| v.fields.is_empty())
23002306
}
23012307

2308+
/// Return a `VariantDef` given a variant id.
23022309
pub fn variant_with_id(&self, vid: DefId) -> &VariantDef {
23032310
self.variants.iter().find(|v| v.def_id == vid)
23042311
.expect("variant_with_id: unknown variant")
23052312
}
23062313

2314+
/// Return a `VariantDef` given a constructor id.
23072315
pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef {
23082316
self.variants.iter().find(|v| v.ctor_def_id == Some(cid))
23092317
.expect("variant_with_ctor_id: unknown variant")
23102318
}
23112319

2320+
/// Return the index of `VariantDef` given a variant id.
23122321
pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx {
23132322
self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid)
23142323
.expect("variant_index_with_id: unknown variant").0
23152324
}
23162325

2326+
/// Return the index of `VariantDef` given a constructor id.
23172327
pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx {
23182328
self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid))
23192329
.expect("variant_index_with_ctor_id: unknown variant").0
@@ -2930,8 +2940,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
29302940
}
29312941
}
29322942

2933-
// Returns `ty::VariantDef` if `def` refers to a struct,
2934-
// or variant or their constructors, panics otherwise.
2943+
/// Returns `ty::VariantDef` if `def` refers to a struct,
2944+
/// or variant or their constructors, panics otherwise.
29352945
pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
29362946
match def {
29372947
Def::Variant(did) => {

src/librustc_metadata/encoder.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -643,13 +643,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
643643
}
644644
};
645645

646-
// Variant constructors have the same visibility as the parent enums.
646+
// Variant constructors have the same visibility as the parent enums, unless marked as
647+
// non-exhaustive, in which case they are lowered to `pub(crate)`.
647648
let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
648649
let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis;
650+
let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx);
651+
if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public {
652+
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
653+
}
649654

650655
Entry {
651656
kind: EntryKind::Variant(self.lazy(&data)),
652-
visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
657+
visibility: self.lazy(&ctor_vis),
653658
span: self.lazy(&tcx.def_span(def_id)),
654659
attributes: LazySeq::empty(),
655660
children: LazySeq::empty(),

src/librustc_passes/ast_validation.rs

-9
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,6 @@ impl<'a> AstValidator<'a> {
192192
}
193193
}
194194

195-
fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
196-
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
197-
if has_non_exhaustive {
198-
self.err_handler().span_err(variant.span,
199-
"#[non_exhaustive] is not yet supported on variants");
200-
}
201-
}
202-
203195
fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
204196
if let VisibilityKind::Inherited = vis.node {
205197
return
@@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
608600
}
609601
ItemKind::Enum(ref def, _) => {
610602
for variant in &def.variants {
611-
self.invalid_non_exhaustive_attribute(variant);
612603
for field in variant.node.data.fields() {
613604
self.invalid_visibility(&field.vis, None);
614605
}

src/librustc_privacy/lib.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,26 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
244244
match tcx.hir().get_by_hir_id(parent_hir_id) {
245245
Node::Variant(..) => {
246246
let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id);
247-
return def_id_visibility(tcx, parent_did);
247+
let (mut ctor_vis, mut span, mut descr) = def_id_visibility(
248+
tcx, parent_did,
249+
);
250+
251+
let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
252+
let ctor_did = tcx.hir().local_def_id_from_hir_id(
253+
vdata.ctor_hir_id().unwrap());
254+
let variant = adt_def.variant_with_ctor_id(ctor_did);
255+
256+
if variant.is_field_list_non_exhaustive() &&
257+
ctor_vis == ty::Visibility::Public
258+
{
259+
ctor_vis = ty::Visibility::Restricted(
260+
DefId::local(CRATE_DEF_INDEX));
261+
let attrs = tcx.get_attrs(variant.def_id);
262+
span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span;
263+
descr = "crate-visible";
264+
}
265+
266+
return (ctor_vis, span, descr);
248267
}
249268
Node::Item(..) => {
250269
let item = match tcx.hir().get_by_hir_id(parent_hir_id) {

src/librustc_resolve/build_reduced_graph.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,14 @@ impl<'a> Resolver<'a> {
588588
let def = Def::Variant(def_id);
589589
self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));
590590

591+
// If the variant is marked as non_exhaustive then lower the visibility to within the
592+
// crate.
593+
let mut ctor_vis = vis;
594+
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
595+
if has_non_exhaustive && vis == ty::Visibility::Public {
596+
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
597+
}
598+
591599
// Define a constructor name in the value namespace.
592600
// Braced variants, unlike structs, generate unusable names in
593601
// value namespace, they are reserved for possible future use.
@@ -597,7 +605,7 @@ impl<'a> Resolver<'a> {
597605
let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
598606
let ctor_kind = CtorKind::from_ast(&variant.node.data);
599607
let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
600-
self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
608+
self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion));
601609
}
602610

603611
/// Constructs the reduced graph for one foreign item.

src/librustc_typeck/check/demand.rs

+55-16
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
270270
None
271271
}
272272

273+
fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp: Span) -> bool {
274+
let cm = self.sess().source_map();
275+
let parent_id = self.tcx.hir().get_parent_node_by_hir_id(hir_id);
276+
if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) {
277+
// Account for fields
278+
if let Node::Expr(hir::Expr {
279+
node: hir::ExprKind::Struct(_, fields, ..), ..
280+
}) = parent {
281+
if let Ok(src) = cm.span_to_snippet(sp) {
282+
for field in fields {
283+
if field.ident.as_str() == src.as_str() && field.is_shorthand {
284+
return true;
285+
}
286+
}
287+
}
288+
}
289+
}
290+
false
291+
}
292+
273293
/// This function is used to determine potential "simple" improvements or users' errors and
274294
/// provide them useful help. For example:
275295
///
@@ -299,6 +319,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
299319
return None;
300320
}
301321

322+
let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(
323+
expr.hir_id,
324+
sp,
325+
);
326+
302327
match (&expected.sty, &checked_ty.sty) {
303328
(&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) {
304329
(&ty::Str, &ty::Array(arr, _)) |
@@ -337,12 +362,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
337362
// bar(&x); // error, expected &mut
338363
// ```
339364
let ref_ty = match mutability {
340-
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
341-
self.tcx.mk_region(ty::ReStatic),
342-
checked_ty),
343-
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
344-
self.tcx.mk_region(ty::ReStatic),
345-
checked_ty),
365+
hir::Mutability::MutMutable => {
366+
self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
367+
}
368+
hir::Mutability::MutImmutable => {
369+
self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
370+
}
346371
};
347372
if self.can_coerce(ref_ty, expected) {
348373
if let Ok(src) = cm.span_to_snippet(sp) {
@@ -363,14 +388,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
363388
if let Some(sugg) = self.can_use_as_ref(expr) {
364389
return Some(sugg);
365390
}
391+
let field_name = if is_struct_pat_shorthand_field {
392+
format!("{}: ", sugg_expr)
393+
} else {
394+
String::new()
395+
};
366396
return Some(match mutability {
367-
hir::Mutability::MutMutable => {
368-
(sp, "consider mutably borrowing here", format!("&mut {}",
369-
sugg_expr))
370-
}
371-
hir::Mutability::MutImmutable => {
372-
(sp, "consider borrowing here", format!("&{}", sugg_expr))
373-
}
397+
hir::Mutability::MutMutable => (
398+
sp,
399+
"consider mutably borrowing here",
400+
format!("{}&mut {}", field_name, sugg_expr),
401+
),
402+
hir::Mutability::MutImmutable => (
403+
sp,
404+
"consider borrowing here",
405+
format!("{}&{}", field_name, sugg_expr),
406+
),
374407
});
375408
}
376409
}
@@ -411,12 +444,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
411444
checked,
412445
sp) {
413446
// do not suggest if the span comes from a macro (#52783)
414-
if let (Ok(code),
415-
true) = (cm.span_to_snippet(sp), sp == expr.span) {
447+
if let (Ok(code), true) = (
448+
cm.span_to_snippet(sp),
449+
sp == expr.span,
450+
) {
416451
return Some((
417452
sp,
418453
"consider dereferencing the borrow",
419-
format!("*{}", code),
454+
if is_struct_pat_shorthand_field {
455+
format!("{}: *{}", code, code)
456+
} else {
457+
format!("*{}", code)
458+
},
420459
));
421460
}
422461
}

src/librustc_typeck/diagnostics.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -4341,11 +4341,12 @@ foo.method(); // Ok!
43414341
"##,
43424342

43434343
E0638: r##"
4344-
This error indicates that the struct or enum must be matched non-exhaustively
4345-
as it has been marked as `non_exhaustive`.
4344+
This error indicates that the struct, enum or enum variant must be matched
4345+
non-exhaustively as it has been marked as `non_exhaustive`.
43464346
43474347
When applied within a crate, downstream users of the crate will need to use the
43484348
`_` pattern when matching enums and use the `..` pattern when matching structs.
4349+
Downstream crates cannot match against non-exhaustive enum variants.
43494350
43504351
For example, in the below example, since the enum is marked as
43514352
`non_exhaustive`, it is required that downstream crates match non-exhaustively
@@ -4390,10 +4391,10 @@ Similarly, for structs, match with `..` to avoid this error.
43904391
"##,
43914392

43924393
E0639: r##"
4393-
This error indicates that the struct or enum cannot be instantiated from
4394-
outside of the defining crate as it has been marked as `non_exhaustive` and as
4395-
such more fields/variants may be added in future that could cause adverse side
4396-
effects for this code.
4394+
This error indicates that the struct, enum or enum variant cannot be
4395+
instantiated from outside of the defining crate as it has been marked
4396+
as `non_exhaustive` and as such more fields/variants may be added in
4397+
future that could cause adverse side effects for this code.
43974398
43984399
It is recommended that you look for a `new` function or equivalent in the
43994400
crate's documentation.

src/librustdoc/clean/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,9 @@ impl Item {
421421
pub fn is_enum(&self) -> bool {
422422
self.type_() == ItemType::Enum
423423
}
424+
pub fn is_variant(&self) -> bool {
425+
self.type_() == ItemType::Variant
426+
}
424427
pub fn is_associated_type(&self) -> bool {
425428
self.type_() == ItemType::AssociatedType
426429
}

src/librustdoc/html/render.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -2604,7 +2604,15 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
26042604
fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result {
26052605
if item.is_non_exhaustive() {
26062606
write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
2607-
if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
2607+
if item.is_struct() {
2608+
"struct"
2609+
} else if item.is_enum() {
2610+
"enum"
2611+
} else if item.is_variant() {
2612+
"variant"
2613+
} else {
2614+
"type"
2615+
}
26082616
})?;
26092617

26102618
if item.is_struct() {
@@ -2617,6 +2625,10 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm
26172625
write!(w, "Non-exhaustive enums could have additional variants added in future. \
26182626
Therefore, when matching against variants of non-exhaustive enums, an \
26192627
extra wildcard arm must be added to account for any future variants.")?;
2628+
} else if item.is_variant() {
2629+
write!(w, "Non-exhaustive enum variants could have additional fields added in future. \
2630+
Therefore, non-exhaustive enum variants cannot be constructed in external \
2631+
crates and cannot be matched against.")?;
26202632
} else {
26212633
write!(w, "This type will require a wildcard arm in any match statements or \
26222634
constructors.")?;
@@ -3679,6 +3691,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
36793691
}
36803692
write!(w, "</code></span>")?;
36813693
document(w, cx, variant)?;
3694+
document_non_exhaustive(w, variant)?;
36823695

36833696
use crate::clean::{Variant, VariantKind};
36843697
if let clean::VariantItem(Variant {

0 commit comments

Comments
 (0)