Skip to content

Commit

Permalink
Auto merge of #59550 - Centril:rollup, r=Centril
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Mar 30, 2019
2 parents 709b72e + 62a78c4 commit 6c49da4
Show file tree
Hide file tree
Showing 52 changed files with 722 additions and 281 deletions.
3 changes: 2 additions & 1 deletion src/ci/docker/armhf-gnu/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c
RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static

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

COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
Expand Down
11 changes: 6 additions & 5 deletions src/doc/unstable-book/src/language-features/non-exhaustive.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109]
------------------------

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

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

4 changes: 2 additions & 2 deletions src/libcore/iter/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,8 @@ pub fn once<T>(value: T) -> Once<T> {
Once { inner: Some(value).into_iter() }
}

/// An iterator that repeats elements of type `A` endlessly by
/// applying the provided closure `F: FnMut() -> A`.
/// An iterator that yields a single element of type `A` by
/// applying the provided closure `F: FnOnce() -> A`.
///
/// This `struct` is created by the [`once_with`] function.
/// See its documentation for more.
Expand Down
14 changes: 12 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
debug!("found non-exhaustive field list for {:?}", parent_did);
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
} else if let Some(variant_did) = variant_did {
if tcx.has_attr(variant_did, "non_exhaustive") {
debug!("found non-exhaustive field list for {:?}", variant_did);
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
}
}

VariantDef {
Expand Down Expand Up @@ -2146,6 +2151,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
}

flags |= match kind {
AdtKind::Enum => AdtFlags::IS_ENUM,
AdtKind::Union => AdtFlags::IS_UNION,
Expand Down Expand Up @@ -2299,21 +2305,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
self.variants.iter().all(|v| v.fields.is_empty())
}

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

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

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

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

// Returns `ty::VariantDef` if `def` refers to a struct,
// or variant or their constructors, panics otherwise.
/// Returns `ty::VariantDef` if `def` refers to a struct,
/// or variant or their constructors, panics otherwise.
pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
match def {
Def::Variant(did) => {
Expand Down
9 changes: 7 additions & 2 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,13 +643,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
}
};

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

Entry {
kind: EntryKind::Variant(self.lazy(&data)),
visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
visibility: self.lazy(&ctor_vis),
span: self.lazy(&tcx.def_span(def_id)),
attributes: LazySeq::empty(),
children: LazySeq::empty(),
Expand Down
9 changes: 0 additions & 9 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,6 @@ impl<'a> AstValidator<'a> {
}
}

fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
if has_non_exhaustive {
self.err_handler().span_err(variant.span,
"#[non_exhaustive] is not yet supported on variants");
}
}

fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
if let VisibilityKind::Inherited = vis.node {
return
Expand Down Expand Up @@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
ItemKind::Enum(ref def, _) => {
for variant in &def.variants {
self.invalid_non_exhaustive_attribute(variant);
for field in variant.node.data.fields() {
self.invalid_visibility(&field.vis, None);
}
Expand Down
21 changes: 20 additions & 1 deletion src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,26 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
match tcx.hir().get_by_hir_id(parent_hir_id) {
Node::Variant(..) => {
let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id);
return def_id_visibility(tcx, parent_did);
let (mut ctor_vis, mut span, mut descr) = def_id_visibility(
tcx, parent_did,
);

let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
let ctor_did = tcx.hir().local_def_id_from_hir_id(
vdata.ctor_hir_id().unwrap());
let variant = adt_def.variant_with_ctor_id(ctor_did);

if variant.is_field_list_non_exhaustive() &&
ctor_vis == ty::Visibility::Public
{
ctor_vis = ty::Visibility::Restricted(
DefId::local(CRATE_DEF_INDEX));
let attrs = tcx.get_attrs(variant.def_id);
span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span;
descr = "crate-visible";
}

return (ctor_vis, span, descr);
}
Node::Item(..) => {
let item = match tcx.hir().get_by_hir_id(parent_hir_id) {
Expand Down
10 changes: 9 additions & 1 deletion src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,14 @@ impl<'a> Resolver<'a> {
let def = Def::Variant(def_id);
self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));

// If the variant is marked as non_exhaustive then lower the visibility to within the
// crate.
let mut ctor_vis = vis;
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
if has_non_exhaustive && vis == ty::Visibility::Public {
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
}

// Define a constructor name in the value namespace.
// Braced variants, unlike structs, generate unusable names in
// value namespace, they are reserved for possible future use.
Expand All @@ -597,7 +605,7 @@ impl<'a> Resolver<'a> {
let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
let ctor_kind = CtorKind::from_ast(&variant.node.data);
let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion));
}

/// Constructs the reduced graph for one foreign item.
Expand Down
71 changes: 55 additions & 16 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
None
}

fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp: Span) -> bool {
let cm = self.sess().source_map();
let parent_id = self.tcx.hir().get_parent_node_by_hir_id(hir_id);
if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) {
// Account for fields
if let Node::Expr(hir::Expr {
node: hir::ExprKind::Struct(_, fields, ..), ..
}) = parent {
if let Ok(src) = cm.span_to_snippet(sp) {
for field in fields {
if field.ident.as_str() == src.as_str() && field.is_shorthand {
return true;
}
}
}
}
}
false
}

