Auto merge of #77039 - ecstatic-morse:rollup-qv3jj4a, r=ecstatic-morse
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`
This commit is contained in:
commit
c2bc344eb2
49 changed files with 763 additions and 323 deletions
|
@ -441,6 +441,7 @@ E0752: include_str!("./error_codes/E0752.md"),
|
||||||
E0753: include_str!("./error_codes/E0753.md"),
|
E0753: include_str!("./error_codes/E0753.md"),
|
||||||
E0754: include_str!("./error_codes/E0754.md"),
|
E0754: include_str!("./error_codes/E0754.md"),
|
||||||
E0755: include_str!("./error_codes/E0755.md"),
|
E0755: include_str!("./error_codes/E0755.md"),
|
||||||
|
E0756: include_str!("./error_codes/E0756.md"),
|
||||||
E0758: include_str!("./error_codes/E0758.md"),
|
E0758: include_str!("./error_codes/E0758.md"),
|
||||||
E0759: include_str!("./error_codes/E0759.md"),
|
E0759: include_str!("./error_codes/E0759.md"),
|
||||||
E0760: include_str!("./error_codes/E0760.md"),
|
E0760: include_str!("./error_codes/E0760.md"),
|
||||||
|
@ -633,7 +634,6 @@ E0774: include_str!("./error_codes/E0774.md"),
|
||||||
E0722, // Malformed `#[optimize]` attribute
|
E0722, // Malformed `#[optimize]` attribute
|
||||||
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
|
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
|
||||||
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
|
// 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]`
|
E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]`
|
||||||
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
|
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
|
||||||
}
|
}
|
||||||
|
|
29
compiler/rustc_error_codes/src/error_codes/E0756.md
Normal file
29
compiler/rustc_error_codes/src/error_codes/E0756.md
Normal file
|
@ -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
|
|
@ -488,18 +488,16 @@ impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
|
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
|
||||||
match t.kind {
|
if let TyKind::TraitObject(
|
||||||
TyKind::TraitObject(
|
poly_trait_refs,
|
||||||
poly_trait_refs,
|
Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
|
||||||
Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
|
) = t.kind
|
||||||
) => {
|
{
|
||||||
for ptr in poly_trait_refs {
|
for ptr in poly_trait_refs {
|
||||||
if Some(self.1) == ptr.trait_ref.trait_def_id() {
|
if Some(self.1) == ptr.trait_ref.trait_def_id() {
|
||||||
self.0.push(ptr.span);
|
self.0.push(ptr.span);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
walk_ty(self, t);
|
walk_ty(self, t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -613,6 +613,19 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<'_>) {
|
fn check_struct_field(&mut self, cx: &LateContext<'_>, sf: &hir::StructField<'_>) {
|
||||||
if !sf.is_positional() {
|
if !sf.is_positional() {
|
||||||
self.check_missing_docs_attrs(
|
self.check_missing_docs_attrs(
|
||||||
|
|
|
@ -5,7 +5,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
|
||||||
use rustc_ast::{Item, ItemKind};
|
use rustc_ast::{Item, ItemKind};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
|
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_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
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> {
|
fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
|
||||||
if let TyKind::Path(qpath) = &ty.kind {
|
if let TyKind::Path(qpath) = &ty.kind {
|
||||||
if let QPath::Resolved(_, path) = qpath {
|
if let QPath::Resolved(_, path) = qpath {
|
||||||
let did = path.res.opt_def_id()?;
|
match path.res {
|
||||||
if cx.tcx.is_diagnostic_item(sym::Ty, did) {
|
Res::Def(_, did) => {
|
||||||
return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
|
if cx.tcx.is_diagnostic_item(sym::Ty, did) {
|
||||||
} else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
|
return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
|
||||||
return Some(format!("TyCtxt{}", 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]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1179,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
|
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();
|
let cname = self.crate_name(LOCAL_CRATE).as_str();
|
||||||
self.sess.consider_optimizing(&cname, msg)
|
self.sess.consider_optimizing(&cname, msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,14 +834,11 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
kind: hir::ItemKind::Impl { items, .. }, ..
|
kind: hir::ItemKind::Impl { items, .. }, ..
|
||||||
})) => {
|
})) => {
|
||||||
for item in &items[..] {
|
for item in &items[..] {
|
||||||
match item.kind {
|
if let hir::AssocItemKind::Type = item.kind {
|
||||||
hir::AssocItemKind::Type => {
|
if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
|
||||||
if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
|
db.span_label(item.span, "expected this associated type");
|
||||||
db.span_label(item.span, "expected this associated type");
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,7 +850,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
|
/// 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`.
|
/// requirement, provide a strucuted suggestion to constrain it to a given type `ty`.
|
||||||
fn constrain_generic_bound_associated_type_structured_suggestion(
|
fn constrain_generic_bound_associated_type_structured_suggestion(
|
||||||
&self,
|
self,
|
||||||
db: &mut DiagnosticBuilder<'_>,
|
db: &mut DiagnosticBuilder<'_>,
|
||||||
trait_ref: &ty::TraitRef<'tcx>,
|
trait_ref: &ty::TraitRef<'tcx>,
|
||||||
bounds: hir::GenericBounds<'_>,
|
bounds: hir::GenericBounds<'_>,
|
||||||
|
@ -877,7 +874,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
/// Given a span corresponding to a bound, provide a structured suggestion to set an
|
/// Given a span corresponding to a bound, provide a structured suggestion to set an
|
||||||
/// associated type to a given type `ty`.
|
/// associated type to a given type `ty`.
|
||||||
fn constrain_associated_type_structured_suggestion(
|
fn constrain_associated_type_structured_suggestion(
|
||||||
&self,
|
self,
|
||||||
db: &mut DiagnosticBuilder<'_>,
|
db: &mut DiagnosticBuilder<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
assoc: &ty::AssocItem,
|
assoc: &ty::AssocItem,
|
||||||
|
|
|
@ -1259,11 +1259,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||||
tcx.layout_raw(param_env.and(normalized))?
|
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)
|
bug!("Layout::compute: unexpected type `{}`", ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Param(_) | ty::Error(_) => {
|
ty::Bound(..) | ty::Param(_) | ty::Error(_) => {
|
||||||
return Err(LayoutError::Unknown(ty));
|
return Err(LayoutError::Unknown(ty));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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.
|
// Iterate all local crate items no matter where they are defined.
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
for item in hir.krate().items.values() {
|
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;
|
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) {
|
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 def_id = local_def_id.to_def_id();
|
||||||
let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
|
let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
|
||||||
|
|
|
@ -549,15 +549,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
};
|
};
|
||||||
// Early-return cases.
|
// Early-return cases.
|
||||||
let val_val = match val.val {
|
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::Error(_) => throw_inval!(TypeckError(ErrorReported)),
|
||||||
ty::ConstKind::Unevaluated(def, substs, promoted) => {
|
ty::ConstKind::Unevaluated(def, substs, promoted) => {
|
||||||
let instance = self.resolve(def, substs)?;
|
let instance = self.resolve(def, substs)?;
|
||||||
return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
|
return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
|
||||||
}
|
}
|
||||||
ty::ConstKind::Infer(..)
|
ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
|
||||||
| ty::ConstKind::Bound(..)
|
|
||||||
| ty::ConstKind::Placeholder(..) => {
|
|
||||||
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
|
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
|
||||||
}
|
}
|
||||||
ty::ConstKind::Value(val_val) => val_val,
|
ty::ConstKind::Value(val_val) => val_val,
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
|
//! 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.
|
//! it finds operations that are invalid in a certain context.
|
||||||
|
|
||||||
|
use rustc_attr as attr;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
pub use self::qualifs::Qualif;
|
pub use self::qualifs::Qualif;
|
||||||
|
|
||||||
|
@ -55,3 +57,9 @@ impl ConstCx<'mir, 'tcx> {
|
||||||
pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
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()
|
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))
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Concrete error types for all operations which may be invalid in a certain const context.
|
//! 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 as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_session::config::nightly_options;
|
use rustc_session::config::nightly_options;
|
||||||
|
@ -14,35 +14,54 @@ use super::ConstCx;
|
||||||
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
|
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
|
||||||
debug!("illegal_op: op={:?}", op);
|
debug!("illegal_op: op={:?}", op);
|
||||||
|
|
||||||
if op.is_allowed_in_item(ccx) {
|
let gate = match op.status_in_item(ccx) {
|
||||||
return;
|
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 {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
op.emit_error(ccx, span);
|
op.emit_error(ccx, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Status {
|
||||||
|
Allowed,
|
||||||
|
Unstable(Symbol),
|
||||||
|
Forbidden,
|
||||||
|
}
|
||||||
|
|
||||||
/// An operation that is not *always* allowed in a const context.
|
/// An operation that is not *always* allowed in a const context.
|
||||||
pub trait NonConstOp: std::fmt::Debug {
|
pub trait NonConstOp: std::fmt::Debug {
|
||||||
/// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
|
/// Returns an enum indicating whether this operation is allowed within the given item.
|
||||||
/// or `None` if such a feature gate does not exist.
|
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
fn feature_gate() -> Option<Symbol> {
|
Status::Forbidden
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -53,9 +72,13 @@ pub trait NonConstOp: std::fmt::Debug {
|
||||||
"{} contains unimplemented expression type",
|
"{} contains unimplemented expression type",
|
||||||
ccx.const_kind()
|
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()) {
|
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||||
err.note(
|
err.note(
|
||||||
"A function call isn't allowed in the const's initialization expression \
|
"A function call isn't allowed in the const's initialization expression \
|
||||||
|
@ -147,7 +170,9 @@ pub struct InlineAsm;
|
||||||
impl NonConstOp for InlineAsm {}
|
impl NonConstOp for InlineAsm {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LiveDrop(pub Option<Span>);
|
pub struct LiveDrop {
|
||||||
|
pub dropped_at: Option<Span>,
|
||||||
|
}
|
||||||
impl NonConstOp for LiveDrop {
|
impl NonConstOp for LiveDrop {
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
let mut diagnostic = struct_span_err!(
|
let mut diagnostic = struct_span_err!(
|
||||||
|
@ -157,7 +182,7 @@ impl NonConstOp for LiveDrop {
|
||||||
"destructors cannot be evaluated at compile-time"
|
"destructors cannot be evaluated at compile-time"
|
||||||
);
|
);
|
||||||
diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
|
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.span_label(span, "value is dropped here");
|
||||||
}
|
}
|
||||||
diagnostic.emit();
|
diagnostic.emit();
|
||||||
|
@ -182,14 +207,13 @@ impl NonConstOp for CellBorrow {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MutBorrow;
|
pub struct MutBorrow;
|
||||||
impl NonConstOp for MutBorrow {
|
impl NonConstOp for MutBorrow {
|
||||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
// Forbid everywhere except in const fn
|
// Forbid everywhere except in const fn with a feature gate
|
||||||
ccx.const_kind() == hir::ConstContext::ConstFn
|
if ccx.const_kind() == hir::ConstContext::ConstFn {
|
||||||
&& ccx.tcx.features().enabled(Self::feature_gate().unwrap())
|
Status::Unstable(sym::const_mut_refs)
|
||||||
}
|
} else {
|
||||||
|
Status::Forbidden
|
||||||
fn feature_gate() -> Option<Symbol> {
|
}
|
||||||
Some(sym::const_mut_refs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -201,15 +225,16 @@ impl NonConstOp for MutBorrow {
|
||||||
&format!("mutable references are not allowed in {}s", ccx.const_kind()),
|
&format!("mutable references are not allowed in {}s", ccx.const_kind()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
ccx.tcx.sess,
|
ccx.tcx.sess,
|
||||||
span,
|
span,
|
||||||
E0764,
|
E0764,
|
||||||
"mutable references are not allowed in {}s",
|
"mutable references are not allowed in {}s",
|
||||||
ccx.const_kind(),
|
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()) {
|
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||||
err.note(
|
err.note(
|
||||||
"References in statics and constants may only refer \
|
"References in statics and constants may only refer \
|
||||||
|
@ -226,11 +251,17 @@ impl NonConstOp for MutBorrow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MutAddressOf;
|
pub struct MutAddressOf;
|
||||||
impl NonConstOp for MutAddressOf {
|
impl NonConstOp for MutAddressOf {
|
||||||
fn feature_gate() -> Option<Symbol> {
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
Some(sym::const_mut_refs)
|
// 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) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -247,16 +278,16 @@ impl NonConstOp for MutAddressOf {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MutDeref;
|
pub struct MutDeref;
|
||||||
impl NonConstOp for MutDeref {
|
impl NonConstOp for MutDeref {
|
||||||
fn feature_gate() -> Option<Symbol> {
|
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||||
Some(sym::const_mut_refs)
|
Status::Unstable(sym::const_mut_refs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Panic;
|
pub struct Panic;
|
||||||
impl NonConstOp for Panic {
|
impl NonConstOp for Panic {
|
||||||
fn feature_gate() -> Option<Symbol> {
|
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||||
Some(sym::const_panic)
|
Status::Unstable(sym::const_panic)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -289,8 +320,8 @@ impl NonConstOp for RawPtrComparison {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RawPtrDeref;
|
pub struct RawPtrDeref;
|
||||||
impl NonConstOp for RawPtrDeref {
|
impl NonConstOp for RawPtrDeref {
|
||||||
fn feature_gate() -> Option<Symbol> {
|
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||||
Some(sym::const_raw_ptr_deref)
|
Status::Unstable(sym::const_raw_ptr_deref)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -307,8 +338,8 @@ impl NonConstOp for RawPtrDeref {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RawPtrToIntCast;
|
pub struct RawPtrToIntCast;
|
||||||
impl NonConstOp for RawPtrToIntCast {
|
impl NonConstOp for RawPtrToIntCast {
|
||||||
fn feature_gate() -> Option<Symbol> {
|
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||||
Some(sym::const_raw_ptr_to_usize_cast)
|
Status::Unstable(sym::const_raw_ptr_to_usize_cast)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -326,8 +357,12 @@ impl NonConstOp for RawPtrToIntCast {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StaticAccess;
|
pub struct StaticAccess;
|
||||||
impl NonConstOp for StaticAccess {
|
impl NonConstOp for StaticAccess {
|
||||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
matches!(ccx.const_kind(), hir::ConstContext::Static(_))
|
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
||||||
|
Status::Allowed
|
||||||
|
} else {
|
||||||
|
Status::Forbidden
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
@ -371,14 +406,13 @@ impl NonConstOp for ThreadLocalAccess {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UnionAccess;
|
pub struct UnionAccess;
|
||||||
impl NonConstOp for 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`.
|
// Union accesses are stable in all contexts except `const fn`.
|
||||||
ccx.const_kind() != hir::ConstContext::ConstFn
|
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||||
|| ccx.tcx.features().enabled(Self::feature_gate().unwrap())
|
Status::Allowed
|
||||||
}
|
} else {
|
||||||
|
Status::Unstable(sym::const_fn_union)
|
||||||
fn feature_gate() -> Option<Symbol> {
|
}
|
||||||
Some(sym::const_fn_union)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::Span;
|
use rustc_span::{sym, Span};
|
||||||
|
|
||||||
use super::ops;
|
use super::ops;
|
||||||
use super::qualifs::{NeedsDrop, Qualif};
|
use super::qualifs::{NeedsDrop, Qualif};
|
||||||
|
@ -11,7 +11,12 @@ use super::ConstCx;
|
||||||
|
|
||||||
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
||||||
/// elaboration.
|
/// 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
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checking_enabled(tcx) {
|
if !checking_enabled(tcx, def_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +57,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
|
||||||
|
|
||||||
impl CheckLiveDrops<'mir, 'tcx> {
|
impl CheckLiveDrops<'mir, 'tcx> {
|
||||||
fn check_live_drop(&self, span: Span) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -551,7 +551,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
||||||
// If we are checking live drops after drop-elaboration, don't emit duplicate
|
// If we are checking live drops after drop-elaboration, don't emit duplicate
|
||||||
// errors here.
|
// errors here.
|
||||||
if super::post_drop_elaboration::checking_enabled(self.tcx) {
|
if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,7 +576,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
|
|
||||||
if needs_drop {
|
if needs_drop {
|
||||||
self.check_op_spanned(
|
self.check_op_spanned(
|
||||||
ops::LiveDrop(Some(terminator.source_info.span)),
|
ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
|
||||||
err_span,
|
err_span,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,11 +242,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
TerminatorKind::InlineAsm { ref operands, .. } => {
|
TerminatorKind::InlineAsm { ref operands, .. } => {
|
||||||
for (index, op) in operands.iter().enumerate() {
|
for (index, op) in operands.iter().enumerate() {
|
||||||
match op {
|
if let InlineAsmOperand::Const { .. } = op {
|
||||||
InlineAsmOperand::Const { .. } => {
|
self.candidates.push(Candidate::InlineAsm { bb: location.block, index })
|
||||||
self.candidates.push(Candidate::InlineAsm { bb: location.block, index })
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -612,12 +609,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
let operand_ty = operand.ty(self.body, self.tcx);
|
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_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");
|
let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
|
||||||
match (cast_in, cast_out) {
|
if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
|
||||||
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
|
// ptr-to-int casts are not possible in consts and thus not promotable
|
||||||
// ptr-to-int casts are not possible in consts and thus not promotable
|
return Err(Unpromotable);
|
||||||
return Err(Unpromotable);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use rustc_attr as attr;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::*;
|
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
|
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
|
||||||
// opt-in via `allow_internal_unstable`.
|
// opt-in via `allow_internal_unstable`.
|
||||||
attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
|
super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate)
|
||||||
.map_or(false, |mut features| features.any(|name| name == feature_gate))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`.
|
/// 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
|
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
|
||||||
// opt-in via `allow_internal_unstable`.
|
// opt-in via `allow_internal_unstable`.
|
||||||
attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
|
super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate)
|
||||||
.map_or(false, |mut features| features.any(|name| name == feature_gate))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_terminator(
|
fn check_terminator(
|
||||||
|
|
|
@ -149,12 +149,9 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match (open_brace, delim) {
|
//only add braces
|
||||||
//only add braces
|
if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) {
|
||||||
(DelimToken::Brace, DelimToken::Brace) => {
|
self.matching_block_spans.push((open_brace_span, close_brace_span));
|
||||||
self.matching_block_spans.push((open_brace_span, close_brace_span));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.open_braces.is_empty() {
|
if self.open_braces.is_empty() {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(bindings_after_at)]
|
#![feature(bindings_after_at)]
|
||||||
|
#![feature(iter_order_by)]
|
||||||
#![feature(or_patterns)]
|
#![feature(or_patterns)]
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
@ -459,14 +460,10 @@ pub fn tokenstream_probably_equal_for_proc_macro(
|
||||||
|
|
||||||
// Break tokens after we expand any nonterminals, so that we break tokens
|
// Break tokens after we expand any nonterminals, so that we break tokens
|
||||||
// that are produced as a result of nonterminal expansion.
|
// 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 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);
|
let 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) {
|
t1.eq_by(t2, |t1, t2| tokentree_probably_equal_for_proc_macro(&t1, &t2, sess))
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t1.next().is_none() && t2.next().is_none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// See comments in `Nonterminal::to_tokenstream` for why we care about
|
// See comments in `Nonterminal::to_tokenstream` for why we care about
|
||||||
|
|
|
@ -525,12 +525,9 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// fill character
|
// fill character
|
||||||
if let Some(&(_, c)) = self.cur.peek() {
|
if let Some(&(_, c)) = self.cur.peek() {
|
||||||
match self.cur.clone().nth(1) {
|
if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) {
|
||||||
Some((_, '>' | '<' | '^')) => {
|
spec.fill = Some(c);
|
||||||
spec.fill = Some(c);
|
self.cur.next();
|
||||||
self.cur.next();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Alignment
|
// Alignment
|
||||||
|
|
|
@ -534,11 +534,8 @@ impl<'a> ModuleData<'a> {
|
||||||
if ns != TypeNS {
|
if ns != TypeNS {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match binding.res() {
|
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() {
|
||||||
Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
|
collected_traits.push((name, binding))
|
||||||
collected_traits.push((name, binding))
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*traits = Some(collected_traits.into_boxed_slice());
|
*traits = Some(collected_traits.into_boxed_slice());
|
||||||
|
|
|
@ -1558,58 +1558,71 @@ pub trait Pos {
|
||||||
fn to_u32(&self) -> u32;
|
fn to_u32(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A byte offset. Keep this small (currently 32-bits), as AST contains
|
macro_rules! impl_pos {
|
||||||
/// a lot of them.
|
(
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
$(
|
||||||
pub struct BytePos(pub u32);
|
$(#[$attr:meta])*
|
||||||
|
$vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty);
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
$(#[$attr])*
|
||||||
|
$vis struct $ident($inner_vis $inner_ty);
|
||||||
|
|
||||||
/// A character offset. Because of multibyte UTF-8 characters, a byte offset
|
impl Pos for $ident {
|
||||||
/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
|
#[inline(always)]
|
||||||
/// values to `CharPos` values as necessary.
|
fn from_usize(n: usize) -> $ident {
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
$ident(n as $inner_ty)
|
||||||
pub struct CharPos(pub usize);
|
}
|
||||||
|
|
||||||
// FIXME: lots of boilerplate in these impls, but so far my attempts to fix
|
#[inline(always)]
|
||||||
// have been unsuccessful.
|
fn to_usize(&self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
|
||||||
impl Pos for BytePos {
|
#[inline(always)]
|
||||||
#[inline(always)]
|
fn from_u32(n: u32) -> $ident {
|
||||||
fn from_usize(n: usize) -> BytePos {
|
$ident(n as $inner_ty)
|
||||||
BytePos(n as u32)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_usize(&self) -> usize {
|
fn to_u32(&self) -> u32 {
|
||||||
self.0 as usize
|
self.0 as u32
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
impl Add for $ident {
|
||||||
fn from_u32(n: u32) -> BytePos {
|
type Output = $ident;
|
||||||
BytePos(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_u32(&self) -> u32 {
|
fn add(self, rhs: $ident) -> $ident {
|
||||||
self.0
|
$ident(self.0 + rhs.0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for $ident {
|
||||||
|
type Output = $ident;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn sub(self, rhs: $ident) -> $ident {
|
||||||
|
$ident(self.0 - rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for BytePos {
|
impl_pos! {
|
||||||
type Output = BytePos;
|
/// 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)]
|
/// A character offset. Because of multibyte UTF-8 characters, a byte offset
|
||||||
fn add(self, rhs: BytePos) -> BytePos {
|
/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
|
||||||
BytePos((self.to_usize() + rhs.to_usize()) as u32)
|
/// values to `CharPos` values as necessary.
|
||||||
}
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
}
|
pub struct CharPos(pub usize);
|
||||||
|
|
||||||
impl Sub for BytePos {
|
|
||||||
type Output = BytePos;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn sub(self, rhs: BytePos) -> BytePos {
|
|
||||||
BytePos((self.to_usize() - rhs.to_usize()) as u32)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
|
impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
|
||||||
|
@ -1624,46 +1637,6 @@ impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Loc, SourceFileAndLine, SourceFileAndBytePos
|
||||||
//
|
//
|
||||||
|
|
|
@ -152,11 +152,8 @@ impl SymbolMangler<'tcx> {
|
||||||
let _ = write!(self.out, "{}", ident.len());
|
let _ = write!(self.out, "{}", ident.len());
|
||||||
|
|
||||||
// Write a separating `_` if necessary (leading digit or `_`).
|
// Write a separating `_` if necessary (leading digit or `_`).
|
||||||
match ident.chars().next() {
|
if let Some('_' | '0'..='9') = ident.chars().next() {
|
||||||
Some('_' | '0'..='9') => {
|
self.push("_");
|
||||||
self.push("_");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push(ident);
|
self.push(ident);
|
||||||
|
|
|
@ -306,11 +306,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn reserve(&mut self, len: usize, additional: usize) {
|
pub fn reserve(&mut self, len: usize, additional: usize) {
|
||||||
match self.try_reserve(len, additional) {
|
handle_reserve(self.try_reserve(len, additional));
|
||||||
Err(CapacityOverflow) => capacity_overflow(),
|
|
||||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
|
||||||
Ok(()) => { /* yay */ }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
|
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
|
||||||
|
@ -340,11 +336,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||||
///
|
///
|
||||||
/// Aborts on OOM.
|
/// Aborts on OOM.
|
||||||
pub fn reserve_exact(&mut self, len: usize, additional: usize) {
|
pub fn reserve_exact(&mut self, len: usize, additional: usize) {
|
||||||
match self.try_reserve_exact(len, additional) {
|
handle_reserve(self.try_reserve_exact(len, additional));
|
||||||
Err(CapacityOverflow) => capacity_overflow(),
|
|
||||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
|
||||||
Ok(()) => { /* yay */ }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
|
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
|
||||||
|
@ -367,11 +359,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||||
///
|
///
|
||||||
/// Aborts on OOM.
|
/// Aborts on OOM.
|
||||||
pub fn shrink_to_fit(&mut self, amount: usize) {
|
pub fn shrink_to_fit(&mut self, amount: usize) {
|
||||||
match self.shrink(amount) {
|
handle_reserve(self.shrink(amount));
|
||||||
Err(CapacityOverflow) => capacity_overflow(),
|
|
||||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
|
||||||
Ok(()) => { /* yay */ }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +505,16 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec<T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 need to guarantee the following:
|
||||||
// * We don't ever allocate `> isize::MAX` byte-size objects.
|
// * We don't ever allocate `> isize::MAX` byte-size objects.
|
||||||
// * We don't overflow `usize::MAX` and actually allocate too little.
|
// * We don't overflow `usize::MAX` and actually allocate too little.
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
#![feature(const_int_pow)]
|
#![feature(const_int_pow)]
|
||||||
#![feature(constctlz)]
|
#![feature(constctlz)]
|
||||||
#![feature(const_panic)]
|
#![feature(const_panic)]
|
||||||
|
#![feature(const_pin)]
|
||||||
#![feature(const_fn_union)]
|
#![feature(const_fn_union)]
|
||||||
#![feature(const_generics)]
|
#![feature(const_generics)]
|
||||||
#![feature(const_option)]
|
#![feature(const_option)]
|
||||||
|
|
|
@ -15,50 +15,33 @@ use crate::ptr;
|
||||||
/// be exposed through a public safe API.
|
/// be exposed through a public safe API.
|
||||||
/// Correspondingly, `ManuallyDrop::drop` is unsafe.
|
/// Correspondingly, `ManuallyDrop::drop` is unsafe.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # `ManuallyDrop` and drop order.
|
||||||
///
|
///
|
||||||
/// This wrapper can be used to enforce a particular drop order on fields, regardless
|
/// Rust has a well-defined [drop order] of values. To make sure that fields or
|
||||||
/// of how they are defined in the struct:
|
/// locals are dropped in a specific order, reorder the declarations such that
|
||||||
|
/// the implicit drop order is the correct one.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// It is possible to use `ManuallyDrop` to control the drop order, but this
|
||||||
/// use std::mem::ManuallyDrop;
|
/// requires unsafe code and is hard to do correctly in the presence of
|
||||||
/// struct Peach;
|
/// unwinding.
|
||||||
/// 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>,
|
|
||||||
/// }
|
|
||||||
///
|
///
|
||||||
/// impl Drop for FruitBox {
|
/// For example, if you want to make sure that a specific field is dropped after
|
||||||
/// fn drop(&mut self) {
|
/// the others, make it the last field of a struct:
|
||||||
/// unsafe {
|
///
|
||||||
/// // Explicit ordering in which field destructors are run specified in the intuitive
|
/// ```
|
||||||
/// // location – the destructor of the structure containing the fields.
|
/// struct Context;
|
||||||
/// // Moreover, one can now reorder fields within the struct however much they want.
|
///
|
||||||
/// ManuallyDrop::drop(&mut self.peach);
|
/// struct Widget {
|
||||||
/// ManuallyDrop::drop(&mut self.banana);
|
/// children: Vec<Widget>,
|
||||||
/// }
|
/// // `context` will be dropped after `children`.
|
||||||
/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
|
/// // Rust guarantees that fields are dropped in the order of declaration.
|
||||||
/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
|
/// context: Context,
|
||||||
/// }
|
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
|
/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
|
||||||
/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
|
|
||||||
/// would also be leaked.
|
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// [`mem::zeroed`]: crate::mem::zeroed
|
/// [`mem::zeroed`]: crate::mem::zeroed
|
||||||
/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
|
/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
|
||||||
/// [pinned]: crate::pin
|
|
||||||
#[stable(feature = "manually_drop", since = "1.20.0")]
|
#[stable(feature = "manually_drop", since = "1.20.0")]
|
||||||
#[lang = "manually_drop"]
|
#[lang = "manually_drop"]
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
|
|
@ -471,9 +471,10 @@ impl<P: Deref<Target: Unpin>> Pin<P> {
|
||||||
///
|
///
|
||||||
/// Unlike `Pin::new_unchecked`, this method is safe because the pointer
|
/// Unlike `Pin::new_unchecked`, this method is safe because the pointer
|
||||||
/// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees.
|
/// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees.
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
|
||||||
#[inline(always)]
|
#[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
|
// SAFETY: the value pointed to is `Unpin`, and so has no requirements
|
||||||
// around pinning.
|
// around pinning.
|
||||||
unsafe { Pin::new_unchecked(pointer) }
|
unsafe { Pin::new_unchecked(pointer) }
|
||||||
|
@ -483,9 +484,10 @@ impl<P: Deref<Target: Unpin>> Pin<P> {
|
||||||
///
|
///
|
||||||
/// This requires that the data inside this `Pin` is [`Unpin`] so that we
|
/// This requires that the data inside this `Pin` is [`Unpin`] so that we
|
||||||
/// can ignore the pinning invariants when unwrapping it.
|
/// can ignore the pinning invariants when unwrapping it.
|
||||||
#[stable(feature = "pin_into_inner", since = "1.39.0")]
|
|
||||||
#[inline(always)]
|
#[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
|
pin.pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,9 +558,10 @@ impl<P: Deref> Pin<P> {
|
||||||
///
|
///
|
||||||
/// [`mem::swap`]: crate::mem::swap
|
/// [`mem::swap`]: crate::mem::swap
|
||||||
#[lang = "new_unchecked"]
|
#[lang = "new_unchecked"]
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
|
||||||
#[inline(always)]
|
#[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 }
|
Pin { pointer }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,9 +592,10 @@ impl<P: Deref> Pin<P> {
|
||||||
///
|
///
|
||||||
/// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
|
/// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
|
||||||
/// instead.
|
/// instead.
|
||||||
#[stable(feature = "pin_into_inner", since = "1.39.0")]
|
|
||||||
#[inline(always)]
|
#[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
|
pin.pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,18 +697,20 @@ impl<'a, T: ?Sized> Pin<&'a T> {
|
||||||
/// with the same lifetime as the original `Pin`.
|
/// with the same lifetime as the original `Pin`.
|
||||||
///
|
///
|
||||||
/// ["pinning projections"]: self#projections-and-structural-pinning
|
/// ["pinning projections"]: self#projections-and-structural-pinning
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
|
||||||
#[inline(always)]
|
#[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
|
self.pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: ?Sized> Pin<&'a mut T> {
|
impl<'a, T: ?Sized> Pin<&'a mut T> {
|
||||||
/// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
|
/// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
|
||||||
#[inline(always)]
|
#[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 }
|
Pin { pointer: self.pointer }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
|
||||||
/// that lives for as long as the borrow of the `Pin`, not the lifetime of
|
/// 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
|
/// the `Pin` itself. This method allows turning the `Pin` into a reference
|
||||||
/// with the same lifetime as the original `Pin`.
|
/// with the same lifetime as the original `Pin`.
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
|
||||||
#[inline(always)]
|
#[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
|
where
|
||||||
T: Unpin,
|
T: Unpin,
|
||||||
{
|
{
|
||||||
|
@ -736,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
|
||||||
///
|
///
|
||||||
/// If the underlying data is `Unpin`, `Pin::get_mut` should be used
|
/// If the underlying data is `Unpin`, `Pin::get_mut` should be used
|
||||||
/// instead.
|
/// instead.
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
|
||||||
#[inline(always)]
|
#[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
|
self.pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
#![feature(iter_order_by)]
|
#![feature(iter_order_by)]
|
||||||
#![feature(cmp_min_max_by)]
|
#![feature(cmp_min_max_by)]
|
||||||
#![feature(iter_map_while)]
|
#![feature(iter_map_while)]
|
||||||
|
#![feature(const_mut_refs)]
|
||||||
|
#![feature(const_pin)]
|
||||||
#![feature(const_slice_from_raw_parts)]
|
#![feature(const_slice_from_raw_parts)]
|
||||||
#![feature(const_raw_ptr_deref)]
|
#![feature(const_raw_ptr_deref)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
@ -79,6 +81,7 @@ mod num;
|
||||||
mod ops;
|
mod ops;
|
||||||
mod option;
|
mod option;
|
||||||
mod pattern;
|
mod pattern;
|
||||||
|
mod pin;
|
||||||
mod ptr;
|
mod ptr;
|
||||||
mod result;
|
mod result;
|
||||||
mod slice;
|
mod slice;
|
||||||
|
|
31
library/core/tests/pin.rs
Normal file
31
library/core/tests/pin.rs
Normal file
|
@ -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();
|
||||||
|
}
|
|
@ -586,6 +586,32 @@ impl fmt::Debug for Stdout {
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Write for Stdout {
|
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> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.lock().write(buf)
|
self.lock().write(buf)
|
||||||
}
|
}
|
||||||
|
@ -609,6 +635,7 @@ impl Write for Stdout {
|
||||||
self.lock().write_fmt(args)
|
self.lock().write_fmt(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Write for StdoutLock<'_> {
|
impl Write for StdoutLock<'_> {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
@ -762,6 +789,32 @@ impl fmt::Debug for Stderr {
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Write for Stderr {
|
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> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.lock().write(buf)
|
self.lock().write(buf)
|
||||||
}
|
}
|
||||||
|
@ -785,6 +838,7 @@ impl Write for Stderr {
|
||||||
self.lock().write_fmt(args)
|
self.lock().write_fmt(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Write for StderrLock<'_> {
|
impl Write for StderrLock<'_> {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
|
|
@ -254,6 +254,30 @@ impl Write for Sink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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")]
|
#[stable(feature = "std_debug", since = "1.16.0")]
|
||||||
impl fmt::Debug for Sink {
|
impl fmt::Debug for Sink {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
|
|
@ -249,6 +249,25 @@ pub struct ChildStdin {
|
||||||
|
|
||||||
#[stable(feature = "process", since = "1.0.0")]
|
#[stable(feature = "process", since = "1.0.0")]
|
||||||
impl Write for ChildStdin {
|
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> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.inner.write(buf)
|
self.inner.write(buf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,14 +352,22 @@ pub fn build_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let for_ = if let Some(did) = did.as_local() {
|
let impl_item = match did.as_local() {
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
|
Some(did) => {
|
||||||
match tcx.hir().expect_item(hir_id).kind {
|
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
|
||||||
hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx),
|
match tcx.hir().expect_item(hir_id).kind {
|
||||||
_ => panic!("did given to build_impl was not an impl"),
|
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 {
|
None => None,
|
||||||
tcx.type_of(did).clean(cx)
|
};
|
||||||
|
|
||||||
|
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
|
// Only inline impl if the implementing type is
|
||||||
|
@ -379,17 +387,12 @@ pub fn build_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
let predicates = tcx.explicit_predicates_of(did);
|
let predicates = tcx.explicit_predicates_of(did);
|
||||||
let (trait_items, generics) = if let Some(did) = did.as_local() {
|
let (trait_items, generics) = match impl_item {
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
|
Some((_, generics, items)) => (
|
||||||
match tcx.hir().expect_item(hir_id).kind {
|
items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
|
||||||
hir::ItemKind::Impl { ref generics, ref items, .. } => (
|
generics.clean(cx),
|
||||||
items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
|
),
|
||||||
generics.clean(cx),
|
None => (
|
||||||
),
|
|
||||||
_ => panic!("did given to build_impl was not an impl"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
tcx.associated_items(did)
|
tcx.associated_items(did)
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
|
@ -401,7 +404,7 @@ pub fn build_impl(
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
|
clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
|
||||||
)
|
),
|
||||||
};
|
};
|
||||||
let polarity = tcx.impl_polarity(did);
|
let polarity = tcx.impl_polarity(did);
|
||||||
let trait_ = associated_trait.clean(cx).map(|bound| match bound {
|
let trait_ = associated_trait.clean(cx).map(|bound| match bound {
|
||||||
|
|
33
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs
Normal file
33
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs
Normal file
|
@ -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() {}
|
|
@ -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
|
||||||
|
|
20
src/test/ui/const-generics/issues/issue-73260.rs
Normal file
20
src/test/ui/const-generics/issues/issue-73260.rs
Normal file
|
@ -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
|
||||||
|
}
|
29
src/test/ui/const-generics/issues/issue-73260.stderr
Normal file
29
src/test/ui/const-generics/issues/issue-73260.stderr
Normal file
|
@ -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`.
|
27
src/test/ui/const-generics/issues/issue-74634.rs
Normal file
27
src/test/ui/const-generics/issues/issue-74634.rs
Normal file
|
@ -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() {}
|
10
src/test/ui/const-generics/issues/issue-74634.stderr
Normal file
10
src/test/ui/const-generics/issues/issue-74634.stderr
Normal file
|
@ -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
|
||||||
|
|
18
src/test/ui/const-generics/issues/issue-76595.rs
Normal file
18
src/test/ui/const-generics/issues/issue-76595.rs
Normal file
|
@ -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
|
||||||
|
}
|
20
src/test/ui/const-generics/issues/issue-76595.stderr
Normal file
20
src/test/ui/const-generics/issues/issue-76595.stderr
Normal file
|
@ -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`.
|
|
@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature
|
||||||
|
|
|
|
||||||
LL | &mut *(box 0)
|
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
|
--> $DIR/box.rs:10:5
|
||||||
|
|
|
|
||||||
LL | &mut *(box 0)
|
LL | &mut *(box 0)
|
||||||
|
|
|
@ -6,17 +6,17 @@ LL | *OH_YES = 99;
|
||||||
|
|
||||||
warning: skipping const checks
|
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
|
--> $DIR/mutable_references.rs:9:26
|
||||||
|
|
|
|
||||||
LL | static FOO: &&mut u32 = &&mut 42;
|
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
|
--> $DIR/mutable_references.rs:13:23
|
||||||
|
|
|
|
||||||
LL | static BAR: &mut () = &mut ();
|
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
|
--> $DIR/mutable_references.rs:18:28
|
||||||
|
|
|
|
||||||
LL | static BOO: &mut Foo<()> = &mut Foo(());
|
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),
|
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
|
--> $DIR/mutable_references.rs:30:27
|
||||||
|
|
|
|
||||||
LL | static OH_YES: &mut i32 = &mut 42;
|
LL | static OH_YES: &mut i32 = &mut 42;
|
||||||
|
|
|
@ -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) };
|
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
|
--> $DIR/mutable_references_err.rs:30:25
|
||||||
|
|
|
|
||||||
LL | const BLUNT: &mut i32 = &mut 42;
|
LL | const BLUNT: &mut i32 = &mut 42;
|
||||||
|
|
22
src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
Normal file
22
src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
Normal file
|
@ -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() {}
|
|
@ -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`.
|
23
src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs
Normal file
23
src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs
Normal file
|
@ -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() {}
|
|
@ -6,3 +6,4 @@ LL | #[ffi_const]
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0756`.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// injected intrinsics by the compiler.
|
// injected intrinsics by the compiler.
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults, extern_types)]
|
||||||
|
|
||||||
//! Some garbage docs for the crate here
|
//! Some garbage docs for the crate here
|
||||||
#![doc="More garbage"]
|
#![doc="More garbage"]
|
||||||
|
@ -183,4 +183,21 @@ pub mod public_interface {
|
||||||
pub use internal_impl::globbed::*;
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -118,5 +118,23 @@ error: missing documentation for a function
|
||||||
LL | pub fn also_undocumented1() {}
|
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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue