//! Compiler intrinsics.
//!
//! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`.
+//! The corresponding const implementations are in `librustc_mir/interpret/intrinsics.rs`
+//!
+//! # Const intrinsics
+//!
+//! Note: any changes to the constness of intrinsics should be discussed with the language team.
+//! This includes changes in the stability of the constness.
+//!
+//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
+//! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to
+//! `librustc_mir/interpret/intrinsics.rs` and add a
+//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
+//!
+//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
+//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
+//! without T-lang consulation, because it bakes a feature into the language that cannot be
+//! replicated in user code without compiler support.
//!
//! # Volatiles
//!
///
/// The stabilized version of this intrinsic is
/// [`std::mem::size_of`](../../std/mem/fn.size_of.html).
+ #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
pub fn size_of<T>() -> usize;
/// Moves a value to an uninitialized memory location.
/// Drop glue is not run on the destination.
pub fn move_val_init<T>(dst: *mut T, src: T);
+ #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
pub fn min_align_of<T>() -> usize;
+ #[rustc_const_unstable(feature = "const_pref_align_of", issue = "0")]
pub fn pref_align_of<T>() -> usize;
/// The size of the referenced value in bytes.
pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;
/// Gets a static string slice containing the name of a type.
+ #[rustc_const_unstable(feature = "const_type_name", issue = "0")]
pub fn type_name<T: ?Sized>() -> &'static str;
/// Gets an identifier which is globally unique to the specified type. This
/// function will return the same value for a type regardless of whichever
/// crate it is invoked in.
+ #[rustc_const_unstable(feature = "const_type_id", issue = "0")]
pub fn type_id<T: ?Sized + 'static>() -> u64;
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
pub fn panic_if_uninhabited<T>();
/// Gets a reference to a static `Location` indicating where it was called.
+ #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
pub fn caller_location() -> &'static crate::panic::Location<'static>;
/// Creates a value initialized to zero.
///
/// The stabilized version of this intrinsic is
/// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html).
+ #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
pub fn needs_drop<T>() -> bool;
/// Calculates the offset from a pointer.
pub fn float_to_int_approx_unchecked<Float, Int>(value: Float) -> Int;
/// Returns the number of bits set in an integer type `T`
+ #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
pub fn ctpop<T>(x: T) -> T;
/// Returns the number of leading unset bits (zeroes) in an integer type `T`.
/// let num_leading = ctlz(x);
/// assert_eq!(num_leading, 16);
/// ```
+ #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
pub fn ctlz<T>(x: T) -> T;
/// Like `ctlz`, but extra-unsafe as it returns `undef` when
/// let num_leading = unsafe { ctlz_nonzero(x) };
/// assert_eq!(num_leading, 3);
/// ```
+ #[rustc_const_unstable(feature = "constctlz", issue = "0")]
pub fn ctlz_nonzero<T>(x: T) -> T;
/// Returns the number of trailing unset bits (zeroes) in an integer type `T`.
/// let num_trailing = cttz(x);
/// assert_eq!(num_trailing, 16);
/// ```
+ #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
pub fn cttz<T>(x: T) -> T;
/// Like `cttz`, but extra-unsafe as it returns `undef` when
/// let num_trailing = unsafe { cttz_nonzero(x) };
/// assert_eq!(num_trailing, 3);
/// ```
+ #[rustc_const_unstable(feature = "const_cttz", issue = "0")]
pub fn cttz_nonzero<T>(x: T) -> T;
/// Reverses the bytes in an integer type `T`.
+ #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
pub fn bswap<T>(x: T) -> T;
/// Reverses the bits in an integer type `T`.
+ #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
pub fn bitreverse<T>(x: T) -> T;
/// Performs checked integer addition.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_add` method. For example,
/// [`std::u32::overflowing_add`](../../std/primitive.u32.html#method.overflowing_add)
+ #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
/// Performs checked integer subtraction
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_sub` method. For example,
/// [`std::u32::overflowing_sub`](../../std/primitive.u32.html#method.overflowing_sub)
+ #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
pub fn sub_with_overflow<T>(x: T, y: T) -> (T, bool);
/// Performs checked integer multiplication
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_mul` method. For example,
/// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul)
+ #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
pub fn mul_with_overflow<T>(x: T, y: T) -> (T, bool);
/// Performs an exact division, resulting in undefined behavior where
/// Performs an unchecked left shift, resulting in undefined behavior when
/// y < 0 or y >= N, where N is the width of T in bits.
+ #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
pub fn unchecked_shl<T>(x: T, y: T) -> T;
/// Performs an unchecked right shift, resulting in undefined behavior when
/// y < 0 or y >= N, where N is the width of T in bits.
+ #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
pub fn unchecked_shr<T>(x: T, y: T) -> T;
/// Returns the result of an unchecked addition, resulting in
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_left` method. For example,
/// [`std::u32::rotate_left`](../../std/primitive.u32.html#method.rotate_left)
+ #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
pub fn rotate_left<T>(x: T, y: T) -> T;
/// Performs rotate right.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_right` method. For example,
/// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right)
+ #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
pub fn rotate_right<T>(x: T, y: T) -> T;
/// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_add` method. For example,
/// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
+ #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
pub fn wrapping_add<T>(a: T, b: T) -> T;
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_sub` method. For example,
/// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
+ #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
pub fn wrapping_sub<T>(a: T, b: T) -> T;
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_mul` method. For example,
/// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
+ #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
pub fn wrapping_mul<T>(a: T, b: T) -> T;
/// Computes `a + b`, while saturating at numeric bounds.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `saturating_add` method. For example,
/// [`std::u32::saturating_add`](../../std/primitive.u32.html#method.saturating_add)
+ #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
pub fn saturating_add<T>(a: T, b: T) -> T;
/// Computes `a - b`, while saturating at numeric bounds.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `saturating_sub` method. For example,
/// [`std::u32::saturating_sub`](../../std/primitive.u32.html#method.saturating_sub)
+ #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
pub fn saturating_sub<T>(a: T, b: T) -> T;
/// Returns the value of the discriminant for the variant in 'v',
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
+ #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "0")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
/// Internal hook used by Miri to implement unwinding.
#![feature(maybe_uninit_slice)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]
+#![feature(const_type_id)]
+#![feature(const_caller_location)]
#[prelude_import]
#[allow(unused)]
// the `caller_location` intrinsic, but once `#[track_caller]` is implemented,
// `panicking::{panic, panic_fmt}` can use that instead of a `Location` argument.
core_intrinsics,
+ const_caller_location,
)]
#[stable(feature = "core", since = "1.6.0")]
macro_rules! panic {
body_ids.sort_by_key(|b| bodies[b].value.span);
body_ids
}
-
-/// Checks if the specified expression is a built-in range literal.
-/// (See: `LoweringContext::lower_expr()`).
-pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
- use hir::{Path, QPath, ExprKind, TyKind};
-
- // Returns whether the given path represents a (desugared) range,
- // either in std or core, i.e. has either a `::std::ops::Range` or
- // `::core::ops::Range` prefix.
- fn is_range_path(path: &Path) -> bool {
- let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect();
- let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
-
- // "{{root}}" is the equivalent of `::` prefix in `Path`.
- if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
- (*std_core == "std" || *std_core == "core") && range.starts_with("Range")
- } else {
- false
- }
- };
-
- // Check whether a span corresponding to a range expression is a
- // range literal, rather than an explicit struct or `new()` call.
- fn is_lit(sess: &Session, span: &Span) -> bool {
- let source_map = sess.source_map();
- let end_point = source_map.end_point(*span);
-
- if let Ok(end_string) = source_map.span_to_snippet(end_point) {
- !(end_string.ends_with("}") || end_string.ends_with(")"))
- } else {
- false
- }
- };
-
- match expr.kind {
- // All built-in range literals but `..=` and `..` desugar to `Struct`s.
- ExprKind::Struct(ref qpath, _, _) => {
- if let QPath::Resolved(None, ref path) = **qpath {
- return is_range_path(&path) && is_lit(sess, &expr.span);
- }
- }
-
- // `..` desugars to its struct path.
- ExprKind::Path(QPath::Resolved(None, ref path)) => {
- return is_range_path(&path) && is_lit(sess, &expr.span);
- }
-
- // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
- ExprKind::Call(ref func, _) => {
- if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
- if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
- let new_call = segment.ident.name == sym::new;
- return is_range_path(&path) && is_lit(sess, &expr.span) && new_call;
- }
- }
- }
-
- _ => {}
- }
-
- false
-}
pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto};
pub use syntax::ast::{CaptureBy, Constness, Movability, Mutability, Unsafety};
use syntax::attr::{InlineAttr, OptimizeAttr};
-use syntax::source_map::Spanned;
-use syntax::symbol::{kw, Symbol};
use syntax::tokenstream::TokenStream;
use syntax::util::parser::ExprPrecedence;
+use syntax_pos::source_map::{SourceMap, Spanned};
+use syntax_pos::symbol::{kw, sym, Symbol};
use syntax_pos::{MultiSpan, Span, DUMMY_SP};
/// HIR doesn't commit to a concrete storage type and has its own alias for a vector.
}
}
+/// Checks if the specified expression is a built-in range literal.
+/// (See: `LoweringContext::lower_expr()`).
+///
+/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`,
+/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`.
+pub fn is_range_literal(sm: &SourceMap, expr: &Expr) -> bool {
+ // Returns whether the given path represents a (desugared) range,
+ // either in std or core, i.e. has either a `::std::ops::Range` or
+ // `::core::ops::Range` prefix.
+ fn is_range_path(path: &Path) -> bool {
+ let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect();
+ let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
+
+ // "{{root}}" is the equivalent of `::` prefix in `Path`.
+ if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
+ (*std_core == "std" || *std_core == "core") && range.starts_with("Range")
+ } else {
+ false
+ }
+ };
+
+ // Check whether a span corresponding to a range expression is a
+ // range literal, rather than an explicit struct or `new()` call.
+ fn is_lit(sm: &SourceMap, span: &Span) -> bool {
+ let end_point = sm.end_point(*span);
+
+ if let Ok(end_string) = sm.span_to_snippet(end_point) {
+ !(end_string.ends_with("}") || end_string.ends_with(")"))
+ } else {
+ false
+ }
+ };
+
+ match expr.kind {
+ // All built-in range literals but `..=` and `..` desugar to `Struct`s.
+ ExprKind::Struct(ref qpath, _, _) => {
+ if let QPath::Resolved(None, ref path) = **qpath {
+ return is_range_path(&path) && is_lit(sm, &expr.span);
+ }
+ }
+
+ // `..` desugars to its struct path.
+ ExprKind::Path(QPath::Resolved(None, ref path)) => {
+ return is_range_path(&path) && is_lit(sm, &expr.span);
+ }
+
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+ ExprKind::Call(ref func, _) => {
+ if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
+ if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
+ let new_call = segment.ident.name == sym::new;
+ return is_range_path(&path) && is_lit(sm, &expr.span) && new_call;
+ }
+ }
+ }
+
+ _ => {}
+ }
+
+ false
+}
+
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
pub enum ExprKind {
/// A `box x` expression.
use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
-use syntax_pos::symbol::{sym, Symbol};
+use syntax_pos::symbol::Symbol;
use rustc_target::spec::abi::Abi;
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;
}
}
- /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
- /// for being called from stable `const fn`s (`min_const_fn`).
- ///
- /// Adding more intrinsics requires sign-off from @rust-lang/lang.
- ///
- /// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
- /// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
- /// stable, it must be callable at all.
- fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
- match self.item_name(def_id) {
- | sym::size_of
- | sym::min_align_of
- | sym::needs_drop
- // Arithmetic:
- | sym::add_with_overflow // ~> .overflowing_add
- | sym::sub_with_overflow // ~> .overflowing_sub
- | sym::mul_with_overflow // ~> .overflowing_mul
- | sym::wrapping_add // ~> .wrapping_add
- | sym::wrapping_sub // ~> .wrapping_sub
- | sym::wrapping_mul // ~> .wrapping_mul
- | sym::saturating_add // ~> .saturating_add
- | sym::saturating_sub // ~> .saturating_sub
- | sym::unchecked_shl // ~> .wrapping_shl
- | sym::unchecked_shr // ~> .wrapping_shr
- | sym::rotate_left // ~> .rotate_left
- | sym::rotate_right // ~> .rotate_right
- | sym::ctpop // ~> .count_ones
- | sym::ctlz // ~> .leading_zeros
- | sym::cttz // ~> .trailing_zeros
- | sym::bswap // ~> .swap_bytes
- | sym::bitreverse // ~> .reverse_bits
- => true,
- _ => false,
- }
- }
-
/// Returns `true` if this function must conform to `min_const_fn`
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
// Bail out if the signature doesn't contain `const`
if !self.is_const_fn_raw(def_id) {
return false;
}
- if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
- return self.is_intrinsic_min_const_fn(def_id);
- }
if self.features().staged_api {
// In order for a libstd function to be considered min_const_fn
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
match tcx.fn_sig(def_id).abi() {
Abi::RustIntrinsic |
- Abi::PlatformIntrinsic => {
- // FIXME: deduplicate these two lists as much as possible
- match tcx.item_name(def_id) {
- // Keep this list in the same order as the match patterns in
- // `librustc_mir/interpret/intrinsics.rs`
-
- // This whitelist is a list of intrinsics that have a miri-engine implementation
- // and can thus be called when enabling enough feature gates. The similar
- // whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
- // the intrinsics to be called by stable const fns.
- | sym::caller_location
-
- | sym::min_align_of
- | sym::pref_align_of
- | sym::needs_drop
- | sym::size_of
- | sym::type_id
- | sym::type_name
-
- | sym::ctpop
- | sym::cttz
- | sym::cttz_nonzero
- | sym::ctlz
- | sym::ctlz_nonzero
- | sym::bswap
- | sym::bitreverse
-
- | sym::wrapping_add
- | sym::wrapping_sub
- | sym::wrapping_mul
- | sym::add_with_overflow
- | sym::sub_with_overflow
- | sym::mul_with_overflow
-
- | sym::saturating_add
- | sym::saturating_sub
-
- | sym::unchecked_shl
- | sym::unchecked_shr
-
- | sym::rotate_left
- | sym::rotate_right
-
- | sym::ptr_offset_from
-
- | sym::transmute
-
- | sym::simd_insert
-
- | sym::simd_extract
-
- => Some(true),
-
- _ => Some(false)
- }
- }
+ Abi::PlatformIntrinsic => Some(tcx.lookup_const_stability(def_id).is_some()),
_ => None
}
}
use crate::hir::def_id::DefId;
use lint::{LateContext, LintArray, LintContext};
use lint::{LateLintPass, LintPass};
-use rustc::hir::lowering::is_range_literal;
-use rustc::hir::{ExprKind, Node};
+use rustc::hir::{is_range_literal, ExprKind, Node};
use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx};
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
if let hir::ExprKind::Struct(..) = par_e.kind {
- if is_range_literal(cx.sess(), par_e)
+ if is_range_literal(cx.sess().source_map(), par_e)
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
{
// The overflowing literal lint was overridden.
return;
}
}
- hir::ExprKind::Struct(..) if is_range_literal(cx.sess(), par_e) => {
+ hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => {
let t = t.name_str();
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
// The overflowing literal lint was overridden.
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use errors::{Applicability, DiagnosticBuilder};
-use rustc::hir;
-use rustc::hir::Node;
-use rustc::hir::{lowering::is_range_literal, print};
+use rustc::hir::{self, is_range_literal, print, Node};
use rustc::ty::adjustment::AllowTwoPhase;
use rustc::ty::{self, AssocItem, Ty};
use syntax::symbol::sym;
// parenthesize if needed (Issue #46756)
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
// parenthesize borrows of range literals (Issue #54505)
- _ if is_range_literal(self.tcx.sess, expr) => true,
+ _ if is_range_literal(self.tcx.sess.source_map(), expr) => true,
_ => false,
};
let sugg_expr = if needs_parens { format!("({})", src) } else { src };
}
}
+ function showSearchResults(search) {
+ if (search === null || typeof search === 'undefined') {
+ search = getSearchElement();
+ }
+ addClass(main, "hidden");
+ removeClass(search, "hidden");
+ }
+
+ function hideSearchResults(search) {
+ if (search === null || typeof search === 'undefined') {
+ search = getSearchElement();
+ }
+ addClass(search, "hidden");
+ removeClass(main, "hidden");
+ }
+
// used for special search precedence
var TY_PRIMITIVE = itemTypes.indexOf("primitive");
var TY_KEYWORD = itemTypes.indexOf("keyword");
if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
// This block occurs when clicking on an element in the navbar while
// in a search.
- addClass(search, "hidden");
- removeClass(main, "hidden");
+ hideSearchResults(search);
var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
if (browserSupportsHistoryApi()) {
history.replaceState(hash, "", "?search=#" + hash);
displayHelp(false, ev, help);
} else if (hasClass(search, "hidden") === false) {
ev.preventDefault();
- addClass(search, "hidden");
- removeClass(main, "hidden");
+ hideSearchResults(search);
document.title = titleBeforeSearch;
}
defocusSearchBar();
return null;
}
- document.onkeypress = handleShortcut;
- document.onkeydown = handleShortcut;
+ document.addEventListener("keypress", handleShortcut);
+ document.addEventListener("keydown", handleShortcut);
var handleSourceHighlight = (function() {
var prev_line_id = 0;
}
})();
- document.onclick = function(ev) {
+ document.addEventListener("click", function(ev) {
if (hasClass(ev.target, "collapse-toggle")) {
collapseDocs(ev.target, "toggle");
} else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
expandSection(a.hash.replace(/^#/, ""));
}
}
- };
+ });
var x = document.getElementsByClassName("version-selector");
if (x.length > 0) {
}
dst = dst[0];
if (window.location.pathname === dst.pathname) {
- addClass(getSearchElement(), "hidden");
- removeClass(main, "hidden");
+ hideSearchResults();
document.location.href = dst.href;
}
};
e.preventDefault();
} else if (e.which === 16) { // shift
// Does nothing, it's just to avoid losing "focus" on the highlighted element.
- } else if (e.which === 27) { // escape
- handleEscape(e);
} else if (actives[currentTab].length > 0) {
removeClass(actives[currentTab][0], "highlighted");
}
"</div><div id=\"results\">" +
ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
- addClass(main, "hidden");
var search = getSearchElement();
- removeClass(search, "hidden");
search.innerHTML = output;
+ showSearchResults(search);
var tds = search.getElementsByTagName("td");
var td_width = 0;
if (tds.length > 0) {
if (browserSupportsHistoryApi()) {
history.replaceState("", window.currentCrate + " - Rust", "?search=");
}
- if (hasClass(main, "content")) {
- removeClass(main, "hidden");
- }
- var search_c = getSearchElement();
- if (hasClass(search_c, "content")) {
- addClass(search_c, "hidden");
- }
+ hideSearchResults();
} else {
searchTimeout = setTimeout(search, 500);
}
search();
};
search_input.onchange = function(e) {
+ if (e.target !== document.activeElement) {
+ // To prevent doing anything when it's from a blur event.
+ return;
+ }
// Do NOT e.preventDefault() here. It will prevent pasting.
clearTimeout(searchTimeout);
// zero-timeout necessary here because at the time of event handler execution the
// Store the previous <title> so we can revert back to it later.
var previousTitle = document.title;
- window.onpopstate = function(e) {
+ window.addEventListener("popstate", function(e) {
var params = getQueryStringParams();
- // When browsing back from search results the main page
- // visibility must be reset.
- if (!params.search) {
- if (hasClass(main, "content")) {
- removeClass(main, "hidden");
- }
- var search_c = getSearchElement();
- if (hasClass(search_c, "content")) {
- addClass(search_c, "hidden");
- }
- }
// Revert to the previous title manually since the History
// API ignores the title parameter.
document.title = previousTitle;
// perform the search. This will empty the bar if there's
// nothing there, which lets you really go back to a
// previous state with nothing in the bar.
- if (params.search) {
+ if (params.search && params.search.length > 0) {
search_input.value = params.search;
+ // Some browsers fire "onpopstate" for every page load
+ // (Chrome), while others fire the event only when actually
+ // popping a state (Firefox), which is why search() is
+ // called both here and at the end of the startSearch()
+ // function.
+ search(e);
} else {
search_input.value = "";
+ // When browsing back from search results the main page
+ // visibility must be reset.
+ hideSearchResults();
}
- // Some browsers fire "onpopstate" for every page load
- // (Chrome), while others fire the event only when actually
- // popping a state (Firefox), which is why search() is
- // called both here and at the end of the startSearch()
- // function.
- search();
- };
+ });
}
search();
}
}
function putBackSearch(search_input) {
- if (search_input.value !== "") {
- addClass(main, "hidden");
- removeClass(getSearchElement(), "hidden");
+ var search = getSearchElement();
+ if (search_input.value !== "" && hasClass(search, "hidden")) {
+ showSearchResults(search);
if (browserSupportsHistoryApi()) {
history.replaceState(search_input.value,
"",
var params = getQueryStringParams();
if (params && params.search) {
- addClass(main, "hidden");
var search = getSearchElement();
- removeClass(search, "hidden");
search.innerHTML = "<h3 style=\"text-align: center;\">Loading search results...</h3>";
+ showSearchResults(search);
}
var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Cursor<T> {
inner: T,
pos: u64,
c.set_position(<usize>::max_value() as u64 + 1);
assert!(c.write_all(&[1, 2, 3]).is_err());
}
+
+ #[test]
+ fn test_partial_eq() {
+ assert_eq!(Cursor::new(Vec::<u8>::new()), Cursor::new(Vec::<u8>::new()));
+ }
+
+ #[test]
+ fn test_eq() {
+ struct AssertEq<T: Eq>(pub T);
+
+ let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
+ }
}
all:
$(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan
$(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value
+ $(RUSTC) -g -Z sanitizer=memory -Z print-link-args maybeuninit.rs | $(CGREP) librustc_msan
+ $(TMPDIR)/maybeuninit 2>&1 | $(CGREP) use-of-uninitialized-value
--- /dev/null
+use std::mem::MaybeUninit;
+
+fn main() {
+ // This is technically not sound -- but we're literally trying to test
+ // that the sanitizer catches this, so I guess "intentionally unsound"?
+ let xs: [u8; 4] = unsafe { MaybeUninit::uninit().assume_init() };
+ let y = xs[0] + xs[1];
+}
-use std::mem;
-
fn main() {
+ // This is technically not sound -- but we're literally trying to test
+ // that the sanitizer catches this, so I guess "intentionally unsound"?
#[allow(deprecated)]
- let xs: [u8; 4] = unsafe { mem::uninitialized() };
+ let xs: [u8; 4] = unsafe { std::mem::uninitialized() };
let y = xs[0] + xs[1];
}
impl<U: Unsigned> Add<U> for UTerm {
type Output = U;
fn add(self, _: U) -> Self::Output {
- #[allow(deprecated)]
- unsafe { ::std::mem::uninitialized() }
+ unimplemented!()
}
}
{
type Output = UInt<Prod<Ul, UInt<Ur, B>>, B0>;
fn mul(self, _: UInt<Ur, B>) -> Self::Output {
- unsafe { ::std::mem::uninitialized() }
+ unimplemented!()
}
}
// ignore-sgx no processes
// ignore-musl FIXME #31506
-use std::mem;
+use std::mem::MaybeUninit;
use std::process::Command;
use std::thread;
use std::env;
let args = env::args().skip(1).collect::<Vec<_>>();
if args.len() > 0 {
match &args[0][..] {
- "main-thread" => recurse(&[]),
- "child-thread" => thread::spawn(|| recurse(&[])).join().unwrap(),
+ "main-thread" => recurse(&MaybeUninit::uninit()),
+ "child-thread" => thread::spawn(|| recurse(&MaybeUninit::uninit())).join().unwrap(),
_ => panic!(),
}
return
}
#[allow(unconditional_recursion)]
-fn recurse(array: &[u64]) {
- unsafe { black_box(array.as_ptr() as u64); }
- #[allow(deprecated)]
- let local: [_; 1024] = unsafe { mem::uninitialized() };
+fn recurse(array: &MaybeUninit<[u64; 1024]>) {
+ unsafe {
+ black_box(array.as_ptr() as u64);
+ }
+ let local: MaybeUninit<[u64; 1024]> = MaybeUninit::uninit();
recurse(&local);
}
use std::mem;
+// Neither of the uninits below are currently accepted as not UB, however,
+// this code does not run and is merely checking that we do not ICE on this pattern,
+// so this is fine.
+
fn foo<const SIZE: usize>() {
let arr: [u8; SIZE] = unsafe {
#[allow(deprecated)]
};
}
+fn bar<const SIZE: usize>() {
+ let arr: [u8; SIZE] = unsafe {
+ let array: [u8; SIZE] = mem::MaybeUninit::uninit().assume_init();
+ array
+ };
+}
+
+
fn main() {}
#![feature(const_fn)]
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
+#![feature(staged_api)]
+#![stable(feature = "foo", since = "1.33.7")]
#![allow(non_camel_case_types)]
#[repr(simd)] struct i8x1(i8);
#[repr(simd)] struct f32x3(f32, f32, f32);
extern "platform-intrinsic" {
+ #[rustc_const_stable(feature = "foo", since = "1.3.37")]
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
+ #[rustc_const_stable(feature = "foo", since = "1.3.37")]
fn simd_extract<T, U>(x: T, idx: u32) -> U;
}
#![feature(core_intrinsics)]
#![feature(const_fn)]
+#![feature(const_type_name)]
#![allow(dead_code)]
const fn type_name_wrapper<T>(_: &T) -> &'static str {
fn main() {
// Check that the tail statement in the body unifies with something
for _ in 0..3 {
- #[allow(deprecated)]
- unsafe { std::mem::uninitialized() }
+ // `()` is fine to zero-initialize as it is zero sized and inhabited.
+ unsafe { std::mem::zeroed() }
}
// Check that the tail statement in the body can be unit
// This note is annotated because the purpose of the test
// is to ensure that certain other notes are not generated.
#![deny(unused_unsafe)] //~ NOTE
-#![allow(deprecated)]
+
// (test that no note is generated on this unsafe fn)
pub unsafe fn a() {
unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe`
//~^ NOTE
}
-
- let () = ::std::mem::uninitialized();
+ // `()` is fine to zero-initialize as it is zero sized and inhabited.
+ let () = ::std::mem::zeroed();
inner()
}
-// run-pass
+// check-pass
trait FromUnchecked {
- unsafe fn from_unchecked();
+ fn from_unchecked();
}
impl FromUnchecked for [u8; 1] {
- unsafe fn from_unchecked() {
- #[allow(deprecated)]
- let mut array: Self = std::mem::uninitialized();
+ fn from_unchecked() {
+ let mut array: Self = [0; 1];
let _ptr = &mut array as *mut [u8] as *mut u8;
}
}
unsafe {
// This should be safe, because we don't match on it unless it's fully formed,
// and it doesn't have a destructor.
- #[allow(deprecated)]
- let mut dest: MyEnum = mem::uninitialized();
+ //
+ // MyEnum is repr(C, u8) so it is guaranteed to have a separate discriminant and each
+ // variant can be zero initialized.
+ let mut dest: MyEnum = mem::zeroed();
while buf.len() > 0 {
match parse_my_enum(&mut dest, &mut buf) {
Ok(()) => output.push(Ok(dest)),
unsafe {
// This should be safe, because we don't match on it unless it's fully formed,
// and it doesn't have a destructor.
- #[allow(deprecated)]
- let mut dest: MyEnum = mem::uninitialized();
+ //
+ // Furthermore, there are no types within MyEnum which cannot be initialized with zero,
+ // specifically, though padding and such are present, there are no references or similar
+ // types.
+ let mut dest: MyEnum = mem::zeroed();
while buf.len() > 0 {
match parse_my_enum(&mut dest, &mut buf) {
Ok(()) => output.push(Ok(dest)),
unsafe {
// This should be safe, because we don't match on it unless it's fully formed,
// and it doesn't have a destructor.
- #[allow(deprecated)]
- let mut dest: MyEnum = mem::uninitialized();
+ //
+ // MyEnum is repr(u8) so it is guaranteed to have a separate discriminant and each variant
+ // can be zero initialized.
+ let mut dest: MyEnum = mem::zeroed();
while buf.len() > 0 {
match parse_my_enum(&mut dest, &mut buf) {
Ok(()) => output.push(Ok(dest)),
-#![allow(deprecated)]
-
+use std::mem::zeroed;
enum Void {}
fn main() {
Ok(n) => n,
};
- let x: &Void = unsafe { std::mem::uninitialized() };
+ // This is pretty much instant UB. However, we have no choice -- we need to
+ // test matching on a reference to `&Void`; we cannot do anything other than
+ // just accept the fact that this is UB if `main` did run, but it doesn't;
+ // this test only checks that these are feature-gated.
+ let x: &Void = unsafe { zeroed() };
let _ = match x {}; //~ ERROR non-exhaustive
- let x: (Void,) = unsafe { std::mem::uninitialized() };
+ let x: (Void,) = unsafe { zeroed() };
let _ = match x {}; //~ ERROR non-exhaustive
- let x: [Void; 1] = unsafe { std::mem::uninitialized() };
+ let x: [Void; 1] = unsafe { zeroed() };
let _ = match x {}; //~ ERROR non-exhaustive
- let x: &[Void] = unsafe { std::mem::uninitialized() };
+ let x: &[Void] = unsafe { zeroed() };
let _ = match x { //~ ERROR non-exhaustive
&[] => (),
};
- let x: Void = unsafe { std::mem::uninitialized() };
+ let x: Void = unsafe { zeroed() };
let _ = match x {}; // okay
let x: Result<u32, Void> = Ok(23);
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
- --> $DIR/uninhabited-matches-feature-gated.rs:7:19
+ --> $DIR/uninhabited-matches-feature-gated.rs:6:19
|
LL | let _ = match x {
| ^ pattern `Err(_)` not covered
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
- --> $DIR/uninhabited-matches-feature-gated.rs:12:19
+ --> $DIR/uninhabited-matches-feature-gated.rs:15:19
|
LL | enum Void {}
| ------------ `Void` defined here
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
- --> $DIR/uninhabited-matches-feature-gated.rs:15:19
+ --> $DIR/uninhabited-matches-feature-gated.rs:18:19
|
LL | let _ = match x {};
| ^
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
- --> $DIR/uninhabited-matches-feature-gated.rs:18:19
+ --> $DIR/uninhabited-matches-feature-gated.rs:21:19
|
LL | let _ = match x {};
| ^
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
- --> $DIR/uninhabited-matches-feature-gated.rs:21:19
+ --> $DIR/uninhabited-matches-feature-gated.rs:24:19
|
LL | let _ = match x {
| ^ pattern `&[_, ..]` not covered
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
- --> $DIR/uninhabited-matches-feature-gated.rs:29:19
+ --> $DIR/uninhabited-matches-feature-gated.rs:32:19
|
LL | let _ = match x {
| ^ pattern `Err(_)` not covered
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
- --> $DIR/uninhabited-matches-feature-gated.rs:34:9
+ --> $DIR/uninhabited-matches-feature-gated.rs:37:9
|
LL | let Ok(x) = x;
| ^^^^^ pattern `Err(_)` not covered
-// run-pass
+// build-pass
// Test the uninit() construct returning various empty types.
// pretty-expanded FIXME #23616
-use std::mem;
+use std::mem::MaybeUninit;
-#[derive(Clone)]
struct Foo;
#[allow(deprecated)]
pub fn main() {
unsafe {
- let _x: Foo = mem::uninitialized();
- let _x: [Foo; 2] = mem::uninitialized();
+ // `Foo` and `[Foo; 2]` are both zero sized and inhabited, so this is safe.
+ let _x: Foo = MaybeUninit::uninit().assume_init();
+ let _x: [Foo; 2] = MaybeUninit::uninit().assume_init();
+ let _x: Foo = std::mem::uninitialized();
+ let _x: [Foo; 2] = std::mem::uninitialized();
}
}