]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #77039 - ecstatic-morse:rollup-qv3jj4a, r=ecstatic-morse
authorbors <bors@rust-lang.org>
Tue, 22 Sep 2020 03:45:30 +0000 (03:45 +0000)
committerbors <bors@rust-lang.org>
Tue, 22 Sep 2020 03:45:30 +0000 (03:45 +0000)
Rollup of 13 pull requests

Successful merges:

 - #72734 (Reduce duplicate in liballoc reserve error handling)
 - #76131 (Don't use `zip` to compare iterators during pretty-print hack)
 - #76150 (Don't recommend ManuallyDrop to customize drop order)
 - #76275 (Implementation of Write for some immutable ref structs)
 - #76489 (Add explanation for E0756)
 - #76581 (do not ICE on bound variables, return `TooGeneric` instead)
 - #76655 (Make some methods of `Pin` unstable const)
 - #76783 (Only get ImplKind::Impl once)
 - #76807 (Use const-checking to forbid use of unstable features in const-stable functions)
 - #76888 (use if let instead of single match arm expressions)
 - #76914 (extend `Ty` and `TyCtxt` lints to self types)
 - #77022 (Reduce boilerplate for BytePos and CharPos)
 - #77032 (lint missing docs for extern items)

Failed merges:

r? `@ghost`

49 files changed:
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0756.md [new file with mode: 0644]
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_mir/src/interpret/operand.rs
compiler/rustc_mir/src/transform/check_consts/mod.rs
compiler/rustc_mir/src/transform/check_consts/ops.rs
compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
compiler/rustc_mir/src/transform/check_consts/validation.rs
compiler/rustc_mir/src/transform/promote_consts.rs
compiler/rustc_mir/src/transform/qualify_min_const_fn.rs
compiler/rustc_parse/src/lexer/tokentrees.rs
compiler/rustc_parse/src/lib.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_symbol_mangling/src/v0.rs
library/alloc/src/raw_vec.rs
library/core/src/lib.rs
library/core/src/mem/manually_drop.rs
library/core/src/pin.rs
library/core/tests/lib.rs
library/core/tests/pin.rs [new file with mode: 0644]
library/std/src/io/stdio.rs
library/std/src/io/util.rs
library/std/src/process.rs
src/librustdoc/clean/inline.rs
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs [new file with mode: 0644]
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-73260.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-73260.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-74634.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-74634.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-76595.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-76595.stderr [new file with mode: 0644]
src/test/ui/consts/miri_unleashed/box.stderr
src/test/ui/consts/miri_unleashed/mutable_references.stderr
src/test/ui/consts/miri_unleashed/mutable_references_err.stderr
src/test/ui/consts/stable-precise-live-drops-in-libcore.rs [new file with mode: 0644]
src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr [new file with mode: 0644]
src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs [new file with mode: 0644]
src/test/ui/ffi_const.stderr
src/test/ui/lint/lint-missing-doc.rs
src/test/ui/lint/lint-missing-doc.stderr

index 23a7b08016e509bbde955726d6b8527d9ea2afd6..a202736ea6cbeab90db5310ff1d0777264bb5af7 100644 (file)
 E0753: include_str!("./error_codes/E0753.md"),
 E0754: include_str!("./error_codes/E0754.md"),
 E0755: include_str!("./error_codes/E0755.md"),
+E0756: include_str!("./error_codes/E0756.md"),
 E0758: include_str!("./error_codes/E0758.md"),
 E0759: include_str!("./error_codes/E0759.md"),
 E0760: include_str!("./error_codes/E0760.md"),
     E0722, // Malformed `#[optimize]` attribute
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
-    E0756, // `#[ffi_const]` is only allowed on foreign functions
     E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]`
     E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md
new file mode 100644 (file)
index 0000000..ffdc421
--- /dev/null
@@ -0,0 +1,29 @@
+The `ffi_const` attribute was used on something other than a foreign function
+declaration.
+
+Erroneous code example:
+
+```compile_fail,E0756
+#![feature(ffi_const)]
+
+#[ffi_const] // error!
+pub fn foo() {}
+# fn main() {}
+```
+
+The `ffi_const` attribute can only be used on foreign function declarations
+which have no side effects except for their return value:
+
+```
+#![feature(ffi_const)]
+
+extern "C" {
+    #[ffi_const] // ok!
+    pub fn strlen(s: *const i8) -> i32;
+}
+# fn main() {}
+```
+
+You can get more information about it in the [unstable Rust Book].
+
+[unstable Rust Book]: https://doc.rust-lang.org/nightly/unstable-book/language-features/ffi-const.html
index 975b9d4f0863140a4187066f0f178139cc5167fe..441cfeea20a48d3a78894264e7d0eaff76dd3d7c 100644 (file)
@@ -488,18 +488,16 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
-        match t.kind {
-            TyKind::TraitObject(
-                poly_trait_refs,
-                Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
-            ) => {
-                for ptr in poly_trait_refs {
-                    if Some(self.1) == ptr.trait_ref.trait_def_id() {
-                        self.0.push(ptr.span);
-                    }
+        if let TyKind::TraitObject(
+            poly_trait_refs,
+            Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
+        ) = t.kind
+        {
+            for ptr in poly_trait_refs {
+                if Some(self.1) == ptr.trait_ref.trait_def_id() {
+                    self.0.push(ptr.span);
                 }
             }
-            _ => {}
         }
         walk_ty(self, t);
     }
index c35b6a9aaf4e95b1603096e51b99ff72f85523c5..abd899e8db4d33b6d9447bc7078dd15d296281b1 100644 (file)
@@ -613,6 +613,19 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
         );
     }
 
+    fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
+        let def_id = cx.tcx.hir().local_def_id(foreign_item.hir_id);
+        let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id());
+        self.check_missing_docs_attrs(
+            cx,
+            Some(foreign_item.hir_id),
+            &foreign_item.attrs,
+            foreign_item.span,
+            article,
+            desc,
+        );
+    }
+
     fn check_struct_field(&mut self, cx: &LateContext<'_>, sf: &hir::StructField<'_>) {
         if !sf.is_positional() {
             self.check_missing_docs_attrs(
index 100e555f299ae691bb9e3e35530dbe02cafb9348..c2d98b8e4ad378fa5bc308a30cd39dd18bbc0d27 100644 (file)
@@ -5,7 +5,9 @@
 use rustc_ast::{Item, ItemKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
+use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -177,11 +179,31 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool {
 fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
     if let TyKind::Path(qpath) = &ty.kind {
         if let QPath::Resolved(_, path) = qpath {
-            let did = path.res.opt_def_id()?;
-            if cx.tcx.is_diagnostic_item(sym::Ty, did) {
-                return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
-            } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
-                return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
+            match path.res {
+                Res::Def(_, did) => {
+                    if cx.tcx.is_diagnostic_item(sym::Ty, did) {
+                        return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
+                    } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
+                        return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
+                    }
+                }
+                // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
+                Res::SelfTy(None, Some((did, _))) => {
+                    if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+                        if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) {
+                            // NOTE: This path is currently unreachable as `Ty<'tcx>` is
+                            // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
+                            // is not actually allowed.
+                            //
+                            // I(@lcnr) still kept this branch in so we don't miss this
+                            // if we ever change it in the future.
+                            return Some(format!("Ty<{}>", substs[0]));
+                        } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) {
+                            return Some(format!("TyCtxt<{}>", substs[0]));
+                        }
+                    }
+                }
+                _ => (),
             }
         }
     }
index cd8f12a4f3576f5ce29cc909a2623cba258fce19..ccc8ffd9a9c6e553eaa20f01312f08127a712448 100644 (file)
@@ -1179,7 +1179,7 @@ pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
         self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
     }
 
-    pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
+    pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
         let cname = self.crate_name(LOCAL_CRATE).as_str();
         self.sess.consider_optimizing(&cname, msg)
     }
index ff98a8b9bf0bf260f5e007fc80fcc5e37a2cde67..342a37cadbac4375385e5c481850c694b3e3ef8c 100644 (file)
@@ -834,14 +834,11 @@ trait defining them",
                 kind: hir::ItemKind::Impl { items, .. }, ..
             })) => {
                 for item in &items[..] {
-                    match item.kind {
-                        hir::AssocItemKind::Type => {
-                            if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
-                                db.span_label(item.span, "expected this associated type");
-                                return true;
-                            }
+                    if let hir::AssocItemKind::Type = item.kind {
+                        if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
+                            db.span_label(item.span, "expected this associated type");
+                            return true;
                         }
-                        _ => {}
                     }
                 }
             }
@@ -853,7 +850,7 @@ trait defining them",
     /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
     /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`.
     fn constrain_generic_bound_associated_type_structured_suggestion(
-        &self,
+        self,
         db: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
@@ -877,7 +874,7 @@ fn constrain_generic_bound_associated_type_structured_suggestion(
     /// Given a span corresponding to a bound, provide a structured suggestion to set an
     /// associated type to a given type `ty`.
     fn constrain_associated_type_structured_suggestion(
-        &self,
+        self,
         db: &mut DiagnosticBuilder<'_>,
         span: Span,
         assoc: &ty::AssocItem,
index b0a1413a9d62fb1e369aa92299372356e60d168e..cb79b089d94a0156fd230f5234a59de330e764f0 100644 (file)
@@ -1259,11 +1259,11 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                 tcx.layout_raw(param_env.and(normalized))?
             }
 
-            ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+            ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
                 bug!("Layout::compute: unexpected type `{}`", ty)
             }
 
-            ty::Param(_) | ty::Error(_) => {
+            ty::Bound(..) | ty::Param(_) | ty::Error(_) => {
                 return Err(LayoutError::Unknown(ty));
             }
         })
index f0bae48cc1221798ef8bea519e8c91117a03e936..c9cc9bfc9fa263ad80a49b996cae750bbf8d9e5c 100644 (file)
@@ -2125,17 +2125,10 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
     // Iterate all local crate items no matter where they are defined.
     let hir = tcx.hir();
     for item in hir.krate().items.values() {
-        if item.ident.name.as_str().is_empty() {
+        if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) {
             continue;
         }
 
-        match item.kind {
-            ItemKind::Use(_, _) => {
-                continue;
-            }
-            _ => {}
-        }
-
         if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) {
             let def_id = local_def_id.to_def_id();
             let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
index 9fcbd60d4a3ba80846f75e4a2d220bee06f0e853..735f890a33bdc495eadff14f607780900b216877 100644 (file)
@@ -549,15 +549,13 @@ pub(super) fn eval_operands(
         };
         // Early-return cases.
         let val_val = match val.val {
-            ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
+            ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
             ty::ConstKind::Unevaluated(def, substs, promoted) => {
                 let instance = self.resolve(def, substs)?;
                 return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
             }
-            ty::ConstKind::Infer(..)
-            | ty::ConstKind::Bound(..)
-            | ty::ConstKind::Placeholder(..) => {
+            ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
                 span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
             }
             ty::ConstKind::Value(val_val) => val_val,
index 81c1b0b5bd49f6443144776f06b11faa79ce72cc..c1b4cb5f1a8d54f7ab4ec4be441e3c5c8414a577 100644 (file)
@@ -4,10 +4,12 @@
 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
 //! it finds operations that are invalid in a certain context.
 
+use rustc_attr as attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::Symbol;
 
 pub use self::qualifs::Qualif;
 
@@ -55,3 +57,9 @@ pub fn const_kind(&self) -> hir::ConstContext {
 pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn()
 }
+
+pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
+    let attrs = tcx.get_attrs(def_id);
+    attr::allow_internal_unstable(&tcx.sess, attrs)
+        .map_or(false, |mut features| features.any(|name| name == feature_gate))
+}
index ea025f208e49d733a25a3be51bf856cdcfb0a101..032cbc23a3f52d8c552224d289443ca767011854 100644 (file)
@@ -1,6 +1,6 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_session::config::nightly_options;
 pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
     debug!("illegal_op: op={:?}", op);
 
-    if op.is_allowed_in_item(ccx) {
-        return;
-    }
+    let gate = match op.status_in_item(ccx) {
+        Status::Allowed => return,
+
+        Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
+            let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn
+                && ccx.tcx.features().enabled(sym::staged_api)
+                && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable)
+                && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);
+
+            if unstable_in_stable {
+                ccx.tcx.sess
+                    .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str()))
+                    .span_suggestion(
+                        ccx.body.span,
+                        "if it is not part of the public API, make this function unstably const",
+                        concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
+                        Applicability::HasPlaceholders,
+                    )
+                    .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
+                    .emit();
+            }
+
+            return;
+        }
+
+        Status::Unstable(gate) => Some(gate),
+        Status::Forbidden => None,
+    };
 
     if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
-        ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
+        ccx.tcx.sess.miri_unleashed_feature(span, gate);
         return;
     }
 
     op.emit_error(ccx, span);
 }
 
+pub enum Status {
+    Allowed,
+    Unstable(Symbol),
+    Forbidden,
+}
+
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
-    /// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
-    /// or `None` if such a feature gate does not exist.
-    fn feature_gate() -> Option<Symbol> {
-        None
-    }
-
-    /// Returns `true` if this operation is allowed in the given item.
-    ///
-    /// This check should assume that we are not in a non-const `fn`, where all operations are
-    /// legal.
-    ///
-    /// By default, it returns `true` if and only if this operation has a corresponding feature
-    /// gate and that gate is enabled.
-    fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
-        Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate))
+    /// Returns an enum indicating whether this operation is allowed within the given item.
+    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+        Status::Forbidden
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -53,9 +72,13 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
             "{} contains unimplemented expression type",
             ccx.const_kind()
         );
-        if let Some(feat) = Self::feature_gate() {
-            err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat));
+
+        if let Status::Unstable(gate) = self.status_in_item(ccx) {
+            if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() {
+                err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate));
+            }
         }
+
         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "A function call isn't allowed in the const's initialization expression \
@@ -147,7 +170,9 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 impl NonConstOp for InlineAsm {}
 
 #[derive(Debug)]
-pub struct LiveDrop(pub Option<Span>);
+pub struct LiveDrop {
+    pub dropped_at: Option<Span>,
+}
 impl NonConstOp for LiveDrop {
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
         let mut diagnostic = struct_span_err!(
@@ -157,7 +182,7 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
             "destructors cannot be evaluated at compile-time"
         );
         diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
-        if let Some(span) = self.0 {
+        if let Some(span) = self.dropped_at {
             diagnostic.span_label(span, "value is dropped here");
         }
         diagnostic.emit();
@@ -182,14 +207,13 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct MutBorrow;
 impl NonConstOp for MutBorrow {
-    fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
-        // Forbid everywhere except in const fn
-        ccx.const_kind() == hir::ConstContext::ConstFn
-            && ccx.tcx.features().enabled(Self::feature_gate().unwrap())
-    }
-
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_mut_refs)
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        // Forbid everywhere except in const fn with a feature gate
+        if ccx.const_kind() == hir::ConstContext::ConstFn {
+            Status::Unstable(sym::const_mut_refs)
+        } else {
+            Status::Forbidden
+        }
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -201,15 +225,16 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
                 &format!("mutable references are not allowed in {}s", ccx.const_kind()),
             )
         } else {
-            struct_span_err!(
+            let mut err = struct_span_err!(
                 ccx.tcx.sess,
                 span,
                 E0764,
                 "mutable references are not allowed in {}s",
                 ccx.const_kind(),
-            )
+            );
+            err.span_label(span, format!("`&mut` is only allowed in `const fn`"));
+            err
         };
-        err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "References in statics and constants may only refer \
@@ -226,11 +251,17 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
     }
 }
 
+// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
 #[derive(Debug)]
 pub struct MutAddressOf;
 impl NonConstOp for MutAddressOf {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_mut_refs)
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        // Forbid everywhere except in const fn with a feature gate
+        if ccx.const_kind() == hir::ConstContext::ConstFn {
+            Status::Unstable(sym::const_mut_refs)
+        } else {
+            Status::Forbidden
+        }
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -247,16 +278,16 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct MutDeref;
 impl NonConstOp for MutDeref {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_mut_refs)
+    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+        Status::Unstable(sym::const_mut_refs)
     }
 }
 
 #[derive(Debug)]
 pub struct Panic;
 impl NonConstOp for Panic {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_panic)
+    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+        Status::Unstable(sym::const_panic)
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -289,8 +320,8 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct RawPtrDeref;
 impl NonConstOp for RawPtrDeref {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_raw_ptr_deref)
+    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+        Status::Unstable(sym::const_raw_ptr_deref)
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -307,8 +338,8 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct RawPtrToIntCast;
 impl NonConstOp for RawPtrToIntCast {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_raw_ptr_to_usize_cast)
+    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+        Status::Unstable(sym::const_raw_ptr_to_usize_cast)
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -326,8 +357,12 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct StaticAccess;
 impl NonConstOp for StaticAccess {
-    fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
-        matches!(ccx.const_kind(), hir::ConstContext::Static(_))
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        if let hir::ConstContext::Static(_) = ccx.const_kind() {
+            Status::Allowed
+        } else {
+            Status::Forbidden
+        }
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -371,14 +406,13 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct UnionAccess;
 impl NonConstOp for UnionAccess {
-    fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         // Union accesses are stable in all contexts except `const fn`.
-        ccx.const_kind() != hir::ConstContext::ConstFn
-            || ccx.tcx.features().enabled(Self::feature_gate().unwrap())
-    }
-
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_fn_union)
+        if ccx.const_kind() != hir::ConstContext::ConstFn {
+            Status::Allowed
+        } else {
+            Status::Unstable(sym::const_fn_union)
+        }
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
index 55075b3ab5e99912e8501ed42b88a82e4b07630f..0228f2d7de023f87f7eb440e4b8bc597344ac230 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 use super::ops;
 use super::qualifs::{NeedsDrop, Qualif};
 
 /// Returns `true` if we should use the more precise live drop checker that runs after drop
 /// elaboration.
-pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool {
+pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+    // Const-stable functions must always use the stable live drop checker.
+    if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) {
+        return false;
+    }
+
     tcx.features().const_precise_live_drops
 }
 
@@ -25,7 +30,7 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<
         return;
     }
 
-    if !checking_enabled(tcx) {
+    if !checking_enabled(tcx, def_id) {
         return;
     }
 
@@ -52,7 +57,7 @@ fn deref(&self) -> &Self::Target {
 
 impl CheckLiveDrops<'mir, 'tcx> {
     fn check_live_drop(&self, span: Span) {
-        ops::non_const(self.ccx, ops::LiveDrop(None), span);
+        ops::non_const(self.ccx, ops::LiveDrop { dropped_at: None }, span);
     }
 }
 
index e8411b121e394b59e81aa1f49a17c49e346a46e0..0501302b7610a089c0552f389b0f54895b1fd52b 100644 (file)
@@ -551,7 +551,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
                 // errors here.
-                if super::post_drop_elaboration::checking_enabled(self.tcx) {
+                if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) {
                     return;
                 }
 
@@ -576,7 +576,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
 
                 if needs_drop {
                     self.check_op_spanned(
-                        ops::LiveDrop(Some(terminator.source_info.span)),
+                        ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
                         err_span,
                     );
                 }
index 01d518386fc4ec589534b87aa0427d4d8fff3eac..cd361e430fa6108e0eb22ab7345698d739176c05 100644 (file)
@@ -242,11 +242,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             }
             TerminatorKind::InlineAsm { ref operands, .. } => {
                 for (index, op) in operands.iter().enumerate() {
-                    match op {
-                        InlineAsmOperand::Const { .. } => {
-                            self.candidates.push(Candidate::InlineAsm { bb: location.block, index })
-                        }
-                        _ => {}
+                    if let InlineAsmOperand::Const { .. } = op {
+                        self.candidates.push(Candidate::InlineAsm { bb: location.block, index })
                     }
                 }
             }
@@ -612,12 +609,9 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 let operand_ty = operand.ty(self.body, self.tcx);
                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-                match (cast_in, cast_out) {
-                    (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
-                        // ptr-to-int casts are not possible in consts and thus not promotable
-                        return Err(Unpromotable);
-                    }
-                    _ => {}
+                if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
+                    // ptr-to-int casts are not possible in consts and thus not promotable
+                    return Err(Unpromotable);
                 }
             }
 
index 5e102f5151d0ceebedcbe3256d8a3804e1b3be3f..f15a7f7c2c889c545b2808fe9e1793953377e32e 100644 (file)
@@ -1,4 +1,3 @@
-use rustc_attr as attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::*;
@@ -344,8 +343,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo
 
     // However, we cannot allow stable `const fn`s to use unstable features without an explicit
     // opt-in via `allow_internal_unstable`.
-    attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
-        .map_or(false, |mut features| features.any(|name| name == feature_gate))
+    super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate)
 }
 
 /// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`.
@@ -364,8 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo
 
     // However, we cannot allow stable `const fn`s to use unstable features without an explicit
     // opt-in via `allow_internal_unstable`.
-    attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
-        .map_or(false, |mut features| features.any(|name| name == feature_gate))
+    super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate)
 }
 
 fn check_terminator(
index 0f364bffb134ec31d83031398a7dd5bb1687ffd0..6233549dc8579782ade27903fb81e0c783e199aa 100644 (file)
@@ -149,12 +149,9 @@ fn parse_token_tree(&mut self) -> PResult<'a, TreeAndSpacing> {
                             }
                         }
 
-                        match (open_brace, delim) {
-                            //only add braces
-                            (DelimToken::Brace, DelimToken::Brace) => {
-                                self.matching_block_spans.push((open_brace_span, close_brace_span));
-                            }
-                            _ => {}
+                        //only add braces
+                        if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) {
+                            self.matching_block_spans.push((open_brace_span, close_brace_span));
                         }
 
                         if self.open_braces.is_empty() {
index 72a34b86ae20bbb0451f8e33ec97763b92b6cdd6..21bbdc9ba8dce05b14bd56770c88dfe7a4bd68a4 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(bindings_after_at)]
+#![feature(iter_order_by)]
 #![feature(or_patterns)]
 
 use rustc_ast as ast;
@@ -459,14 +460,10 @@ fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
 
     // Break tokens after we expand any nonterminals, so that we break tokens
     // that are produced as a result of nonterminal expansion.
-    let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
-    let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
-    for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
-        if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) {
-            return false;
-        }
-    }
-    t1.next().is_none() && t2.next().is_none()
+    let t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
+    let t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
+
+    t1.eq_by(t2, |t1, t2| tokentree_probably_equal_for_proc_macro(&t1, &t2, sess))
 }
 
 // See comments in `Nonterminal::to_tokenstream` for why we care about
index dde162681b77311f1f4923f13d3d04f55f6dda68..cef632b1d8f03180ced3f5017e0c833301acda04 100644 (file)
@@ -525,12 +525,9 @@ fn format(&mut self) -> FormatSpec<'a> {
 
         // fill character
         if let Some(&(_, c)) = self.cur.peek() {
-            match self.cur.clone().nth(1) {
-                Some((_, '>' | '<' | '^')) => {
-                    spec.fill = Some(c);
-                    self.cur.next();
-                }
-                _ => {}
+            if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) {
+                spec.fill = Some(c);
+                self.cur.next();
             }
         }
         // Alignment
index 85ddc5f55d110b389f288f839c35e2eb50417831..677cf27cde71cbd353f523530413dd49546b70e4 100644 (file)
@@ -534,11 +534,8 @@ fn ensure_traits<R>(&'a self, resolver: &mut R)
                 if ns != TypeNS {
                     return;
                 }
-                match binding.res() {
-                    Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
-                        collected_traits.push((name, binding))
-                    }
-                    _ => (),
+                if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() {
+                    collected_traits.push((name, binding))
                 }
             });
             *traits = Some(collected_traits.into_boxed_slice());
index a730c30378827e328ae8f5c5106e9e5da5f3d3ab..4b02a2d4076d7749c0cb28a078bd0c129fb6ff71 100644 (file)
@@ -1558,58 +1558,71 @@ pub trait Pos {
     fn to_u32(&self) -> u32;
 }
 
-/// A byte offset. Keep this small (currently 32-bits), as AST contains
-/// a lot of them.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
-pub struct BytePos(pub u32);
-
-/// A character offset. Because of multibyte UTF-8 characters, a byte offset
-/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
-/// values to `CharPos` values as necessary.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct CharPos(pub usize);
+macro_rules! impl_pos {
+    (
+        $(
+            $(#[$attr:meta])*
+            $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
+        )*
+    ) => {
+        $(
+            $(#[$attr])*
+            $vis struct $ident($inner_vis $inner_ty);
+
+            impl Pos for $ident {
+                #[inline(always)]
+                fn from_usize(n: usize) -> $ident {
+                    $ident(n as $inner_ty)
+                }
 
-// FIXME: lots of boilerplate in these impls, but so far my attempts to fix
-// have been unsuccessful.
+                #[inline(always)]
+                fn to_usize(&self) -> usize {
+                    self.0 as usize
+                }
 
-impl Pos for BytePos {
-    #[inline(always)]
-    fn from_usize(n: usize) -> BytePos {
-        BytePos(n as u32)
-    }
+                #[inline(always)]
+                fn from_u32(n: u32) -> $ident {
+                    $ident(n as $inner_ty)
+                }
 
-    #[inline(always)]
-    fn to_usize(&self) -> usize {
-        self.0 as usize
-    }
+                #[inline(always)]
+                fn to_u32(&self) -> u32 {
+                    self.0 as u32
+                }
+            }
 
-    #[inline(always)]
-    fn from_u32(n: u32) -> BytePos {
-        BytePos(n)
-    }
+            impl Add for $ident {
+                type Output = $ident;
 
-    #[inline(always)]
-    fn to_u32(&self) -> u32 {
-        self.0
-    }
-}
+                #[inline(always)]
+                fn add(self, rhs: $ident) -> $ident {
+                    $ident(self.0 + rhs.0)
+                }
+            }
 
-impl Add for BytePos {
-    type Output = BytePos;
+            impl Sub for $ident {
+                type Output = $ident;
 
-    #[inline(always)]
-    fn add(self, rhs: BytePos) -> BytePos {
-        BytePos((self.to_usize() + rhs.to_usize()) as u32)
-    }
+                #[inline(always)]
+                fn sub(self, rhs: $ident) -> $ident {
+                    $ident(self.0 - rhs.0)
+                }
+            }
+        )*
+    };
 }
 
-impl Sub for BytePos {
-    type Output = BytePos;
+impl_pos! {
+    /// A byte offset. Keep this small (currently 32-bits), as AST contains
+    /// a lot of them.
+    #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+    pub struct BytePos(pub u32);
 
-    #[inline(always)]
-    fn sub(self, rhs: BytePos) -> BytePos {
-        BytePos((self.to_usize() - rhs.to_usize()) as u32)
-    }
+    /// A character offset. Because of multibyte UTF-8 characters, a byte offset
+    /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
+    /// values to `CharPos` values as necessary.
+    #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+    pub struct CharPos(pub usize);
 }
 
 impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
@@ -1624,46 +1637,6 @@ fn decode(d: &mut D) -> Result<BytePos, D::Error> {
     }
 }
 
-impl Pos for CharPos {
-    #[inline(always)]
-    fn from_usize(n: usize) -> CharPos {
-        CharPos(n)
-    }
-
-    #[inline(always)]
-    fn to_usize(&self) -> usize {
-        self.0
-    }
-
-    #[inline(always)]
-    fn from_u32(n: u32) -> CharPos {
-        CharPos(n as usize)
-    }
-
-    #[inline(always)]
-    fn to_u32(&self) -> u32 {
-        self.0 as u32
-    }
-}
-
-impl Add for CharPos {
-    type Output = CharPos;
-
-    #[inline(always)]
-    fn add(self, rhs: CharPos) -> CharPos {
-        CharPos(self.to_usize() + rhs.to_usize())
-    }
-}
-
-impl Sub for CharPos {
-    type Output = CharPos;
-
-    #[inline(always)]
-    fn sub(self, rhs: CharPos) -> CharPos {
-        CharPos(self.to_usize() - rhs.to_usize())
-    }
-}
-
 // _____________________________________________________________________________
 // Loc, SourceFileAndLine, SourceFileAndBytePos
 //
index 619edf06aa6e69820b27cafdfa3defbd73bbae85..091d488138e464528c69fe9fb36b08d6153ff3d4 100644 (file)
@@ -152,11 +152,8 @@ fn push_ident(&mut self, ident: &str) {
         let _ = write!(self.out, "{}", ident.len());
 
         // Write a separating `_` if necessary (leading digit or `_`).
-        match ident.chars().next() {
-            Some('_' | '0'..='9') => {
-                self.push("_");
-            }
-            _ => {}
+        if let Some('_' | '0'..='9') = ident.chars().next() {
+            self.push("_");
         }
 
         self.push(ident);
index 62675665f037f39da3c680db2e7338f6fdc83071..e33dddc4f984183730d669885632f07828704c0d 100644 (file)
@@ -306,11 +306,7 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
     /// # }
     /// ```
     pub fn reserve(&mut self, len: usize, additional: usize) {
-        match self.try_reserve(len, additional) {
-            Err(CapacityOverflow) => capacity_overflow(),
-            Err(AllocError { layout, .. }) => handle_alloc_error(layout),
-            Ok(()) => { /* yay */ }
-        }
+        handle_reserve(self.try_reserve(len, additional));
     }
 
     /// The same as `reserve`, but returns on errors instead of panicking or aborting.
@@ -340,11 +336,7 @@ pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryRe
     ///
     /// Aborts on OOM.
     pub fn reserve_exact(&mut self, len: usize, additional: usize) {
-        match self.try_reserve_exact(len, additional) {
-            Err(CapacityOverflow) => capacity_overflow(),
-            Err(AllocError { layout, .. }) => handle_alloc_error(layout),
-            Ok(()) => { /* yay */ }
-        }
+        handle_reserve(self.try_reserve_exact(len, additional));
     }
 
     /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
@@ -367,11 +359,7 @@ pub fn try_reserve_exact(
     ///
     /// Aborts on OOM.
     pub fn shrink_to_fit(&mut self, amount: usize) {
-        match self.shrink(amount) {
-            Err(CapacityOverflow) => capacity_overflow(),
-            Err(AllocError { layout, .. }) => handle_alloc_error(layout),
-            Ok(()) => { /* yay */ }
-        }
+        handle_reserve(self.shrink(amount));
     }
 }
 
@@ -517,6 +505,16 @@ fn drop(&mut self) {
     }
 }
 
+// Central function for reserve error handling.
+#[inline]
+fn handle_reserve(result: Result<(), TryReserveError>) {
+    match result {
+        Err(CapacityOverflow) => capacity_overflow(),
+        Err(AllocError { layout, .. }) => handle_alloc_error(layout),
+        Ok(()) => { /* yay */ }
+    }
+}
+
 // We need to guarantee the following:
 // * We don't ever allocate `> isize::MAX` byte-size objects.
 // * We don't overflow `usize::MAX` and actually allocate too little.
index fc6d6bcecd7c4ea1b79758af87789e52915aa635..9de0f76cbdd2cdb565add1abd273b7263d7a4e68 100644 (file)
@@ -78,6 +78,7 @@
 #![feature(const_int_pow)]
 #![feature(constctlz)]
 #![feature(const_panic)]
+#![feature(const_pin)]
 #![feature(const_fn_union)]
 #![feature(const_generics)]
 #![feature(const_option)]
index aab0e96d83ab98c6a5b6faf6635bc4bf16580c69..d86939454be5b0c4432dec7fe6c97a90da0c5e48 100644 (file)
 /// be exposed through a public safe API.
 /// Correspondingly, `ManuallyDrop::drop` is unsafe.
 ///
-/// # Examples
+/// # `ManuallyDrop` and drop order.
 ///
-/// This wrapper can be used to enforce a particular drop order on fields, regardless
-/// of how they are defined in the struct:
+/// Rust has a well-defined [drop order] of values. To make sure that fields or
+/// locals are dropped in a specific order, reorder the declarations such that
+/// the implicit drop order is the correct one.
 ///
-/// ```rust
-/// use std::mem::ManuallyDrop;
-/// struct Peach;
-/// struct Banana;
-/// struct Melon;
-/// struct FruitBox {
-///     // Immediately clear there’s something non-trivial going on with these fields.
-///     peach: ManuallyDrop<Peach>,
-///     melon: Melon, // Field that’s independent of the other two.
-///     banana: ManuallyDrop<Banana>,
-/// }
+/// It is possible to use `ManuallyDrop` to control the drop order, but this
+/// requires unsafe code and is hard to do correctly in the presence of
+/// unwinding.
 ///
-/// impl Drop for FruitBox {
-///     fn drop(&mut self) {
-///         unsafe {
-///             // Explicit ordering in which field destructors are run specified in the intuitive
-///             // location â€“ the destructor of the structure containing the fields.
-///             // Moreover, one can now reorder fields within the struct however much they want.
-///             ManuallyDrop::drop(&mut self.peach);
-///             ManuallyDrop::drop(&mut self.banana);
-///         }
-///         // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
-///         // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
-///     }
-/// }
-/// ```
+/// For example, if you want to make sure that a specific field is dropped after
+/// the others, make it the last field of a struct:
 ///
-/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
-/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
-/// would also be leaked.
+/// ```
+/// struct Context;
 ///
-/// In contrast, the automatically-generated compiler drop implementation would have ensured
-/// that all fields are dropped even in the presence of panics. This is especially important when
-/// working with [pinned] data, where reusing the memory without calling the destructor could lead
-/// to Undefined Behaviour.
+/// struct Widget {
+///     children: Vec<Widget>,
+///     // `context` will be dropped after `children`.
+///     // Rust guarantees that fields are dropped in the order of declaration.
+///     context: Context,
+/// }
+/// ```
 ///
+/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
 /// [`mem::zeroed`]: crate::mem::zeroed
 /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
-/// [pinned]: crate::pin
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
index 1cc1dfb01433556f6bf20ad47374af1fbae190e5..9f0284d5d95425e0fd6a3d68ac1a23fd63dd47c5 100644 (file)
@@ -471,9 +471,10 @@ impl<P: Deref<Target: Unpin>> Pin<P> {
     ///
     /// Unlike `Pin::new_unchecked`, this method is safe because the pointer
     /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees.
-    #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn new(pointer: P) -> Pin<P> {
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin", since = "1.33.0")]
+    pub const fn new(pointer: P) -> Pin<P> {
         // SAFETY: the value pointed to is `Unpin`, and so has no requirements
         // around pinning.
         unsafe { Pin::new_unchecked(pointer) }
@@ -483,9 +484,10 @@ pub fn new(pointer: P) -> Pin<P> {
     ///
     /// This requires that the data inside this `Pin` is [`Unpin`] so that we
     /// can ignore the pinning invariants when unwrapping it.
-    #[stable(feature = "pin_into_inner", since = "1.39.0")]
     #[inline(always)]
-    pub fn into_inner(pin: Pin<P>) -> P {
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin_into_inner", since = "1.39.0")]
+    pub const fn into_inner(pin: Pin<P>) -> P {
         pin.pointer
     }
 }
@@ -556,9 +558,10 @@ impl<P: Deref> Pin<P> {
     ///
     /// [`mem::swap`]: crate::mem::swap
     #[lang = "new_unchecked"]
-    #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin", since = "1.33.0")]
+    pub const unsafe fn new_unchecked(pointer: P) -> Pin<P> {
         Pin { pointer }
     }
 
@@ -589,9 +592,10 @@ pub fn as_ref(&self) -> Pin<&P::Target> {
     ///
     /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
     /// instead.
-    #[stable(feature = "pin_into_inner", since = "1.39.0")]
     #[inline(always)]
-    pub unsafe fn into_inner_unchecked(pin: Pin<P>) -> P {
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin_into_inner", since = "1.39.0")]
+    pub const unsafe fn into_inner_unchecked(pin: Pin<P>) -> P {
         pin.pointer
     }
 }
@@ -693,18 +697,20 @@ pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>
     /// with the same lifetime as the original `Pin`.
     ///
     /// ["pinning projections"]: self#projections-and-structural-pinning
-    #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn get_ref(self) -> &'a T {
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin", since = "1.33.0")]
+    pub const fn get_ref(self) -> &'a T {
         self.pointer
     }
 }
 
 impl<'a, T: ?Sized> Pin<&'a mut T> {
     /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
-    #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn into_ref(self) -> Pin<&'a T> {
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin", since = "1.33.0")]
+    pub const fn into_ref(self) -> Pin<&'a T> {
         Pin { pointer: self.pointer }
     }
 
@@ -717,9 +723,10 @@ pub fn into_ref(self) -> Pin<&'a T> {
     /// that lives for as long as the borrow of the `Pin`, not the lifetime of
     /// the `Pin` itself. This method allows turning the `Pin` into a reference
     /// with the same lifetime as the original `Pin`.
-    #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn get_mut(self) -> &'a mut T
+    #[stable(feature = "pin", since = "1.33.0")]
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    pub const fn get_mut(self) -> &'a mut T
     where
         T: Unpin,
     {
@@ -736,9 +743,10 @@ pub fn get_mut(self) -> &'a mut T
     ///
     /// If the underlying data is `Unpin`, `Pin::get_mut` should be used
     /// instead.
-    #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub unsafe fn get_unchecked_mut(self) -> &'a mut T {
+    #[stable(feature = "pin", since = "1.33.0")]
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    pub const unsafe fn get_unchecked_mut(self) -> &'a mut T {
         self.pointer
     }
 
index 4db391f3e567eb69c962c40b7c53264320c5057e..7e75c7cf47bf6b251cfc29ecb309b07c7acb0131 100644 (file)
@@ -43,6 +43,8 @@
 #![feature(iter_order_by)]
 #![feature(cmp_min_max_by)]
 #![feature(iter_map_while)]
+#![feature(const_mut_refs)]
+#![feature(const_pin)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_raw_ptr_deref)]
 #![feature(never_type)]
@@ -79,6 +81,7 @@
 mod ops;
 mod option;
 mod pattern;
+mod pin;
 mod ptr;
 mod result;
 mod slice;
diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs
new file mode 100644 (file)
index 0000000..6f617c8
--- /dev/null
@@ -0,0 +1,31 @@
+use core::pin::Pin;
+
+#[test]
+fn pin_const() {
+    // test that the methods of `Pin` are usable in a const context
+
+    const POINTER: &'static usize = &2;
+
+    const PINNED: Pin<&'static usize> = Pin::new(POINTER);
+    const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) };
+    assert_eq!(PINNED_UNCHECKED, PINNED);
+
+    const INNER: &'static usize = Pin::into_inner(PINNED);
+    assert_eq!(INNER, POINTER);
+
+    const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) };
+    assert_eq!(INNER_UNCHECKED, POINTER);
+
+    const REF: &'static usize = PINNED.get_ref();
+    assert_eq!(REF, POINTER);
+
+    // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context.
+    // A const fn is used because `&mut` is not (yet) usable in constants.
+    const fn pin_mut_const() {
+        let _ = Pin::new(&mut 2).into_ref();
+        let _ = Pin::new(&mut 2).get_mut();
+        let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() };
+    }
+
+    pin_mut_const();
+}
index 9974b65f1e1645452c4ad04773f018540480f531..71ed2d84cad0d5fbcb630e359c7048071cf44fdd 100644 (file)
@@ -586,6 +586,32 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&*self).write(buf)
+    }
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        (&*self).write_vectored(bufs)
+    }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        io::Write::is_write_vectored(&&*self)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        (&*self).flush()
+    }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        (&*self).write_all(buf)
+    }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        (&*self).write_all_vectored(bufs)
+    }
+    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
+        (&*self).write_fmt(args)
+    }
+}
+
+#[stable(feature = "write_mt", since = "1.48.0")]
+impl Write for &Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.lock().write(buf)
     }