/// This function is used to determine potential "simple" improvements or users' errors and
/// provide them useful help. For example:
///
Expand Down Expand Up @@ -299,6 +319,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
return None;
}

let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(
expr.hir_id,
sp,
);

match (&expected.sty, &checked_ty.sty) {
(&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) {
(&ty::Str, &ty::Array(arr, _)) |
Expand Down Expand Up @@ -337,12 +362,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// bar(&x); // error, expected &mut
// ```
let ref_ty = match mutability {
hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
self.tcx.mk_region(ty::ReStatic),
checked_ty),
hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
self.tcx.mk_region(ty::ReStatic),
checked_ty),
hir::Mutability::MutMutable => {
self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
}
hir::Mutability::MutImmutable => {
self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
}
};
if self.can_coerce(ref_ty, expected) {
if let Ok(src) = cm.span_to_snippet(sp) {
Expand All @@ -363,14 +388,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(sugg) = self.can_use_as_ref(expr) {
return Some(sugg);
}
let field_name = if is_struct_pat_shorthand_field {
format!("{}: ", sugg_expr)
} else {
String::new()
};
return Some(match mutability {
hir::Mutability::MutMutable => {
(sp, "consider mutably borrowing here", format!("&mut {}",
sugg_expr))
}
hir::Mutability::MutImmutable => {
(sp, "consider borrowing here", format!("&{}", sugg_expr))
}
hir::Mutability::MutMutable => (
sp,
"consider mutably borrowing here",
format!("{}&mut {}", field_name, sugg_expr),
),
hir::Mutability::MutImmutable => (
sp,
"consider borrowing here",
format!("{}&{}", field_name, sugg_expr),
),
});
}
}
Expand Down Expand Up @@ -411,12 +444,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
checked,
sp) {
// do not suggest if the span comes from a macro (#52783)
if let (Ok(code),
true) = (cm.span_to_snippet(sp), sp == expr.span) {
if let (Ok(code), true) = (
cm.span_to_snippet(sp),
sp == expr.span,
) {
return Some((
sp,
"consider dereferencing the borrow",
format!("*{}", code),
if is_struct_pat_shorthand_field {
format!("{}: *{}", code, code)
} else {
format!("*{}", code)
},
));
}
}
Expand Down
13 changes: 7 additions & 6 deletions src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4341,11 +4341,12 @@ foo.method(); // Ok!
"##,

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

E0639: r##"
This error indicates that the struct or enum cannot be instantiated from
outside of the defining crate as it has been marked as `non_exhaustive` and as
such more fields/variants may be added in future that could cause adverse side
effects for this code.
This error indicates that the struct, enum or enum variant cannot be
instantiated from outside of the defining crate as it has been marked
as `non_exhaustive` and as such more fields/variants may be added in
future that could cause adverse side effects for this code.
It is recommended that you look for a `new` function or equivalent in the
crate's documentation.
Expand Down
3 changes: 3 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ impl Item {
pub fn is_enum(&self) -> bool {
self.type_() == ItemType::Enum
}
pub fn is_variant(&self) -> bool {
self.type_() == ItemType::Variant
}
pub fn is_associated_type(&self) -> bool {
self.type_() == ItemType::AssociatedType
}
Expand Down
15 changes: 14 additions & 1 deletion src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2604,7 +2604,15 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result {
if item.is_non_exhaustive() {
write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
if item.is_struct() {
"struct"
} else if item.is_enum() {
"enum"
} else if item.is_variant() {
"variant"
} else {
"type"
}
})?;

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

use crate::clean::{Variant, VariantKind};
if let clean::VariantItem(Variant {
Expand Down
Loading

0 comments on commit 6c49da4

Please sign in to comment.