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
This commit is contained in:
commit
6c49da4544
52 changed files with 722 additions and 281 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 };
|
|||
// when marked non_exhaustive.
|
||||
let &Config { window_width, window_height, .. } = config;
|
||||
```
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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) => {
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
///
|
||||
|
@ -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, _)) |
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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.")?;
|
||||
|
@ -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 {
|
||||
|
|
|
@ -2071,6 +2071,14 @@ if (!DOMTokenList.prototype.remove) {
|
|||
collapser(e, collapse);
|
||||
});
|
||||
}
|
||||
|
||||
var blanket_list = document.getElementById("blanket-implementations-list");
|
||||
|
||||
if (blanket_list !== null) {
|
||||
onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) {
|
||||
collapser(e, collapse);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2263,6 +2271,8 @@ if (!DOMTokenList.prototype.remove) {
|
|||
otherMessage += "struct";
|
||||
} else if (hasClass(e, "non-exhaustive-enum")) {
|
||||
otherMessage += "enum";
|
||||
} else if (hasClass(e, "non-exhaustive-variant")) {
|
||||
otherMessage += "enum variant";
|
||||
} else if (hasClass(e, "non-exhaustive-type")) {
|
||||
otherMessage += "type";
|
||||
}
|
||||
|
@ -2280,6 +2290,9 @@ if (!DOMTokenList.prototype.remove) {
|
|||
if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
|
||||
collapseDocs(e.previousSibling.childNodes[0], "toggle");
|
||||
}
|
||||
if (hasClass(e, "non-exhaustive") === true) {
|
||||
collapseDocs(e.previousSibling.childNodes[0], "toggle");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
//! let mut buffer = [0; 10];
|
||||
//!
|
||||
//! // read up to 10 bytes
|
||||
//! f.read(&mut buffer)?;
|
||||
//! let n = f.read(&mut buffer)?;
|
||||
//!
|
||||
//! println!("The bytes: {:?}", buffer);
|
||||
//! println!("The bytes: {:?}", &buffer[..n]);
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
@ -56,9 +56,9 @@
|
|||
//! f.seek(SeekFrom::End(-10))?;
|
||||
//!
|
||||
//! // read up to 10 bytes
|
||||
//! f.read(&mut buffer)?;
|
||||
//! let n = f.read(&mut buffer)?;
|
||||
//!
|
||||
//! println!("The bytes: {:?}", buffer);
|
||||
//! println!("The bytes: {:?}", &buffer[..n]);
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
@ -537,7 +537,9 @@ pub trait Read {
|
|||
/// let mut buffer = [0; 10];
|
||||
///
|
||||
/// // read up to 10 bytes
|
||||
/// f.read(&mut buffer[..])?;
|
||||
/// let n = f.read(&mut buffer[..])?;
|
||||
///
|
||||
/// println!("The bytes: {:?}", &buffer[..n]);
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -1062,12 +1064,23 @@ impl Initializer {
|
|||
/// use std::fs::File;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let data = b"some bytes";
|
||||
///
|
||||
/// let mut pos = 0;
|
||||
/// let mut buffer = File::create("foo.txt")?;
|
||||
///
|
||||
/// buffer.write(b"some bytes")?;
|
||||
/// while pos < data.len() {
|
||||
/// let bytes_written = buffer.write(&data[pos..])?;
|
||||
/// pos += bytes_written;
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The trait also provides convenience methods like [`write_all`], which calls
|
||||
/// `write` in a loop until its entire input has been written.
|
||||
///
|
||||
/// [`write_all`]: #method.write_all
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(spotlight)]
|
||||
pub trait Write {
|
||||
|
|
|
@ -233,10 +233,14 @@ macro_rules! eprintln {
|
|||
/// to give up ownership, you can instead borrow with `dbg!(&expr)`
|
||||
/// for some expression `expr`.
|
||||
///
|
||||
/// The `dbg!` macro works exactly the same in release builds.
|
||||
/// This is useful when debugging issues that only occur in release
|
||||
/// builds or when debugging in release mode is significantly faster.
|
||||
///
|
||||
/// Note that the macro is intended as a debugging tool and therefore you
|
||||
/// should avoid having uses of it in version control for longer periods.
|
||||
/// Use cases involving debug output that should be added to version control
|
||||
/// may be better served by macros such as `debug!` from the `log` crate.
|
||||
/// are better served by macros such as [`debug!`][debug-log] from the [`log`][log] crate.
|
||||
///
|
||||
/// # Stability
|
||||
///
|
||||
|
@ -311,6 +315,8 @@ macro_rules! eprintln {
|
|||
/// file and line whenever it's reached.
|
||||
///
|
||||
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
|
||||
/// [debug-log]: https://docs.rs/log/*/log/macro.debug.html
|
||||
/// [log]: https://docs.rs/log/
|
||||
#[macro_export]
|
||||
#[stable(feature = "dbg_macro", since = "1.32.0")]
|
||||
macro_rules! dbg {
|
||||
|
|
|
@ -115,6 +115,21 @@ impl AsRawFd for io::Stderr {
|
|||
fn as_raw_fd(&self) -> RawFd { 2 }
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawFd for io::StdinLock<'a> {
|
||||
fn as_raw_fd(&self) -> RawFd { 0 }
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawFd for io::StdoutLock<'a> {
|
||||
fn as_raw_fd(&self) -> RawFd { 1 }
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawFd for io::StderrLock<'a> {
|
||||
fn as_raw_fd(&self) -> RawFd { 2 }
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl FromRawFd for net::TcpStream {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
|
||||
|
|
|
@ -95,3 +95,18 @@ impl AsRawFd for io::Stdout {
|
|||
impl AsRawFd for io::Stderr {
|
||||
fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawFd for io::StdinLock<'a> {
|
||||
fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawFd for io::StdoutLock<'a> {
|
||||
fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawFd for io::StderrLock<'a> {
|
||||
fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
|
||||
}
|
||||
|
|
|
@ -83,6 +83,27 @@ impl AsRawHandle for io::Stderr {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawHandle for io::StdinLock<'a> {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawHandle for io::StdoutLock<'a> {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
|
||||
impl<'a> AsRawHandle for io::StderrLock<'a> {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl FromRawHandle for fs::File {
|
||||
unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
|
||||
|
|
|
@ -906,7 +906,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
|
|||
not currently handle destructors.",
|
||||
cfg_fn!(thread_local))),
|
||||
|
||||
("rustc_on_unimplemented", Normal, template!(List:
|
||||
("rustc_on_unimplemented", Whitelisted, template!(List:
|
||||
r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
|
||||
NameValueStr: "message"),
|
||||
Gated(Stability::Unstable,
|
||||
|
@ -962,6 +962,20 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
|
|||
is just used for rustc unit tests \
|
||||
and will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_layout_scalar_valid_range_start", Whitelisted, template!(List: "value"),
|
||||
Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"the `#[rustc_layout_scalar_valid_range_start]` attribute \
|
||||
is just used to enable niche optimizations in libcore \
|
||||
and will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_layout_scalar_valid_range_end", Whitelisted, template!(List: "value"),
|
||||
Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"the `#[rustc_layout_scalar_valid_range_end]` attribute \
|
||||
is just used to enable niche optimizations in libcore \
|
||||
and will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_regions", Normal, template!(Word), Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"the `#[rustc_regions]` attribute \
|
||||
|
|
|
@ -2626,7 +2626,13 @@ impl<'a> Parser<'a> {
|
|||
let mut trailing_comma = false;
|
||||
let mut recovered = false;
|
||||
while self.token != token::CloseDelim(token::Paren) {
|
||||
es.push(self.parse_expr()?);
|
||||
es.push(match self.parse_expr() {
|
||||
Ok(es) => es,
|
||||
Err(err) => {
|
||||
// recover from parse error in tuple list
|
||||
return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err)));
|
||||
}
|
||||
});
|
||||
recovered = self.expect_one_of(
|
||||
&[],
|
||||
&[token::Comma, token::CloseDelim(token::Paren)],
|
||||
|
@ -3237,36 +3243,54 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
if self.expr_is_complete(&e) { break; }
|
||||
match self.token {
|
||||
// expr(...)
|
||||
token::OpenDelim(token::Paren) => {
|
||||
let es = self.parse_unspanned_seq(
|
||||
&token::OpenDelim(token::Paren),
|
||||
&token::CloseDelim(token::Paren),
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
|p| Ok(p.parse_expr()?)
|
||||
)?;
|
||||
hi = self.prev_span;
|
||||
// expr(...)
|
||||
token::OpenDelim(token::Paren) => {
|
||||
let seq = self.parse_unspanned_seq(
|
||||
&token::OpenDelim(token::Paren),
|
||||
&token::CloseDelim(token::Paren),
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
|p| Ok(p.parse_expr()?)
|
||||
).map(|es| {
|
||||
let nd = self.mk_call(e, es);
|
||||
let hi = self.prev_span;
|
||||
self.mk_expr(lo.to(hi), nd, ThinVec::new())
|
||||
});
|
||||
e = self.recover_seq_parse_error(token::Paren, lo, seq);
|
||||
}
|
||||
|
||||
let nd = self.mk_call(e, es);
|
||||
e = self.mk_expr(lo.to(hi), nd, ThinVec::new());
|
||||
}
|
||||
|
||||
// expr[...]
|
||||
// Could be either an index expression or a slicing expression.
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
self.bump();
|
||||
let ix = self.parse_expr()?;
|
||||
hi = self.span;
|
||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||
let index = self.mk_index(e, ix);
|
||||
e = self.mk_expr(lo.to(hi), index, ThinVec::new())
|
||||
}
|
||||
_ => return Ok(e)
|
||||
// expr[...]
|
||||
// Could be either an index expression or a slicing expression.
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
self.bump();
|
||||
let ix = self.parse_expr()?;
|
||||
hi = self.span;
|
||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||
let index = self.mk_index(e, ix);
|
||||
e = self.mk_expr(lo.to(hi), index, ThinVec::new())
|
||||
}
|
||||
_ => return Ok(e)
|
||||
}
|
||||
}
|
||||
return Ok(e);
|
||||
}
|
||||
|
||||
fn recover_seq_parse_error(
|
||||
&mut self,
|
||||
delim: token::DelimToken,
|
||||
lo: Span,
|
||||
result: PResult<'a, P<Expr>>,
|
||||
) -> P<Expr> {
|
||||
match result {
|
||||
Ok(x) => x,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
// recover from parse error
|
||||
self.consume_block(delim);
|
||||
self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn process_potential_macro_variable(&mut self) {
|
||||
let (token, span) = match self.token {
|
||||
token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
|
||||
|
@ -4253,7 +4277,14 @@ impl<'a> Parser<'a> {
|
|||
// Trailing commas are significant because (p) and (p,) are different patterns.
|
||||
fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
|
||||
self.expect(&token::OpenDelim(token::Paren))?;
|
||||
let result = self.parse_pat_list()?;
|
||||
let result = match self.parse_pat_list() {
|
||||
Ok(result) => result,
|
||||
Err(mut err) => { // recover from parse error in tuple pattern list
|
||||
err.emit();
|
||||
self.consume_block(token::Paren);
|
||||
return Ok((vec![], Some(0), false));
|
||||
}
|
||||
};
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
Ok(result)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// We should not see the unused_attributes lint fire for
|
||||
// rustc_on_unimplemented, but with this bug we are seeing it fire (on
|
||||
// subsequent runs) if incremental compilation is enabled.
|
||||
|
||||
// revisions: rpass1 rpass2
|
||||
// compile-pass
|
||||
|
||||
#![feature(on_unimplemented)]
|
||||
#![deny(unused_attributes)]
|
||||
|
||||
#[rustc_on_unimplemented = "invalid"]
|
||||
trait Index<Idx: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
fn index(&self, index: Idx) -> &Self::Output;
|
||||
}
|
||||
|
||||
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
|
||||
impl Index<usize> for [i32] {
|
||||
type Output = i32;
|
||||
fn index(&self, index: usize) -> &i32 {
|
||||
&self[index]
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Index::<usize>::index(&[1, 2, 3] as &[i32], 2);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// We should not see the unused_attributes lint fire for
|
||||
// rustc_layout_scalar_valid_range_start, but with this bug we are
|
||||
// seeing it fire (on subsequent runs) if incremental compilation is
|
||||
// enabled.
|
||||
|
||||
// revisions: rpass1 rpass2
|
||||
// compile-pass
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![deny(unused_attributes)]
|
||||
|
||||
#[rustc_layout_scalar_valid_range_start(10)]
|
||||
#[rustc_layout_scalar_valid_range_end(30)]
|
||||
struct RestrictedRange(u32);
|
||||
const OKAY_RANGE: RestrictedRange = unsafe { RestrictedRange(20) };
|
||||
|
||||
fn main() {
|
||||
OKAY_RANGE.0;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
// run-pass
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
pub enum NonExhaustiveEnum {
|
||||
Unit,
|
||||
Tuple(u32),
|
||||
Struct { field: u32 }
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// run-pass
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct NormalStruct {
|
||||
pub first_field: u16,
|
||||
pub second_field: u16,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UnitStruct;
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct TupleStruct (pub u16, pub u16);
|
|
@ -1,9 +0,0 @@
|
|||
// run-pass
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
pub enum NonExhaustiveVariants {
|
||||
#[non_exhaustive] Unit,
|
||||
#[non_exhaustive] Tuple(u32),
|
||||
#[non_exhaustive] Struct { field: u32 }
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// run-pass
|
||||
// aux-build:enums.rs
|
||||
extern crate enums;
|
||||
|
||||
// ignore-pretty issue #37199
|
||||
|
||||
use enums::NonExhaustiveEnum;
|
||||
|
||||
fn main() {
|
||||
let enum_unit = NonExhaustiveEnum::Unit;
|
||||
|
||||
match enum_unit {
|
||||
NonExhaustiveEnum::Unit => 1,
|
||||
NonExhaustiveEnum::Tuple(_) => 2,
|
||||
// This particular arm tests that a enum marked as non-exhaustive
|
||||
// will not error if its variants are matched exhaustively.
|
||||
NonExhaustiveEnum::Struct { field } => field,
|
||||
_ => 0 // no error with wildcard
|
||||
};
|
||||
|
||||
match enum_unit {
|
||||
_ => "no error with only wildcard"
|
||||
};
|
||||
|
||||
|
||||
// issue #53549 - check that variant constructors can still be called normally.
|
||||
|
||||
match NonExhaustiveEnum::Unit {
|
||||
NonExhaustiveEnum::Unit => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match NonExhaustiveEnum::Tuple(2) {
|
||||
NonExhaustiveEnum::Tuple(2) => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match (NonExhaustiveEnum::Unit {}) {
|
||||
NonExhaustiveEnum::Unit {} => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match (NonExhaustiveEnum::Tuple { 0: 2 }) {
|
||||
NonExhaustiveEnum::Tuple { 0: 2 } => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match (NonExhaustiveEnum::Struct { field: 2 }) {
|
||||
NonExhaustiveEnum::Struct { field: 2 } => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
// aux-build:structs.rs
|
||||
extern crate structs;
|
||||
|
||||
use structs::{NormalStruct, UnitStruct, TupleStruct};
|
||||
|
||||
// We only test matching here as we cannot create non-exhaustive
|
||||
// structs from another crate. ie. they'll never pass in run-pass tests.
|
||||
|
||||
fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
|
||||
let NormalStruct { first_field, second_field, .. } = ns;
|
||||
|
||||
let TupleStruct { 0: first, 1: second, .. } = ts;
|
||||
|
||||
let UnitStruct { .. } = us;
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -1,22 +0,0 @@
|
|||
// run-pass
|
||||
// aux-build:variants.rs
|
||||
extern crate variants;
|
||||
|
||||
use variants::NonExhaustiveVariants;
|
||||
|
||||
/*
|
||||
* The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
|
||||
* variants. See issue #44109 and PR 45394.
|
||||
*/
|
||||
// ignore-test
|
||||
|
||||
fn main() {
|
||||
let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 };
|
||||
let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
|
||||
|
||||
match variant_struct {
|
||||
NonExhaustiveVariants::Unit => "",
|
||||
NonExhaustiveVariants::Struct { field, .. } => "",
|
||||
NonExhaustiveVariants::Tuple(fe_tpl, ..) => ""
|
||||
};
|
||||
}
|
|
@ -15,6 +15,14 @@ fn foo4(u: &u32) {
|
|||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
struct S<'a> {
|
||||
u: &'a u32,
|
||||
}
|
||||
|
||||
struct R {
|
||||
i: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = String::new();
|
||||
let r_s = &s;
|
||||
|
@ -27,4 +35,14 @@ fn main() {
|
|||
foo4(&0);
|
||||
assert_eq!(3i32, &3i32);
|
||||
//~^ ERROR mismatched types
|
||||
let u = 3;
|
||||
let s = S { u };
|
||||
//~^ ERROR mismatched types
|
||||
let s = S { u: u };
|
||||
//~^ ERROR mismatched types
|
||||
let i = &4;
|
||||
let r = R { i };
|
||||
//~^ ERROR mismatched types
|
||||
let r = R { i: i };
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ LL | foo3(u);
|
|||
found type `&u32`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:22:9
|
||||
--> $DIR/deref-suggestion.rs:30:9
|
||||
|
|
||||
LL | foo(&"aaa".to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
@ -35,7 +35,7 @@ LL | foo(&"aaa".to_owned());
|
|||
found type `&std::string::String`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:24:9
|
||||
--> $DIR/deref-suggestion.rs:32:9
|
||||
|
|
||||
LL | foo(&mut "aaa".to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -59,7 +59,7 @@ LL | foo3(borrow!(0));
|
|||
found type `&{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:28:5
|
||||
--> $DIR/deref-suggestion.rs:36:5
|
||||
|
|
||||
LL | assert_eq!(3i32, &3i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found &i32
|
||||
|
@ -68,6 +68,54 @@ LL | assert_eq!(3i32, &3i32);
|
|||
found type `&i32`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:39:17
|
||||
|
|
||||
LL | let s = S { u };
|
||||
| ^
|
||||
| |
|
||||
| expected &u32, found integer
|
||||
| help: consider borrowing here: `u: &u`
|
||||
|
|
||||
= note: expected type `&u32`
|
||||
found type `{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:41:20
|
||||
|
|
||||
LL | let s = S { u: u };
|
||||
| ^
|
||||
| |
|
||||
| expected &u32, found integer
|
||||
| help: consider borrowing here: `&u`
|
||||
|
|
||||
= note: expected type `&u32`
|
||||
found type `{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:44:17
|
||||
|
|
||||
LL | let r = R { i };
|
||||
| ^
|
||||
| |
|
||||
| expected u32, found &{integer}
|
||||
| help: consider dereferencing the borrow: `i: *i`
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `&{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:46:20
|
||||
|
|
||||
LL | let r = R { i: i };
|
||||
| ^
|
||||
| |
|
||||
| expected u32, found &{integer}
|
||||
| help: consider dereferencing the borrow: `*i`
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `&{integer}`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
fn main () {
|
||||
let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=`
|
||||
let sr: Vec<(u32, _, _) = vec![];
|
||||
//~^ ERROR expected one of `,` or `>`, found `=`
|
||||
//~| ERROR expected value, found struct `Vec`
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR invalid left-hand side expression
|
||||
//~| ERROR expected expression, found reserved identifier `_`
|
||||
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
|
||||
//~^ ERROR no method named `iter` found for type `()` in the current scope
|
||||
}
|
||||
|
|
|
@ -1,10 +1,47 @@
|
|||
error: expected expression, found reserved identifier `_`
|
||||
--> $DIR/issue-34334.rs:2:23
|
||||
|
|
||||
LL | let sr: Vec<(u32, _, _) = vec![];
|
||||
| ^ expected expression
|
||||
|
||||
error: expected one of `,` or `>`, found `=`
|
||||
--> $DIR/issue-34334.rs:2:29
|
||||
|
|
||||
LL | let sr: Vec<(u32, _, _) = vec![];
|
||||
| -- ^ expected one of `,` or `>` here
|
||||
| |
|
||||
| --- ^ expected one of `,` or `>` here
|
||||
| | |
|
||||
| | help: use `=` if you meant to assign
|
||||
| while parsing the type for `sr`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0423]: expected value, found struct `Vec`
|
||||
--> $DIR/issue-34334.rs:2:13
|
||||
|
|
||||
LL | let sr: Vec<(u32, _, _) = vec![];
|
||||
| ^^^ did you mean `Vec { /* fields */ }`?
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-34334.rs:2:31
|
||||
|
|
||||
LL | let sr: Vec<(u32, _, _) = vec![];
|
||||
| ^^^^^^ expected bool, found struct `std::vec::Vec`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found type `std::vec::Vec<_>`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0070]: invalid left-hand side expression
|
||||
--> $DIR/issue-34334.rs:2:13
|
||||
|
|
||||
LL | let sr: Vec<(u32, _, _) = vec![];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid
|
||||
|
||||
error[E0599]: no method named `iter` found for type `()` in the current scope
|
||||
--> $DIR/issue-34334.rs:8:36
|
||||
|
|
||||
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors occurred: E0070, E0308, E0423, E0599.
|
||||
For more information about an error, try `rustc --explain E0070`.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn main() {
|
||||
match 0 {
|
||||
match (0, 1) {
|
||||
(, ..) => {} //~ ERROR expected pattern, found `,`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn main() {
|
||||
match 0 {
|
||||
match (0, 1) {
|
||||
(pat ..) => {} //~ ERROR unexpected token: `)`
|
||||
}
|
||||
}
|
||||
|
|
14
src/test/ui/parser/recover-from-bad-variant.rs
Normal file
14
src/test/ui/parser/recover-from-bad-variant.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
enum Enum {
|
||||
Foo { a: usize, b: usize },
|
||||
Bar(usize, usize),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Enum::Foo(a: 3, b: 4);
|
||||
//~^ ERROR expected type, found `3`
|
||||
match x {
|
||||
Enum::Foo(a, b) => {}
|
||||
//~^ ERROR expected tuple struct/variant, found struct variant `Enum::Foo`
|
||||
Enum::Bar(a, b) => {}
|
||||
}
|
||||
}
|
23
src/test/ui/parser/recover-from-bad-variant.stderr
Normal file
23
src/test/ui/parser/recover-from-bad-variant.stderr
Normal file
|
@ -0,0 +1,23 @@
|
|||
error: expected type, found `3`
|
||||
--> $DIR/recover-from-bad-variant.rs:7:26
|
||||
|
|
||||
LL | let x = Enum::Foo(a: 3, b: 4);
|
||||
| ^ expecting a type here because of type ascription
|
||||
|
|
||||
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
|
||||
note: this expression expects an ascribed type after the colon
|
||||
--> $DIR/recover-from-bad-variant.rs:7:23
|
||||
|
|
||||
LL | let x = Enum::Foo(a: 3, b: 4);
|
||||
| ^
|
||||
= help: this might be indicative of a syntax error elsewhere
|
||||
|
||||
error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo`
|
||||
--> $DIR/recover-from-bad-variant.rs:10:9
|
||||
|
|
||||
LL | Enum::Foo(a, b) => {}
|
||||
| ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`?
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0532`.
|
12
src/test/ui/parser/recover-tuple-pat.rs
Normal file
12
src/test/ui/parser/recover-tuple-pat.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
fn main() {
|
||||
let x = (1, 2, 3, 4);
|
||||
match x {
|
||||
(1, .., 4) => {}
|
||||
(1, .=., 4) => { let _: usize = ""; }
|
||||
//~^ ERROR expected pattern, found `.`
|
||||
//~| ERROR mismatched types
|
||||
(.=., 4) => {}
|
||||
//~^ ERROR expected pattern, found `.`
|
||||
(1, 2, 3, 4) => {}
|
||||
}
|
||||
}
|
24
src/test/ui/parser/recover-tuple-pat.stderr
Normal file
24
src/test/ui/parser/recover-tuple-pat.stderr
Normal file
|
@ -0,0 +1,24 @@
|
|||
error: expected pattern, found `.`
|
||||
--> $DIR/recover-tuple-pat.rs:5:13
|
||||
|
|
||||
LL | (1, .=., 4) => { let _: usize = ""; }
|
||||
| ^ expected pattern
|
||||
|
||||
error: expected pattern, found `.`
|
||||
--> $DIR/recover-tuple-pat.rs:8:10
|
||||
|
|
||||
LL | (.=., 4) => {}
|
||||
| ^ expected pattern
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recover-tuple-pat.rs:5:41
|
||||
|
|
||||
LL | (1, .=., 4) => { let _: usize = ""; }
|
||||
| ^^ expected usize, found reference
|
||||
|
|
||||
= note: expected type `usize`
|
||||
found type `&'static str`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
11
src/test/ui/parser/recover-tuple.rs
Normal file
11
src/test/ui/parser/recover-tuple.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
fn main() {
|
||||
// no complaints about the tuple not matching the expected type
|
||||
let x: (usize, usize, usize) = (3, .=.);
|
||||
//~^ ERROR expected expression, found `.`
|
||||
// verify that the parser recovers:
|
||||
let y: usize = ""; //~ ERROR mismatched types
|
||||
// no complaints about the type
|
||||
foo(x);
|
||||
}
|
||||
|
||||
fn foo(_: (usize, usize, usize)) {}
|
18
src/test/ui/parser/recover-tuple.stderr
Normal file
18
src/test/ui/parser/recover-tuple.stderr
Normal file
|
@ -0,0 +1,18 @@
|
|||
error: expected expression, found `.`
|
||||
--> $DIR/recover-tuple.rs:3:40
|
||||
|
|
||||
LL | let x: (usize, usize, usize) = (3, .=.);
|
||||
| ^ expected expression
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recover-tuple.rs:6:20
|
||||
|
|
||||
LL | let y: usize = "";
|
||||
| ^^ expected usize, found reference
|
||||
|
|
||||
= note: expected type `usize`
|
||||
found type `&'static str`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -6,7 +6,10 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s
|
|||
|
||||
fn check<'a>() {
|
||||
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
|
||||
let _: Box<('a) + Trait>; //~ ERROR expected type, found `'a`
|
||||
let _: Box<('a) + Trait>;
|
||||
//~^ ERROR expected type, found `'a`
|
||||
//~| ERROR expected `:`, found `)`
|
||||
//~| ERROR chained comparison operators require parentheses
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -10,6 +10,21 @@ error: parenthesized lifetime bounds are not supported
|
|||
LL | let _: Box<Trait + ('a)>;
|
||||
| ^^^^ help: remove the parentheses
|
||||
|
||||
error: expected `:`, found `)`
|
||||
--> $DIR/trait-object-lifetime-parens.rs:9:19
|
||||
|
|
||||
LL | let _: Box<('a) + Trait>;
|
||||
| ^ expected `:`
|
||||
|
||||
error: chained comparison operators require parentheses
|
||||
--> $DIR/trait-object-lifetime-parens.rs:9:15
|
||||
|
|
||||
LL | let _: Box<('a) + Trait>;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
|
||||
= help: or use `(...)` if you meant to specify fn arguments
|
||||
|
||||
error: expected type, found `'a`
|
||||
--> $DIR/trait-object-lifetime-parens.rs:9:17
|
||||
|
|
||||
|
@ -18,5 +33,5 @@ LL | let _: Box<('a) + Trait>;
|
|||
| |
|
||||
| while parsing the type for `_`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
@ -12,4 +12,48 @@ fn main() {
|
|||
NonExhaustiveEnum::Tuple(_) => "second",
|
||||
NonExhaustiveEnum::Struct { .. } => "third"
|
||||
};
|
||||
|
||||
// Everything below this is expected to compile successfully.
|
||||
|
||||
let enum_unit = NonExhaustiveEnum::Unit;
|
||||
|
||||
match enum_unit {
|
||||
NonExhaustiveEnum::Unit => 1,
|
||||
NonExhaustiveEnum::Tuple(_) => 2,
|
||||
// This particular arm tests that a enum marked as non-exhaustive
|
||||
// will not error if its variants are matched exhaustively.
|
||||
NonExhaustiveEnum::Struct { field } => field,
|
||||
_ => 0 // no error with wildcard
|
||||
};
|
||||
|
||||
match enum_unit {
|
||||
_ => "no error with only wildcard"
|
||||
};
|
||||
|
||||
// #53549: Check that variant constructors can still be called normally.
|
||||
match NonExhaustiveEnum::Unit {
|
||||
NonExhaustiveEnum::Unit => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match NonExhaustiveEnum::Tuple(2) {
|
||||
NonExhaustiveEnum::Tuple(2) => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match (NonExhaustiveEnum::Unit {}) {
|
||||
NonExhaustiveEnum::Unit {} => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match (NonExhaustiveEnum::Tuple { 0: 2 }) {
|
||||
NonExhaustiveEnum::Tuple { 0: 2 } => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match (NonExhaustiveEnum::Struct { field: 2 }) {
|
||||
NonExhaustiveEnum::Struct { field: 2 } => {},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
|
@ -35,3 +35,15 @@ fn main() {
|
|||
let UnitStruct { } = us;
|
||||
//~^ ERROR `..` required with struct marked as non-exhaustive
|
||||
}
|
||||
|
||||
// Everything below this is expected to compile successfully.
|
||||
|
||||
// We only test matching here as we cannot create non-exhaustive
|
||||
// structs from another crate. ie. they'll never pass in run-pass tests.
|
||||
fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
|
||||
let NormalStruct { first_field, second_field, .. } = ns;
|
||||
|
||||
let TupleStruct { 0: first, 1: second, .. } = ts;
|
||||
|
||||
let UnitStruct { .. } = us;
|
||||
}
|
|
@ -1,29 +1,29 @@
|
|||
error[E0423]: expected function, found struct `TupleStruct`
|
||||
--> $DIR/structs.rs:20:14
|
||||
--> $DIR/struct.rs:20:14
|
||||
|
|
||||
LL | let ts = TupleStruct(640, 480);
|
||||
| ^^^^^^^^^^^ constructor is not visible here due to private fields
|
||||
|
||||
error[E0423]: expected value, found struct `UnitStruct`
|
||||
--> $DIR/structs.rs:29:14
|
||||
--> $DIR/struct.rs:29:14
|
||||
|
|
||||
LL | let us = UnitStruct;
|
||||
| ^^^^^^^^^^ constructor is not visible here due to private fields
|
||||
|
||||
error[E0603]: tuple struct `TupleStruct` is private
|
||||
--> $DIR/structs.rs:23:32
|
||||
--> $DIR/struct.rs:23:32
|
||||
|
|
||||
LL | let ts_explicit = structs::TupleStruct(640, 480);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0603]: unit struct `UnitStruct` is private
|
||||
--> $DIR/structs.rs:32:32
|
||||
--> $DIR/struct.rs:32:32
|
||||
|
|
||||
LL | let us_explicit = structs::UnitStruct;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0639]: cannot create non-exhaustive struct using struct expression
|
||||
--> $DIR/structs.rs:7:14
|
||||
--> $DIR/struct.rs:7:14
|
||||
|
|
||||
LL | let fr = FunctionalRecord {
|
||||
| ______________^
|
||||
|
@ -35,25 +35,25 @@ LL | | };
|
|||
| |_____^
|
||||
|
||||
error[E0639]: cannot create non-exhaustive struct using struct expression
|
||||
--> $DIR/structs.rs:14:14
|
||||
--> $DIR/struct.rs:14:14
|
||||
|
|
||||
LL | let ns = NormalStruct { first_field: 640, second_field: 480 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0638]: `..` required with struct marked as non-exhaustive
|
||||
--> $DIR/structs.rs:17:9
|
||||
--> $DIR/struct.rs:17:9
|
||||
|
|
||||
LL | let NormalStruct { first_field, second_field } = ns;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0638]: `..` required with struct marked as non-exhaustive
|
||||
--> $DIR/structs.rs:26:9
|
||||
--> $DIR/struct.rs:26:9
|
||||
|
|
||||
LL | let TupleStruct { 0: first_field, 1: second_field } = ts;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0638]: `..` required with struct marked as non-exhaustive
|
||||
--> $DIR/structs.rs:35:9
|
||||
--> $DIR/struct.rs:35:9
|
||||
|
|
||||
LL | let UnitStruct { } = us;
|
||||
| ^^^^^^^^^^^^^^
|
|
@ -1,4 +1,5 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![feature(non_exhaustive)]
|
||||
|
|
@ -1,26 +1,33 @@
|
|||
// aux-build:variants.rs
|
||||
|
||||
extern crate variants;
|
||||
|
||||
use variants::NonExhaustiveVariants;
|
||||
|
||||
/*
|
||||
* The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
|
||||
* variants. See issue #44109 and PR 45394.
|
||||
*/
|
||||
// ignore-test
|
||||
|
||||
fn main() {
|
||||
let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
|
||||
//~^ ERROR cannot create non-exhaustive variant
|
||||
|
||||
let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 };
|
||||
//~^ ERROR cannot create non-exhaustive variant
|
||||
let variant_tuple = NonExhaustiveVariants::Tuple(640);
|
||||
//~^ ERROR tuple variant `Tuple` is private [E0603]
|
||||
|
||||
let variant_unit = NonExhaustiveVariants::Unit;
|
||||
//~^ ERROR unit variant `Unit` is private [E0603]
|
||||
|
||||
match variant_struct {
|
||||
NonExhaustiveVariants::Unit => "",
|
||||
//~^ ERROR unit variant `Unit` is private [E0603]
|
||||
NonExhaustiveVariants::Tuple(fe_tpl) => "",
|
||||
//~^ ERROR `..` required with variant marked as non-exhaustive
|
||||
//~^ ERROR tuple variant `Tuple` is private [E0603]
|
||||
NonExhaustiveVariants::Struct { field } => ""
|
||||
//~^ ERROR `..` required with variant marked as non-exhaustive
|
||||
};
|
||||
|
||||
if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
|
||||
//~^ ERROR tuple variant `Tuple` is private [E0603]
|
||||
}
|
||||
|
||||
if let NonExhaustiveVariants::Struct { field } = variant_struct {
|
||||
//~^ ERROR `..` required with variant marked as non-exhaustive
|
||||
}
|
||||
}
|
52
src/test/ui/rfc-2008-non-exhaustive/variant.stderr
Normal file
52
src/test/ui/rfc-2008-non-exhaustive/variant.stderr
Normal file
|
@ -0,0 +1,52 @@
|
|||
error[E0603]: tuple variant `Tuple` is private
|
||||
--> $DIR/variant.rs:11:48
|
||||
|
|
||||
LL | let variant_tuple = NonExhaustiveVariants::Tuple(640);
|
||||
| ^^^^^
|
||||
|
||||
error[E0603]: unit variant `Unit` is private
|
||||
--> $DIR/variant.rs:14:47
|
||||
|
|
||||
LL | let variant_unit = NonExhaustiveVariants::Unit;
|
||||
| ^^^^
|
||||
|
||||
error[E0603]: unit variant `Unit` is private
|
||||
--> $DIR/variant.rs:18:32
|
||||
|
|
||||
LL | NonExhaustiveVariants::Unit => "",
|
||||
| ^^^^
|
||||
|
||||
error[E0603]: tuple variant `Tuple` is private
|
||||
--> $DIR/variant.rs:20:32
|
||||
|
|
||||
LL | NonExhaustiveVariants::Tuple(fe_tpl) => "",
|
||||
| ^^^^^
|
||||
|
||||
error[E0603]: tuple variant `Tuple` is private
|
||||
--> $DIR/variant.rs:26:35
|
||||
|
|
||||
LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
|
||||
| ^^^^^
|
||||
|
||||
error[E0639]: cannot create non-exhaustive variant using struct expression
|
||||
--> $DIR/variant.rs:8:26
|
||||
|
|
||||
LL | let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0638]: `..` required with variant marked as non-exhaustive
|
||||
--> $DIR/variant.rs:22:9
|
||||
|
|
||||
LL | NonExhaustiveVariants::Struct { field } => ""
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0638]: `..` required with variant marked as non-exhaustive
|
||||
--> $DIR/variant.rs:30:12
|
||||
|
|
||||
LL | if let NonExhaustiveVariants::Struct { field } = variant_struct {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors occurred: E0603, E0638, E0639.
|
||||
For more information about an error, try `rustc --explain E0603`.
|
|
@ -1,17 +0,0 @@
|
|||
#![feature(non_exhaustive)]
|
||||
|
||||
/*
|
||||
* The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
|
||||
* variants. See issue #44109 and PR 45394.
|
||||
*/
|
||||
|
||||
pub enum NonExhaustiveVariants {
|
||||
#[non_exhaustive] Unit,
|
||||
//~^ ERROR #[non_exhaustive] is not yet supported on variants
|
||||
#[non_exhaustive] Tuple(u32),
|
||||
//~^ ERROR #[non_exhaustive] is not yet supported on variants
|
||||
#[non_exhaustive] Struct { field: u32 }
|
||||
//~^ ERROR #[non_exhaustive] is not yet supported on variants
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -1,20 +0,0 @@
|
|||
error: #[non_exhaustive] is not yet supported on variants
|
||||
--> $DIR/variants_create.rs:9:23
|
||||
|
|
||||
LL | #[non_exhaustive] Unit,
|
||||
| ^^^^
|
||||
|
||||
error: #[non_exhaustive] is not yet supported on variants
|
||||
--> $DIR/variants_create.rs:11:23
|
||||
|
|
||||
LL | #[non_exhaustive] Tuple(u32),
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: #[non_exhaustive] is not yet supported on variants
|
||||
--> $DIR/variants_create.rs:13:23
|
||||
|
|
||||
LL | #[non_exhaustive] Struct { field: u32 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
// run-pass
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
/*
|
||||
* The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
|
||||
* variants. See issue #44109 and PR 45394.
|
||||
*/
|
||||
// ignore-test
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
pub enum NonExhaustiveVariants {
|
||||
#[non_exhaustive] Unit,
|
Loading…
Add table
Add a link
Reference in a new issue