@@ -609,6 +635,7 @@ fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
         self.lock().write_fmt(args)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for StdoutLock<'_> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@@ -762,6 +789,32 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for Stderr {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&*self).write(buf)
+    }
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        (&*self).write_vectored(bufs)
+    }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        io::Write::is_write_vectored(&&*self)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        (&*self).flush()
+    }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        (&*self).write_all(buf)
+    }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        (&*self).write_all_vectored(bufs)
+    }
+    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
+        (&*self).write_fmt(args)
+    }
+}
+
+#[stable(feature = "write_mt", since = "1.48.0")]
+impl Write for &Stderr {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.lock().write(buf)
     }
@@ -785,6 +838,7 @@ fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
         self.lock().write_fmt(args)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for StderrLock<'_> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
index 44d2937ee1bf2a1f5bba58c5b60b4fd47563a760..dc05b9648fd6be2bf5a351fecbfdaecafdf7f396 100644 (file)
@@ -254,6 +254,30 @@ fn flush(&mut self) -> io::Result<()> {
     }
 }
 
+#[stable(feature = "write_mt", since = "1.48.0")]
+impl Write for &Sink {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        Ok(buf.len())
+    }
+
+    #[inline]
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum();
+        Ok(total_len)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl fmt::Debug for Sink {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
index 00e2dbc9c1dbf33e5d3c7c94c36edf4b6635f762..9f3796e11ed1aa6a8c8c0c06a28cc926382f95a8 100644 (file)
@@ -249,6 +249,25 @@ pub struct ChildStdin {
 
 #[stable(feature = "process", since = "1.0.0")]
 impl Write for ChildStdin {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&*self).write(buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        (&*self).write_vectored(bufs)
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        io::Write::is_write_vectored(&&*self)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        (&*self).flush()
+    }
+}
+
+#[stable(feature = "write_mt", since = "1.48.0")]
+impl Write for &ChildStdin {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.inner.write(buf)
     }
index a12181be67dd3cc4cdf1457bdc4413e55607c267..31e8c32f062ab4adefcc451d395f154db7e3ef83 100644 (file)
@@ -352,14 +352,22 @@ pub fn build_impl(
         }
     }
 
-    let for_ = if let Some(did) = did.as_local() {
-        let hir_id = tcx.hir().local_def_id_to_hir_id(did);
-        match tcx.hir().expect_item(hir_id).kind {
-            hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx),
-            _ => panic!("did given to build_impl was not an impl"),
+    let impl_item = match did.as_local() {
+        Some(did) => {
+            let hir_id = tcx.hir().local_def_id_to_hir_id(did);
+            match tcx.hir().expect_item(hir_id).kind {
+                hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => {
+                    Some((self_ty, generics, items))
+                }
+                _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
+            }
         }
-    } else {
-        tcx.type_of(did).clean(cx)
+        None => None,
+    };
+
+    let for_ = match impl_item {
+        Some((self_ty, _, _)) => self_ty.clean(cx),
+        None => tcx.type_of(did).clean(cx),
     };
 
     // Only inline impl if the implementing type is
@@ -379,17 +387,12 @@ pub fn build_impl(
     }
 
     let predicates = tcx.explicit_predicates_of(did);
-    let (trait_items, generics) = if let Some(did) = did.as_local() {
-        let hir_id = tcx.hir().local_def_id_to_hir_id(did);
-        match tcx.hir().expect_item(hir_id).kind {
-            hir::ItemKind::Impl { ref generics, ref items, .. } => (
-                items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
-                generics.clean(cx),
-            ),
-            _ => panic!("did given to build_impl was not an impl"),
-        }
-    } else {
-        (
+    let (trait_items, generics) = match impl_item {
+        Some((_, generics, items)) => (
+            items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
+            generics.clean(cx),
+        ),
+        None => (
             tcx.associated_items(did)
                 .in_definition_order()
                 .filter_map(|item| {
@@ -401,7 +404,7 @@ pub fn build_impl(
                 })
                 .collect::<Vec<_>>(),
             clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
-        )
+        ),
     };
     let polarity = tcx.impl_polarity(did);
     let trait_ = associated_trait.clean(cx).map(|bound| match bound {
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs
new file mode 100644 (file)
index 0000000..f58446d
--- /dev/null
@@ -0,0 +1,33 @@
+// NOTE: This test doesn't actually require `fulldeps`
+// so we could instead use it as an `ui` test.
+//
+// Considering that all other `internal-lints` are tested here
+// this seems like the cleaner solution though.
+#![feature(rustc_attrs)]
+#![deny(rustc::ty_pass_by_reference)]
+#![allow(unused)]
+
+#[rustc_diagnostic_item = "TyCtxt"]
+struct TyCtxt<'tcx> {
+    inner: &'tcx (),
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    fn by_value(self) {} // OK
+    fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference
+}
+
+
+struct TyS<'tcx> {
+    inner: &'tcx (),
+}
+
+#[rustc_diagnostic_item = "Ty"]
+type Ty<'tcx> = &'tcx TyS<'tcx>;
+
+impl<'tcx> TyS<'tcx> {
+    fn by_value(self: Ty<'tcx>) {}
+    fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference
+}
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr
new file mode 100644 (file)
index 0000000..b846b30
--- /dev/null
@@ -0,0 +1,20 @@
+error: passing `TyCtxt<'tcx>` by reference
+  --> $DIR/pass_ty_by_ref_self.rs:17:15
+   |
+LL |     fn by_ref(&self) {}
+   |               ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
+   |
+note: the lint level is defined here
+  --> $DIR/pass_ty_by_ref_self.rs:7:9
+   |
+LL | #![deny(rustc::ty_pass_by_reference)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: passing `Ty<'tcx>` by reference
+  --> $DIR/pass_ty_by_ref_self.rs:30:21
+   |
+LL |     fn by_ref(self: &Ty<'tcx>) {}
+   |                     ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs
new file mode 100644 (file)
index 0000000..351d684
--- /dev/null
@@ -0,0 +1,20 @@
+// compile-flags: -Zsave-analysis
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+struct Arr<const N: usize>
+where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression
+{
+}
+
+enum Assert<const CHECK: bool> {}
+
+trait IsTrue {}
+
+impl IsTrue for Assert<true> {}
+
+fn main() {
+    let x: Arr<{usize::max_value()}> = Arr {};
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr
new file mode 100644 (file)
index 0000000..e22612e
--- /dev/null
@@ -0,0 +1,29 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-73260.rs:6:47
+   |
+LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
+   |                                               ^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error[E0308]: mismatched types
+  --> $DIR/issue-73260.rs:17:12
+   |
+LL |     let x: Arr<{usize::max_value()}> = Arr {};
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true`
+   |
+   = note: expected type `false`
+              found type `true`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-73260.rs:17:40
+   |
+LL |     let x: Arr<{usize::max_value()}> = Arr {};
+   |                                        ^^^ expected `false`, found `true`
+   |
+   = note: expected type `false`
+              found type `true`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issues/issue-74634.rs b/src/test/ui/const-generics/issues/issue-74634.rs
new file mode 100644 (file)
index 0000000..0f23fa9
--- /dev/null
@@ -0,0 +1,27 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait If<const COND: bool> {}
+impl If<true> for () {}
+
+trait IsZero<const N: u8> {
+    type Answer;
+}
+
+struct True;
+struct False;
+
+impl<const N: u8> IsZero<N> for ()
+where (): If<{N == 0}> { //~ERROR constant expression
+    type Answer = True;
+}
+
+trait Foobar<const N: u8> {}
+
+impl<const N: u8> Foobar<N> for ()
+where (): IsZero<N, Answer = True> {}
+
+impl<const N: u8> Foobar<N> for ()
+where (): IsZero<N, Answer = False> {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-74634.stderr b/src/test/ui/const-generics/issues/issue-74634.stderr
new file mode 100644 (file)
index 0000000..091a1ac
--- /dev/null
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-74634.rs:15:11
+   |
+LL | where (): If<{N == 0}> {
+   |           ^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs
new file mode 100644 (file)
index 0000000..0a16ca1
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Bool<const B: bool>;
+
+trait True {}
+
+impl True for Bool<true> {}
+
+fn test<T, const P: usize>() where Bool<{core::mem::size_of::<T>() > 4}>: True {
+    todo!()
+}
+
+fn main() {
+    test::<2>();
+    //~^ ERROR wrong number of type
+    //~| ERROR constant expression depends
+}
diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr
new file mode 100644 (file)
index 0000000..2e45759
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0107]: wrong number of type arguments: expected 1, found 0
+  --> $DIR/issue-76595.rs:15:5
+   |
+LL |     test::<2>();
+   |     ^^^^^^^^^ expected 1 type argument
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-76595.rs:15:5
+   |
+LL | fn test<T, const P: usize>() where Bool<{core::mem::size_of::<T>() > 4}>: True {
+   |                                                                           ---- required by this bound in `test`
+...
+LL |     test::<2>();
+   |     ^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
index 768b795ca5b392b8c93b345150bd85b65879ec17..66ea9d5924dfb6157740e1aa7386534e36226f48 100644 (file)
@@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature
    |
 LL |     &mut *(box 0)
    |     ^^^^^^^^^^^^^
-help: skipping check for `const_mut_refs` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/box.rs:10:5
    |
 LL |     &mut *(box 0)
index 7109ffd8b61d783b1c770ad0ce172cb55e03ac79..c6180c1e0041c97bf9b5a77bf958fd5376ad5da1 100644 (file)
@@ -6,17 +6,17 @@ LL |     *OH_YES = 99;
 
 warning: skipping const checks
    |
-help: skipping check for `const_mut_refs` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references.rs:9:26
    |
 LL | static FOO: &&mut u32 = &&mut 42;
    |                          ^^^^^^^
-help: skipping check for `const_mut_refs` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references.rs:13:23
    |
 LL | static BAR: &mut () = &mut ();
    |                       ^^^^^^^
-help: skipping check for `const_mut_refs` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references.rs:18:28
    |
 LL | static BOO: &mut Foo<()> = &mut Foo(());
@@ -26,7 +26,7 @@ help: skipping check that does not even have a feature gate
    |
 LL |     x: &UnsafeCell::new(42),
    |        ^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_mut_refs` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references.rs:30:27
    |
 LL | static OH_YES: &mut i32 = &mut 42;
index 45e7d5a2cc3b3e03bb93d0054c27d2e7a41c499d..7647a9ff4f6e4c69271047dc8a53b8157dad24c8 100644 (file)
@@ -30,7 +30,7 @@ help: skipping check that does not even have a feature gate
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_mut_refs` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:30:25
    |
 LL | const BLUNT: &mut i32 = &mut 42;
diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
new file mode 100644 (file)
index 0000000..651462d
--- /dev/null
@@ -0,0 +1,22 @@
+#![stable(feature = "core", since = "1.6.0")]
+#![feature(staged_api)]
+#![feature(const_precise_live_drops, const_fn)]
+
+enum Either<T, S> {
+    Left(T),
+    Right(S),
+}
+
+impl<T> Either<T, T> {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "foo", since = "1.0.0")]
+    pub const fn unwrap(self) -> T {
+        //~^ ERROR destructors cannot be evaluated at compile-time
+        match self {
+            Self::Left(t) => t,
+            Self::Right(t) => t,
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr
new file mode 100644 (file)
index 0000000..a3f5135
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25
+   |
+LL |     pub const fn unwrap(self) -> T {
+   |                         ^^^^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs
new file mode 100644 (file)
index 0000000..619084e
--- /dev/null
@@ -0,0 +1,23 @@
+// check-pass
+
+#![stable(feature = "core", since = "1.6.0")]
+#![feature(staged_api)]
+#![feature(const_precise_live_drops)]
+
+enum Either<T, S> {
+    Left(T),
+    Right(S),
+}
+
+impl<T> Either<T, T> {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "foo", issue = "none")]
+    pub const fn unwrap(self) -> T {
+        match self {
+            Self::Left(t) => t,
+            Self::Right(t) => t,
+        }
+    }
+}
+
+fn main() {}
index 623551cc07bbb4ba288590180afa449d6c0bcf18..bc3c12eaf981b96f663a1d2b662f7d69b2e2139d 100644 (file)
@@ -6,3 +6,4 @@ LL | #[ffi_const]
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0756`.
index bab6f4e9e5e155835c5ed232f2ac4de8799cbab4..2297257919ee14cbb52fe5e1d42a2a14240bda41 100644 (file)
@@ -2,7 +2,7 @@
 // injected intrinsics by the compiler.
 #![deny(missing_docs)]
 #![allow(dead_code)]
-#![feature(associated_type_defaults)]
+#![feature(associated_type_defaults, extern_types)]
 
 //! Some garbage docs for the crate here
 #![doc="More garbage"]
@@ -183,4 +183,21 @@ pub mod public_interface {
     pub use internal_impl::globbed::*;
 }
 
+extern "C" {
+    /// dox
+    pub fn extern_fn_documented(f: f32) -> f32;
+    pub fn extern_fn_undocumented(f: f32) -> f32;
+    //~^ ERROR: missing documentation for a function
+
+    /// dox
+    pub static EXTERN_STATIC_DOCUMENTED: u8;
+    pub static EXTERN_STATIC_UNDOCUMENTED: u8;
+    //~^ ERROR: missing documentation for a static
+
+    /// dox
+    pub type ExternTyDocumented;
+    pub type ExternTyUndocumented;
+    //~^ ERROR: missing documentation for a foreign type
+}
+
 fn main() {}
index 21da4fae4c161246f6a0ec7446eb27f84b8f43cc..56f8fc10e862320f3e55d899aa4cb7b912c98427 100644 (file)
@@ -118,5 +118,23 @@ error: missing documentation for a function
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: missing documentation for a function
+  --> $DIR/lint-missing-doc.rs:189:5
+   |
+LL |     pub fn extern_fn_undocumented(f: f32) -> f32;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+  --> $DIR/lint-missing-doc.rs:194:5
+   |
+LL |     pub static EXTERN_STATIC_UNDOCUMENTED: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a foreign type
+  --> $DIR/lint-missing-doc.rs:199:5
+   |
+LL |     pub type ExternTyUndocumented;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 22 previous errors