exclude = [
"build",
"compiler/rustc_codegen_cranelift",
+ "compiler/rustc_codegen_gcc",
"src/test/rustdoc-gui",
# HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
"obj",
+Rust 1.56.0 (2021-10-21)
+========================
+
+Language
+--------
+
+- [The 2021 Edition is now stable.][rust#88100]
+ See [the edition guide][rust-2021-edition-guide] for more details.
+- [You can now specify explicit discriminant values on any Rust enum.][rust#86860]
+- [The pattern in `binding @ pattern` can now also introduce new bindings.][rust#85305]
+- [Union field access is permitted in `const fn`.][rust#85769]
+
+[rust-2021-edition-guide]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/index.html
+
+Compiler
+--------
+
+- [Upgrade to LLVM 13.][rust#87570]
+- [Support memory, address, and thread sanitizers on aarch64-unknown-freebsd.][rust#88023]
+- [Allow specifying a deployment target version for all iOS targets][rust#87699]
+- [Warnings can be forced on with `--force-warn`.][rust#87472]
+ This feature is primarily intended for usage by `cargo fix`, rather than end users.
+- [Promote `aarch64-apple-ios-sim` to Tier 2\*.][rust#87760]
+- [Add `powerpc-unknown-freebsd` at Tier 3\*.][rust#87370]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [Allow writing of incomplete UTF-8 sequences via stdout/stderr on Windows.][rust#83342]
+ The Windows console still requires valid Unicode, but this change allows
+ splitting a UTF-8 character across multiple write calls. This allows, for
+ instance, programs that just read and write data buffers (e.g. copying a file
+ to stdout) without regard for Unicode or character boundaries.
+- [Prefer `AtomicU{64,128}` over Mutex for Instant backsliding protection.][rust#83093]
+ For this use case, atomics scale much better under contention.
+- [Implement `Extend<(A, B)>` for `(Extend<A>, Extend<B>)`][rust#85835]
+- [impl Default, Copy, Clone for std::io::Sink and std::io::Empty][rust#86744]
+- [`impl From<[(K, V); N]>` for all collections.][rust#84111]
+- [Remove `P: Unpin` bound on impl Future for Pin.][rust#81363]
+- [Treat invalid environment variable names as non-existent.][rust#86183]
+ Previously, the environment functions would panic if given a variable name
+ with an internal null character or equal sign (`=`). Now, these functions will
+ just treat such names as non-existent variables, since the OS cannot represent
+ the existence of a variable with such a name.
+
+Stabilised APIs
+---------------
+
+- [`std::os::unix::fs::chroot`]
+- [`Iterator::intersperse`]
+- [`Iterator::intersperse_with`]
+- [`UnsafeCell::raw_get`]
+- [`BufWriter::into_parts`]
+- [`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]
+ These APIs were previously stable in `std`, but are now also available in `core`.
+- [`Vec::shrink_to`]
+- [`String::shrink_to`]
+- [`OsString::shrink_to`]
+- [`PathBuf::shrink_to`]
+- [`BinaryHeap::shrink_to`]
+- [`VecDeque::shrink_to`]
+- [`HashMap::shrink_to`]
+- [`HashSet::shrink_to`]
+- [`task::ready!`]
+
+These APIs are now usable in const contexts:
+
+- [`std::mem::transmute`]
+- [`[T]::first`][`slice::first`]
+- [`[T]::split_first`][`slice::split_first`]
+- [`[T]::last`][`slice::last`]
+- [`[T]::split_last`][`slice::split_last`]
+
+Cargo
+-----
+
+- [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`]
+ This has no effect at present on dependency version selection.
+ We encourage crates to specify their minimum supported Rust version, and we encourage CI systems
+ that support Rust code to include a crate's specified minimum version in the text matrix for that
+ crate by default.
+
+Compatibility notes
+-------------------
+
+- [Update to new argument parsing rules on Windows.][rust#87580]
+ This adjusts Rust's standard library to match the behavior of the standard
+ libraries for C/C++. The rules have changed slightly over time, and this PR
+ brings us to the latest set of rules (changed in 2008).
+- [Disallow the aapcs calling convention on aarch64][rust#88399]
+ This was already not supported by LLVM; this change surfaces this lack of
+ support with a better error message.
+- [Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default][rust#87385]
+- [Warn when an escaped newline skips multiple lines.][rust#87671]
+- [Calls to `libc::getpid` / `std::process::id` from `Command::pre_exec`
+ may return different values on glibc <= 2.24.][rust#81825]
+ Rust now invokes the `clone3` system call directly, when available, to use new functionality
+ available via that system call. Older versions of glibc cache the result of `getpid`, and only
+ update that cache when calling glibc's clone/fork functions, so a direct system call bypasses
+ that cache update. glibc 2.25 and newer no longer cache `getpid` for exactly this reason.
+
+Internal changes
+----------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [LLVM is compiled with PGO in published x86_64-unknown-linux-gnu artifacts.][rust#88069]
+ This improves the performance of most Rust builds.
+- [Unify representation of macros in internal data structures.][rust#88019]
+ This change fixes a host of bugs with the handling of macros by the compiler,
+ as well as rustdoc.
+
+[`std::os::unix::fs::chroot`]: https://doc.rust-lang.org/stable/std/os/unix/fs/fn.chroot.html
+[`Iterator::intersperse`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse
+[`Iterator::intersperse_with`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse
+[`UnsafeCell::raw_get`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.raw_get
+[`BufWriter::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.BufWriter.html#method.into_parts
+[`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]: https://github.com/rust-lang/rust/pull/84662
+[`Vec::shrink_to`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.shrink_to
+[`String::shrink_to`]: https://doc.rust-lang.org/stable/std/string/struct.String.html#method.shrink_to
+[`OsString::shrink_to`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.shrink_to
+[`PathBuf::shrink_to`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.shrink_to
+[`BinaryHeap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.shrink_to
+[`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to
+[`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to
+[`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to
+[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html
+[`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html
+[`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first
+[`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first
+[`slice::last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last
+[`slice::split_last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last
+[`rust-version`]: https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field
+[rust#87671]: https://github.com/rust-lang/rust/pull/87671
+[rust#86183]: https://github.com/rust-lang/rust/pull/86183
+[rust#87385]: https://github.com/rust-lang/rust/pull/87385
+[rust#88100]: https://github.com/rust-lang/rust/pull/88100
+[rust#86860]: https://github.com/rust-lang/rust/pull/86860
+[rust#84039]: https://github.com/rust-lang/rust/pull/84039
+[rust#86492]: https://github.com/rust-lang/rust/pull/86492
+[rust#88363]: https://github.com/rust-lang/rust/pull/88363
+[rust#85305]: https://github.com/rust-lang/rust/pull/85305
+[rust#87832]: https://github.com/rust-lang/rust/pull/87832
+[rust#88069]: https://github.com/rust-lang/rust/pull/88069
+[rust#87472]: https://github.com/rust-lang/rust/pull/87472
+[rust#87699]: https://github.com/rust-lang/rust/pull/87699
+[rust#87570]: https://github.com/rust-lang/rust/pull/87570
+[rust#88023]: https://github.com/rust-lang/rust/pull/88023
+[rust#87760]: https://github.com/rust-lang/rust/pull/87760
+[rust#87370]: https://github.com/rust-lang/rust/pull/87370
+[rust#87580]: https://github.com/rust-lang/rust/pull/87580
+[rust#83342]: https://github.com/rust-lang/rust/pull/83342
+[rust#83093]: https://github.com/rust-lang/rust/pull/83093
+[rust#88177]: https://github.com/rust-lang/rust/pull/88177
+[rust#88548]: https://github.com/rust-lang/rust/pull/88548
+[rust#88551]: https://github.com/rust-lang/rust/pull/88551
+[rust#88299]: https://github.com/rust-lang/rust/pull/88299
+[rust#88220]: https://github.com/rust-lang/rust/pull/88220
+[rust#85835]: https://github.com/rust-lang/rust/pull/85835
+[rust#86879]: https://github.com/rust-lang/rust/pull/86879
+[rust#86744]: https://github.com/rust-lang/rust/pull/86744
+[rust#84662]: https://github.com/rust-lang/rust/pull/84662
+[rust#86593]: https://github.com/rust-lang/rust/pull/86593
+[rust#81050]: https://github.com/rust-lang/rust/pull/81050
+[rust#81363]: https://github.com/rust-lang/rust/pull/81363
+[rust#84111]: https://github.com/rust-lang/rust/pull/84111
+[rust#85769]: https://github.com/rust-lang/rust/pull/85769#issuecomment-854363720
+[rust#88490]: https://github.com/rust-lang/rust/pull/88490
+[rust#88269]: https://github.com/rust-lang/rust/pull/88269
+[rust#84176]: https://github.com/rust-lang/rust/pull/84176
+[rust#88399]: https://github.com/rust-lang/rust/pull/88399
+[rust#88227]: https://github.com/rust-lang/rust/pull/88227
+[rust#88200]: https://github.com/rust-lang/rust/pull/88200
+[rust#82776]: https://github.com/rust-lang/rust/pull/82776
+[rust#88077]: https://github.com/rust-lang/rust/pull/88077
+[rust#87728]: https://github.com/rust-lang/rust/pull/87728
+[rust#87050]: https://github.com/rust-lang/rust/pull/87050
+[rust#87619]: https://github.com/rust-lang/rust/pull/87619
+[rust#81825]: https://github.com/rust-lang/rust/pull/81825#issuecomment-808406918
+[rust#88019]: https://github.com/rust-lang/rust/pull/88019
+
Version 1.55.0 (2021-09-09)
============================
- [Upgrade to Unicode 10.0.0][42999]
- [Reimplemented `{f32, f64}::{min, max}` in Rust instead of using CMath.][42430]
- [Skip the main thread's manual stack guard on Linux][43072]
-- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in O(1) time][43077]
+- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in *O*(1) time][43077]
- [`#[repr(align(N))]` attribute max number is now 2^31 - 1.][43097] This was
previously 2^15.
- [`{OsStr, Path}::Display` now avoids allocations where possible][42613]
algorithm][s].
* [`std::io::copy` allows `?Sized` arguments][cc].
* The `Windows`, `Chunks`, and `ChunksMut` iterators over slices all
- [override `count`, `nth` and `last` with an O(1)
+ [override `count`, `nth` and `last` with an *O*(1)
implementation][it].
* [`Default` is implemented for arrays up to `[T; 32]`][d].
* [`IntoRawFd` has been added to the Unix-specific prelude,
* The `Default` implementation for `Arc` [no longer requires `Sync +
Send`][arc].
* [The `Iterator` methods `count`, `nth`, and `last` have been
- overridden for slices to have O(1) performance instead of O(n)][si].
+ overridden for slices to have *O*(1) performance instead of *O*(*n*)][si].
* Incorrect handling of paths on Windows has been improved in both the
compiler and the standard library.
* [`AtomicPtr` gained a `Default` implementation][ap].
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
-use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
use std::fmt;
use std::rc::Rc;
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
placeholder: ty::PlaceholderRegion,
error_element: RegionElement,
- span: Span,
+ cause: ObligationCause<'tcx>,
) {
match self.0 {
UniverseInfoInner::RelateTys { expected, found } => {
- let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
let err = mbcx.infcx.report_mismatched_types(
- &ObligationCause::misc(span, body_id),
+ &cause,
expected,
found,
TypeError::RegionsPlaceholderMismatch,
err.buffer(&mut mbcx.errors_buffer);
}
UniverseInfoInner::TypeOp(ref type_op_info) => {
- type_op_info.report_error(mbcx, placeholder, error_element, span);
+ type_op_info.report_error(mbcx, placeholder, error_element, cause);
}
UniverseInfoInner::Other => {
// FIXME: This error message isn't great, but it doesn't show
mbcx.infcx
.tcx
.sess
- .struct_span_err(span, "higher-ranked subtype error")
+ .struct_span_err(cause.span, "higher-ranked subtype error")
.buffer(&mut mbcx.errors_buffer);
}
}
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
- span: Span,
+ cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>>;
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
placeholder: ty::PlaceholderRegion,
error_element: RegionElement,
- span: Span,
+ cause: ObligationCause<'tcx>,
) {
let tcx = mbcx.infcx.tcx;
let base_universe = self.base_universe();
{
adjusted
} else {
- self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+ self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
return;
};
debug!(?placeholder_region);
- let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);
+ let span = cause.span;
+ let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
if let Some(nice_error) = nice_error {
nice_error.buffer(&mut mbcx.errors_buffer);
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
- span: Span,
+ cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> {
- tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
- type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span));
- try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
- })
+ tcx.infer_ctxt().enter_with_canonical(
+ cause.span,
+ &self.canonical_query,
+ |ref infcx, key, _| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+ type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
+ try_extract_error_from_fulfill_cx(
+ fulfill_cx,
+ infcx,
+ placeholder_region,
+ error_region,
+ )
+ },
+ )
}
}
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
- span: Span,
+ cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> {
- tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
-
- let mut selcx = SelectionContext::new(infcx);
-
- // FIXME(lqd): Unify and de-duplicate the following with the actual
- // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
- // `ObligationCause`. The normalization results are currently different between
- // `AtExt::normalize` used in the query and `normalize` called below: the former fails
- // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
- // after #85499 lands to see if its fixes have erased this difference.
- let (param_env, value) = key.into_parts();
- let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
- &mut selcx,
- param_env,
- ObligationCause::dummy_with_span(span),
- value.value,
- );
- fulfill_cx.register_predicate_obligations(infcx, obligations);
-
- try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
- })
+ tcx.infer_ctxt().enter_with_canonical(
+ cause.span,
+ &self.canonical_query,
+ |ref infcx, key, _| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+
+ let mut selcx = SelectionContext::new(infcx);
+
+ // FIXME(lqd): Unify and de-duplicate the following with the actual
+ // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+ // `ObligationCause`. The normalization results are currently different between
+ // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+ // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+ // after #85499 lands to see if its fixes have erased this difference.
+ let (param_env, value) = key.into_parts();
+ let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
+ &mut selcx,
+ param_env,
+ cause,
+ value.value,
+ );
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+ try_extract_error_from_fulfill_cx(
+ fulfill_cx,
+ infcx,
+ placeholder_region,
+ error_region,
+ )
+ },
+ )
}
}
fn nice_error(
&self,
tcx: TyCtxt<'tcx>,
- span: Span,
+ cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx>> {
- tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
- type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
- try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
- })
+ tcx.infer_ctxt().enter_with_canonical(
+ cause.span,
+ &self.canonical_query,
+ |ref infcx, key, _| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+ type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
+ .ok()?;
+ try_extract_error_from_fulfill_cx(
+ fulfill_cx,
+ infcx,
+ placeholder_region,
+ error_region,
+ )
+ },
+ )
}
}
borrow_region: RegionVid,
outlived_region: RegionVid,
) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
- let BlameConstraint { category, from_closure, span, variance_info: _ } =
+ let BlameConstraint { category, from_closure, cause, variance_info: _ } =
self.regioncx.best_blame_constraint(
&self.body,
borrow_region,
let outlived_fr_name = self.give_region_a_name(outlived_region);
- (category, from_closure, span, outlived_fr_name)
+ (category, from_closure, cause.span, outlived_fr_name)
}
/// Returns structured explanation for *why* the borrow contains the
use crate::borrowck_errors;
+use super::{OutlivesSuggestionBuilder, RegionName};
use crate::region_infer::BlameConstraint;
use crate::{
nll::ConstraintDescription,
MirBorrowckCtxt,
};
-use super::{OutlivesSuggestionBuilder, RegionName};
-
impl ConstraintDescription for ConstraintCategory {
fn description(&self) -> &'static str {
// Must end with a space. Allows for empty names to be provided.
ConstraintCategory::OpaqueType => "opaque type ",
ConstraintCategory::ClosureUpvar(_) => "closure capture ",
ConstraintCategory::Usage => "this usage ",
- ConstraintCategory::Boring
+ ConstraintCategory::Predicate(_)
+ | ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal => "",
}
let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
- let (_, span) = self.regioncx.find_outlives_blame_span(
+ let (_, cause) = self.regioncx.find_outlives_blame_span(
&self.body,
longer_fr,
NllRegionVariableOrigin::Placeholder(placeholder),
let universe = placeholder.universe;
let universe_info = self.regioncx.universe_info(universe);
- universe_info.report_error(self, placeholder, error_element, span);
+ universe_info.report_error(self, placeholder, error_element, cause);
}
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let BlameConstraint { category, span, variance_info, from_closure: _ } =
+ let BlameConstraint { category, cause, variance_info, from_closure: _ } =
self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
- debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
+ debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
- let nice = NiceRegionError::new_from_span(self.infcx, span, o, f);
+ let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
if let Some(diag) = nice.try_report_from_nll() {
diag.buffer(&mut self.errors_buffer);
return;
fr_is_local,
outlived_fr_is_local,
category,
- span,
+ span: cause.span,
};
let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
Rvalue::Use(ref operand)
| Rvalue::Repeat(ref operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
- | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
+ | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
+ | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
self.consume_operand(location, operand)
}
Rvalue::Use(ref operand)
| Rvalue::Repeat(ref operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
- | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
+ | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
+ | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
self.consume_operand(location, (operand, span), flow_state)
}
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_hir::CRATE_HIR_ID;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::canonical::QueryOutlivesConstraint;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
ConstraintCategory, Local, Location, ReturnConstraint,
};
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
outlived_free_region: fr,
- blame_span: blame_span_category.1,
+ blame_span: blame_span_category.1.span,
category: blame_span_category.0,
});
}
return BlameConstraint {
category: constraint.category,
from_closure: false,
- span,
+ cause: ObligationCause::dummy_with_span(span),
variance_info: constraint.variance_info,
};
}
.map(|&(category, span)| BlameConstraint {
category,
from_closure: true,
- span: span,
+ cause: ObligationCause::dummy_with_span(span),
variance_info: constraint.variance_info,
})
.unwrap_or(BlameConstraint {
category: constraint.category,
from_closure: false,
- span: body.source_info(loc).span,
+ cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
variance_info: constraint.variance_info,
})
}
- /// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
+ /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
crate fn find_outlives_blame_span(
&self,
body: &Body<'tcx>,
fr1: RegionVid,
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
- ) -> (ConstraintCategory, Span) {
- let BlameConstraint { category, span, .. } =
+ ) -> (ConstraintCategory, ObligationCause<'tcx>) {
+ let BlameConstraint { category, cause, .. } =
self.best_blame_constraint(body, fr1, fr1_origin, |r| {
self.provides_universal_region(r, fr1, fr2)
});
- (category, span)
+ (category, cause)
}
/// Walks the graph of constraints (where `'a: 'b` is considered
.collect::<Vec<_>>()
);
+ // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
+ // Instead, we use it to produce an improved `ObligationCauseCode`.
+ // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
+ // constraints. Currently, we just pick the first one.
+ let cause_code = path
+ .iter()
+ .find_map(|constraint| {
+ if let ConstraintCategory::Predicate(predicate_span) = constraint.category {
+ // We currentl'y doesn't store the `DefId` in the `ConstraintCategory`
+ // for perforamnce reasons. The error reporting code used by NLL only
+ // uses the span, so this doesn't cause any problems at the moment.
+ Some(ObligationCauseCode::BindingObligation(
+ CRATE_DEF_ID.to_def_id(),
+ predicate_span,
+ ))
+ } else {
+ None
+ }
+ })
+ .unwrap_or_else(|| ObligationCauseCode::MiscObligation);
+
// Classify each of the constraints along the path.
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
BlameConstraint {
category: constraint.category,
from_closure: false,
- span: constraint.locations.span(body),
+ cause: ObligationCause::new(
+ constraint.locations.span(body),
+ CRATE_HIR_ID,
+ cause_code.clone(),
+ ),
variance_info: constraint.variance_info,
}
}
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
- | ConstraintCategory::Internal => false,
+ | ConstraintCategory::Internal
+ | ConstraintCategory::Predicate(_) => false,
ConstraintCategory::TypeAnnotation
| ConstraintCategory::Return(_)
| ConstraintCategory::Yield => true,
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
- | ConstraintCategory::Internal => false,
+ | ConstraintCategory::Internal
+ | ConstraintCategory::Predicate(_) => false,
_ => true,
}
}
pub struct BlameConstraint<'tcx> {
pub category: ConstraintCategory,
pub from_closure: bool,
- pub span: Span,
+ pub cause: ObligationCause<'tcx>,
pub variance_info: ty::VarianceDiagInfo<'tcx>,
}
use rustc_infer::traits::query::NoSolution;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
use rustc_trait_selection::traits::query::Fallible;
category: ConstraintCategory,
) {
self.prove_predicates(
- Some(ty::PredicateKind::Trait(ty::TraitPredicate {
+ Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
- })),
+ }))),
locations,
category,
);
pub(super) fn normalize_and_prove_instantiated_predicates(
&mut self,
+ // Keep this parameter for now, in case we start using
+ // it in `ConstraintCategory` at some point.
+ _def_id: DefId,
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
locations: Locations,
) {
- for predicate in instantiated_predicates.predicates {
+ for (predicate, span) in instantiated_predicates
+ .predicates
+ .into_iter()
+ .zip(instantiated_predicates.spans.into_iter())
+ {
let predicate = self.normalize(predicate, locations);
- self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
+ self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
}
}
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
};
+use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() {
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
self.cx.normalize_and_prove_instantiated_predicates(
+ def_id,
instantiated_predicates,
location.to_locations(),
);
}
self.prove_predicate(
- ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into()))
+ .to_predicate(self.tcx()),
Locations::All(span),
ConstraintCategory::TypeAnnotation,
);
obligations.obligations.push(traits::Obligation::new(
ObligationCause::dummy(),
param_env,
- ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
+ .to_predicate(infcx.tcx),
));
obligations.add(
infcx
self.check_call_dest(body, term, &sig, destination, term_location);
self.prove_predicates(
- sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())),
+ sig.inputs_and_output
+ .iter()
+ .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))),
term_location.to_locations(),
ConstraintCategory::Boring,
);
}
}
- Rvalue::NullaryOp(_, ty) => {
- // Even with unsized locals cannot box an unsized value.
- if self.unsized_feature_enabled() {
- let span = body.source_info(location).span;
- self.ensure_place_sized(ty, span);
- }
-
+ Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
| Rvalue::AddressOf(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
+ | Rvalue::ShallowInitBox(..)
| Rvalue::BinaryOp(..)
| Rvalue::CheckedBinaryOp(..)
| Rvalue::NullaryOp(..)
aggregate_kind, location
);
- let instantiated_predicates = match aggregate_kind {
+ let (def_id, instantiated_predicates) = match aggregate_kind {
AggregateKind::Adt(def, _, substs, _, _) => {
- tcx.predicates_of(def.did).instantiate(tcx, substs)
+ (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs))
}
// For closures, we have some **extra requirements** we
// clauses on the struct.
AggregateKind::Closure(def_id, substs)
| AggregateKind::Generator(def_id, substs, _) => {
- self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)
+ (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location))
}
- AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
+ AggregateKind::Array(_) | AggregateKind::Tuple => {
+ (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
+ }
};
self.normalize_and_prove_instantiated_predicates(
+ def_id,
instantiated_predicates,
location.to_locations(),
);
use rustc_ast as ast;
use rustc_ast::mut_visit::MutVisitor;
+use rustc_ast::ptr::P;
use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
use rustc_ast::visit::Visitor;
use rustc_ast::{mut_visit, visit};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
+use rustc_feature::Features;
use rustc_parse::parser::ForceCollect;
use rustc_session::utils::FlattenNonterminals;
-
-use rustc_ast::ptr::P;
+use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::Span;
use smallvec::SmallVec;
annotatable: Annotatable,
) -> Vec<Annotatable> {
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
- vec![cfg_eval(ecx, annotatable)]
+ vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
}
-crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable {
- CfgEval {
- cfg: &mut StripUnconfigured {
- sess: ecx.sess,
- features: ecx.ecfg.features,
- config_tokens: true,
- },
- }
- .configure_annotatable(annotatable)
- // Since the item itself has already been configured by the `InvocationCollector`,
- // we know that fold result vector will contain exactly one element.
- .unwrap()
+crate fn cfg_eval(
+ sess: &Session,
+ features: Option<&Features>,
+ annotatable: Annotatable,
+) -> Annotatable {
+ CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
+ .configure_annotatable(annotatable)
+ // Since the item itself has already been configured by the `InvocationCollector`,
+ // we know that fold result vector will contain exactly one element.
+ .unwrap()
}
struct CfgEval<'a, 'b> {
use crate::cfg_eval::cfg_eval;
-use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
+use rustc_ast as ast;
+use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
use rustc_errors::{struct_span_err, Applicability};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
use rustc_feature::AttributeTemplate;
use rustc_parse::validate_attr;
use rustc_session::Session;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
crate struct Expander;
return ExpandResult::Ready(vec![item]);
}
- let item = cfg_eval(ecx, item);
-
+ let (sess, features) = (ecx.sess, ecx.ecfg.features);
let result =
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
let template =
template,
);
- attr.meta_item_list()
+ let mut resolutions: Vec<_> = attr
+ .meta_item_list()
.unwrap_or_default()
.into_iter()
.filter_map(|nested_meta| match nested_meta {
report_path_args(sess, &meta);
meta.path
})
- .map(|path| (path, item.clone(), None))
- .collect()
+ .map(|path| (path, dummy_annotatable(), None))
+ .collect();
+
+ // Do not configure or clone items unless necessary.
+ match &mut resolutions[..] {
+ [] => {}
+ [(_, first_item, _), others @ ..] => {
+ *first_item = cfg_eval(sess, features, item.clone());
+ for (_, item, _) in others {
+ *item = first_item.clone();
+ }
+ }
+ }
+
+ resolutions
});
match result {
}
}
+// The cheapest `Annotatable` to construct.
+fn dummy_annotatable() -> Annotatable {
+ Annotatable::GenericParam(ast::GenericParam {
+ id: ast::DUMMY_NODE_ID,
+ ident: Ident::invalid(),
+ attrs: Default::default(),
+ bounds: Default::default(),
+ is_placeholder: false,
+ kind: GenericParamKind::Lifetime,
+ })
+}
+
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
let item_kind = match item {
Annotatable::Item(item) => Some(&item.kind),
/rand
/regex
/simple-raytracer
-/stdsimd
+/portable-simd
[[package]]
name = "cranelift-bforest"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
[[package]]
name = "cranelift-codegen-meta"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
[[package]]
name = "cranelift-codegen-shared"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
[[package]]
name = "cranelift-entity"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
[[package]]
name = "cranelift-frontend"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-jit"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-module"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"cranelift-codegen",
"libc",
[[package]]
name = "cranelift-object"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "addr2line"
-version = "0.14.1"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
+checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
dependencies = [
"compiler_builtins",
"gimli",
[[package]]
name = "cc"
-version = "1.0.69"
+version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cfg-if"
[[package]]
name = "compiler_builtins"
-version = "0.1.46"
+version = "0.1.50"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "gimli"
-version = "0.23.0"
+version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
[[package]]
name = "libc"
-version = "0.2.98"
+version = "0.2.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
dependencies = [
"rustc-std-workspace-core",
]
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
+
[[package]]
name = "miniz_oxide"
version = "0.4.4"
[[package]]
name = "object"
-version = "0.22.0"
+version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
+checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
dependencies = [
"compiler_builtins",
+ "memchr",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.20"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
+checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
[[package]]
name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
);
clone_repo(
- "stdsimd",
- "https://github.com/rust-lang/stdsimd",
- "be96995d8ddec03fac9a0caf4d4c51c7fbc33507",
+ "portable-simd",
+ "https://github.com/rust-lang/portable-simd",
+ "8cf7a62e5d2552961df51e5200aaa5b7c890a4bf",
);
- apply_patches("stdsimd", Path::new("stdsimd"));
+ apply_patches("portable-simd", Path::new("portable-simd"));
clone_repo(
"simple-raytracer",
clone_repo(
"build_sysroot/compiler-builtins",
"https://github.com/rust-lang/compiler-builtins.git",
- "0.1.46",
+ "0.1.50",
);
apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins"));
}
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
rm -rf target/ build/ perf.data{,.old}
-rm -rf rand/ regex/ simple-raytracer/ stdsimd/
+rm -rf rand/ regex/ simple-raytracer/ portable-simd/
## Jit mode
+> ⚠⚠⚠ The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. ⚠⚠⚠
+
In jit mode cg_clif will immediately execute your code without creating an executable file.
> This requires all dependencies to be available as dynamic library.
-#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)]
+#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler, box_syntax)]
#![no_std]
extern crate alloc;
-#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)]
+#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)]
#![no_core]
#![allow(dead_code, non_camel_case_types)]
--- /dev/null
+From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Sun, 25 Jul 2021 18:39:31 +0200
+Subject: [PATCH] Disable unsupported tests
+
+---
+ crates/core_simd/src/vector.rs | 2 ++
+ crates/core_simd/src/math.rs | 4 ++++
+ crates/core_simd/tests/masks.rs | 12 ------------
+ crates/core_simd/tests/ops_macros.rs | 6 ++++++
+ crates/core_simd/tests/round.rs | 2 ++
+ 6 files changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
+index 25c5309..2b3d819 100644
+--- a/crates/core_simd/src/vector.rs
++++ b/crates/core_simd/src/vector.rs
+@@ -22,6 +22,7 @@ where
+ self.0
+ }
+
++ /*
+ /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
+ /// If an index is out of bounds, that lane instead selects the value from the "or" vector.
+ /// ```
+@@ -150,6 +151,7 @@ where
+ // Cleared ☢️ *mut T Zone
+ }
+ }
++ */
+ }
+
+ impl<T, const LANES: usize> Copy for Simd<T, LANES>
+diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
+index 7290a28..e394730 100644
+--- a/crates/core_simd/src/math.rs
++++ b/crates/core_simd/src/math.rs
+@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith {
+ ($($ty:ty),+) => {
+ $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
+
++ /*
+ /// Lanewise saturating add.
+ ///
+ /// # Examples
+@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith {
+ pub fn saturating_sub(self, second: Self) -> Self {
+ unsafe { crate::intrinsics::simd_saturating_sub(self, second) }
+ }
++ */
+ })+
+ }
+ }
+@@ -46,6 +48,7 @@ macro_rules! impl_int_arith {
+ ($($ty:ty),+) => {
+ $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
+
++ /*
+ /// Lanewise saturating add.
+ ///
+ /// # Examples
+@@ -141,6 +144,7 @@ macro_rules! impl_int_arith {
+ pub fn saturating_neg(self) -> Self {
+ Self::splat(0).saturating_sub(self)
+ }
++ */
+ })+
+ }
+ }
+diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
+index 61d8e44..2bccae2 100644
+--- a/crates/core_simd/tests/masks.rs
++++ b/crates/core_simd/tests/masks.rs
+@@ -67,19 +67,6 @@ macro_rules! test_mask_api {
+ assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
+ assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
+ }
+-
+- #[cfg(feature = "generic_const_exprs")]
+- #[test]
+- fn roundtrip_bitmask_conversion() {
+- let values = [
+- true, false, false, true, false, false, true, false,
+- true, true, false, false, false, false, false, true,
+- ];
+- let mask = core_simd::Mask::<$type, 16>::from_array(values);
+- let bitmask = mask.to_bitmask();
+- assert_eq!(bitmask, [0b01001001, 0b10000011]);
+- assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
+- }
+ }
+ }
+ }
+diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
+index cb39e73..fc0ebe1 100644
+--- a/crates/core_simd/tests/ops_macros.rs
++++ b/crates/core_simd/tests/ops_macros.rs
+@@ -435,6 +435,7 @@ macro_rules! impl_float_tests {
+ )
+ }
+
++ /*
+ fn mul_add<const LANES: usize>() {
+ test_helpers::test_ternary_elementwise(
+ &Vector::<LANES>::mul_add,
+@@ -442,6 +443,7 @@ macro_rules! impl_float_tests {
+ &|_, _, _| true,
+ )
+ }
++ */
+
+ fn recip<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+@@ -581,6 +585,7 @@ macro_rules! impl_float_tests {
+ });
+ }
+
++ /*
+ fn horizontal_max<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ let vmax = Vector::<LANES>::from_array(x).horizontal_max();
+@@ -604,6 +609,7 @@ macro_rules! impl_float_tests {
+ Ok(())
+ });
+ }
++ */
+ }
+
+ #[cfg(feature = "std")]
+diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs
+index 37044a7..4cdc6b7 100644
+--- a/crates/core_simd/tests/round.rs
++++ b/crates/core_simd/tests/round.rs
+@@ -25,6 +25,7 @@ macro_rules! float_rounding_test {
+ )
+ }
+
++ /*
+ fn round<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::round,
+@@ -32,6 +33,7 @@ macro_rules! float_rounding_test {
+ &|_| true,
+ )
+ }
++ */
+
+ fn trunc<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+--
+2.26.2.7.g19db9cfb68
+
+++ /dev/null
-From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Sun, 25 Jul 2021 18:39:31 +0200
-Subject: [PATCH] Disable unsupported tests
-
----
- crates/core_simd/src/array.rs | 2 ++
- crates/core_simd/src/lib.rs | 2 +-
- crates/core_simd/src/math.rs | 4 ++++
- crates/core_simd/tests/masks.rs | 12 ------------
- crates/core_simd/tests/ops_macros.rs | 6 ++++++
- crates/core_simd/tests/round.rs | 2 ++
- 6 files changed, 15 insertions(+), 13 deletions(-)
-
-diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs
-index 25c5309..2b3d819 100644
---- a/crates/core_simd/src/array.rs
-+++ b/crates/core_simd/src/array.rs
-@@ -22,6 +22,7 @@ where
- #[must_use]
- fn splat(val: Self::Scalar) -> Self;
-
-+ /*
- /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
- /// If an index is out of bounds, that lane instead selects the value from the "or" vector.
- /// ```
-@@ -150,6 +151,7 @@ where
- // Cleared ☢️ *mut T Zone
- }
- }
-+ */
- }
-
- macro_rules! impl_simdarray_for {
-diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs
-index a64904d..299eb11 100644
---- a/crates/core_simd/src/lib.rs
-+++ b/crates/core_simd/src/lib.rs
-@@ -1,7 +1,7 @@
- #![no_std]
- #![allow(incomplete_features)]
- #![feature(
-- const_generics,
-+ const_generics,
- platform_intrinsics,
- repr_simd,
- simd_ffi,
-diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
-index 7290a28..e394730 100644
---- a/crates/core_simd/src/math.rs
-+++ b/crates/core_simd/src/math.rs
-@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith {
- ($(($name:ident, $n:ident)),+) => {
- $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
-
-+ /*
- /// Lanewise saturating add.
- ///
- /// # Examples
-@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith {
- pub fn saturating_sub(self, second: Self) -> Self {
- unsafe { crate::intrinsics::simd_saturating_sub(self, second) }
- }
-+ */
- })+
- }
- }
-@@ -46,6 +48,7 @@ macro_rules! impl_int_arith {
- ($(($name:ident, $n:ident)),+) => {
- $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
-
-+ /*
- /// Lanewise saturating add.
- ///
- /// # Examples
-@@ -141,6 +144,7 @@ macro_rules! impl_int_arith {
- pub fn saturating_neg(self) -> Self {
- Self::splat(0).saturating_sub(self)
- }
-+ */
- })+
- }
- }
-diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
-index 61d8e44..2bccae2 100644
---- a/crates/core_simd/tests/masks.rs
-+++ b/crates/core_simd/tests/masks.rs
-@@ -67,18 +67,6 @@ macro_rules! test_mask_api {
- assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
- assert_eq!(core_simd::$name::<8>::from_int(int), mask);
- }
--
-- #[test]
-- fn roundtrip_bitmask_conversion() {
-- let values = [
-- true, false, false, true, false, false, true, false,
-- true, true, false, false, false, false, false, true,
-- ];
-- let mask = core_simd::$name::<16>::from_array(values);
-- let bitmask = mask.to_bitmask();
-- assert_eq!(bitmask, [0b01001001, 0b10000011]);
-- assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask);
-- }
- }
- }
- }
-diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
-index cb39e73..fc0ebe1 100644
---- a/crates/core_simd/tests/ops_macros.rs
-+++ b/crates/core_simd/tests/ops_macros.rs
-@@ -435,6 +435,7 @@ macro_rules! impl_float_tests {
- )
- }
-
-+ /*
- fn mul_add<const LANES: usize>() {
- test_helpers::test_ternary_elementwise(
- &Vector::<LANES>::mul_add,
-@@ -442,6 +443,7 @@ macro_rules! impl_float_tests {
- &|_, _, _| true,
- )
- }
-+ */
-
- fn sqrt<const LANES: usize>() {
- test_helpers::test_unary_elementwise(
-@@ -581,6 +585,7 @@ macro_rules! impl_float_tests {
- });
- }
-
-+ /*
- fn horizontal_max<const LANES: usize>() {
- test_helpers::test_1(&|x| {
- let vmax = Vector::<LANES>::from_array(x).horizontal_max();
-@@ -604,6 +609,7 @@ macro_rules! impl_float_tests {
- Ok(())
- });
- }
-+ */
- }
- }
- }
-diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs
-index 37044a7..4cdc6b7 100644
---- a/crates/core_simd/tests/round.rs
-+++ b/crates/core_simd/tests/round.rs
-@@ -25,6 +25,7 @@ macro_rules! float_rounding_test {
- )
- }
-
-+ /*
- fn round<const LANES: usize>() {
- test_helpers::test_unary_elementwise(
- &Vector::<LANES>::round,
-@@ -32,6 +33,7 @@ macro_rules! float_rounding_test {
- &|_| true,
- )
- }
-+ */
-
- fn trunc<const LANES: usize>() {
- test_helpers::test_unary_elementwise(
---
-2.26.2.7.g19db9cfb68
-
-From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001
+From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001
From: bjorn3 <bjorn3@users.noreply.github.com>
Date: Thu, 18 Feb 2021 18:45:28 +0100
Subject: [PATCH] Disable 128bit atomic operations
library/core/src/panic/unwind_safe.rs | 6 -----
library/core/src/sync/atomic.rs | 38 ---------------------------
library/core/tests/atomic.rs | 4 ---
- 3 files changed, 48 deletions(-)
+ library/std/src/time/monotonic.rs | 6 +++--
+ 4 files changed, 4 insertions(+), 50 deletions(-)
diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
index 092b7cf..158cf71 100644
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
-index 0194c58..25a0038 100644
+index d9de37e..8293fce 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
-@@ -2229,44 +2229,6 @@ atomic_int! {
+@@ -2234,44 +2234,6 @@ atomic_int! {
"AtomicU64::new(0)",
u64 AtomicU64 ATOMIC_U64_INIT
}
#[cfg(target_has_atomic = "ptr")]
assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
#[cfg(target_has_atomic = "ptr")]
+diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
+index fa96b7a..2854f9c 100644
+--- a/library/std/src/time/monotonic.rs
++++ b/library/std/src/time/monotonic.rs
+@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
+ inner::monotonize(raw)
+ }
+
+-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
++#[cfg(target_has_atomic = "64")]
+ pub mod inner {
+ use crate::sync::atomic::AtomicU64;
+ use crate::sync::atomic::Ordering::*;
+@@ -70,6 +70,7 @@ pub mod inner {
+ }
+ }
+
++/*
+ #[cfg(target_has_atomic = "128")]
+ pub mod inner {
+ use crate::sync::atomic::AtomicU128;
+@@ -94,8 +95,9 @@ pub mod inner {
+ ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
+ }
+ }
++*/
+
+-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
++#[cfg(not(target_has_atomic = "64"))]
+ pub mod inner {
+ use crate::cmp;
+ use crate::sys::time;
--
2.26.2.7.g19db9cfb68
[toolchain]
-channel = "nightly-2021-08-05"
+channel = "nightly-2021-09-19"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
cargo install ripgrep
rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true
-for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do
+for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do
rm $test
done
fi
popd
- pushd stdsimd
- echo "[TEST] rust-lang/stdsimd"
+ pushd portable-simd
+ echo "[TEST] rust-lang/portable-simd"
../build/cargo clean
../build/cargo build --all-targets --target $TARGET_TRIPLE
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
//! Creation of ar archives like for the lib and staticlib crate type
use std::collections::BTreeMap;
+use std::convert::TryFrom;
use std::fs::File;
+use std::io::{self, Read, Seek};
use std::path::{Path, PathBuf};
use rustc_codegen_ssa::back::archive::ArchiveBuilder;
use rustc_session::Session;
-use object::{Object, ObjectSymbol, SymbolKind};
+use object::read::archive::ArchiveFile;
+use object::{Object, ObjectSymbol, ReadCache, SymbolKind};
#[derive(Debug)]
enum ArchiveEntry {
- FromArchive { archive_index: usize, entry_index: usize },
+ FromArchive { archive_index: usize, file_range: (u64, u64) },
File(PathBuf),
}
use_gnu_style_archive: bool,
no_builtin_ranlib: bool,
- src_archives: Vec<(PathBuf, ar::Archive<File>)>,
+ src_archives: Vec<File>,
// Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
// the end of an archive for linkers to not get confused.
- entries: Vec<(String, ArchiveEntry)>,
+ entries: Vec<(Vec<u8>, ArchiveEntry)>,
}
impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
let (src_archives, entries) = if let Some(input) = input {
- let mut archive = ar::Archive::new(File::open(input).unwrap());
+ let read_cache = ReadCache::new(File::open(input).unwrap());
+ let archive = ArchiveFile::parse(&read_cache).unwrap();
let mut entries = Vec::new();
- let mut i = 0;
- while let Some(entry) = archive.next_entry() {
+ for entry in archive.members() {
let entry = entry.unwrap();
entries.push((
- String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
- ArchiveEntry::FromArchive { archive_index: 0, entry_index: i },
+ entry.name().to_vec(),
+ ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() },
));
- i += 1;
}
- (vec![(input.to_owned(), archive)], entries)
+ (vec![read_cache.into_inner()], entries)
} else {
(vec![], Vec::new())
};
}
fn src_files(&mut self) -> Vec<String> {
- self.entries.iter().map(|(name, _)| name.clone()).collect()
+ self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect()
}
fn remove_file(&mut self, name: &str) {
let index = self
.entries
.iter()
- .position(|(entry_name, _)| entry_name == name)
+ .position(|(entry_name, _)| entry_name == name.as_bytes())
.expect("Tried to remove file not existing in src archive");
self.entries.remove(index);
}
fn add_file(&mut self, file: &Path) {
self.entries.push((
- file.file_name().unwrap().to_str().unwrap().to_string(),
+ file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
ArchiveEntry::File(file.to_owned()),
));
}
where
F: FnMut(&str) -> bool + 'static,
{
- let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
+ let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?);
+ let archive = ArchiveFile::parse(&read_cache).unwrap();
let archive_index = self.src_archives.len();
- let mut i = 0;
- while let Some(entry) = archive.next_entry() {
- let entry = entry?;
- let file_name = String::from_utf8(entry.header().identifier().to_vec())
- .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
+ for entry in archive.members() {
+ let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+ let file_name = String::from_utf8(entry.name().to_vec())
+ .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if !skip(&file_name) {
- self.entries
- .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
+ self.entries.push((
+ file_name.into_bytes(),
+ ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
+ ));
}
- i += 1;
}
- self.src_archives.push((archive_path.to_owned(), archive));
+ self.src_archives.push(read_cache.into_inner());
Ok(())
}
// FIXME only read the symbol table of the object files to avoid having to keep all
// object files in memory at once, or read them twice.
let data = match entry {
- ArchiveEntry::FromArchive { archive_index, entry_index } => {
+ ArchiveEntry::FromArchive { archive_index, file_range } => {
// FIXME read symbols from symtab
- use std::io::Read;
- let (ref _src_archive_path, ref mut src_archive) =
- self.src_archives[archive_index];
- let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
- let mut data = Vec::new();
- entry.read_to_end(&mut data).unwrap();
+ let src_read_cache = &mut self.src_archives[archive_index];
+
+ src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap();
+ let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap());
+ src_read_cache.read_exact(&mut data).unwrap();
+
data
}
ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
match object::File::parse(&*data) {
Ok(object) => {
symbol_table.insert(
- entry_name.as_bytes().to_vec(),
+ entry_name.to_vec(),
object
.symbols()
.filter_map(|symbol| {
} else {
sess.fatal(&format!(
"error parsing `{}` during archive creation: {}",
- entry_name, err
+ String::from_utf8_lossy(&entry_name),
+ err
));
}
}
err
));
}),
- entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
+ entries.iter().map(|(name, _)| name.clone()).collect(),
ar::GnuSymbolTableFormat::Size32,
symbol_table,
)
// Add all files
for (entry_name, data) in entries.into_iter() {
- let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
+ let header = ar::Header::new(entry_name, data.len() as u64);
match builder {
BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
+++ /dev/null
-//! Abstraction around the object writing crate
-
-use std::convert::{TryFrom, TryInto};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_session::Session;
-
-use cranelift_codegen::isa::TargetIsa;
-use cranelift_module::FuncId;
-use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-
-use object::write::*;
-use object::{RelocationEncoding, SectionKind, SymbolFlags};
-
-use gimli::SectionId;
-
-use crate::debuginfo::{DebugReloc, DebugRelocName};
-
-pub(crate) trait WriteMetadata {
- fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
-}
-
-impl WriteMetadata for object::write::Object {
- fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
- let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
- let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
- let offset = self.append_section_data(section_id, &data, 1);
- // For MachO and probably PE this is necessary to prevent the linker from throwing away the
- // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
- self.add_symbol(object::write::Symbol {
- name: symbol_name.into_bytes(),
- value: offset,
- size: data.len() as u64,
- kind: object::SymbolKind::Data,
- scope: object::SymbolScope::Dynamic,
- weak: false,
- section: SymbolSection::Section(section_id),
- flags: SymbolFlags::None,
- });
- }
-}
-
-pub(crate) trait WriteDebugInfo {
- type SectionId: Copy;
-
- fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
- fn add_debug_reloc(
- &mut self,
- section_map: &FxHashMap<SectionId, Self::SectionId>,
- from: &Self::SectionId,
- reloc: &DebugReloc,
- );
-}
-
-impl WriteDebugInfo for ObjectProduct {
- type SectionId = (object::write::SectionId, object::write::SymbolId);
-
- fn add_debug_section(
- &mut self,
- id: SectionId,
- data: Vec<u8>,
- ) -> (object::write::SectionId, object::write::SymbolId) {
- let name = if self.object.format() == object::BinaryFormat::MachO {
- id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
- } else {
- id.name().to_string()
- }
- .into_bytes();
-
- let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
- // FIXME use SHT_X86_64_UNWIND for .eh_frame
- let section_id = self.object.add_section(
- segment,
- name,
- if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
- );
- self.object
- .section_mut(section_id)
- .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
- let symbol_id = self.object.section_symbol(section_id);
- (section_id, symbol_id)
- }
-
- fn add_debug_reloc(
- &mut self,
- section_map: &FxHashMap<SectionId, Self::SectionId>,
- from: &Self::SectionId,
- reloc: &DebugReloc,
- ) {
- let (symbol, symbol_offset) = match reloc.name {
- DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
- DebugRelocName::Symbol(id) => {
- let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
- self.object
- .symbol_section_and_offset(symbol_id)
- .expect("Debug reloc for undef sym???")
- }
- };
- self.object
- .add_relocation(
- from.0,
- Relocation {
- offset: u64::from(reloc.offset),
- symbol,
- kind: reloc.kind,
- encoding: RelocationEncoding::Generic,
- size: reloc.size * 8,
- addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
- },
- )
- .unwrap();
- }
-}
-
-pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
- let triple = crate::target_triple(sess);
-
- let binary_format = match triple.binary_format {
- target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
- target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
- target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
- binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
- };
- let architecture = match triple.architecture {
- target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
- target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
- target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
- target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
- architecture => {
- sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
- }
- };
- let endian = match triple.endianness().unwrap() {
- target_lexicon::Endianness::Little => object::Endianness::Little,
- target_lexicon::Endianness::Big => object::Endianness::Big,
- };
-
- let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
- metadata_object.add_file_symbol(name.as_bytes().to_vec());
- f(&mut metadata_object);
- metadata_object.write().unwrap()
-}
-
-pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
- let mut builder =
- ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
- // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
- // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
- // can easily double the amount of time necessary to perform linking.
- builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
- ObjectModule::new(builder)
-}
let len = codegen_array_len(fx, place);
lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
}
+ Rvalue::ShallowInitBox(ref operand, content_ty) => {
+ let content_ty = fx.monomorphize(content_ty);
+ let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
+ let operand = codegen_operand(fx, operand);
+ let operand = operand.load_scalar(fx);
+ lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
+ }
Rvalue::NullaryOp(NullOp::Box, content_ty) => {
let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
let content_ty = fx.monomorphize(content_ty);
#![feature(rustc_private, once_cell)]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
extern crate rustc_data_structures;
extern crate rustc_driver;
//! target crates.
#![feature(rustc_private)]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
extern crate rustc_driver;
extern crate rustc_interface;
//! Write the debuginfo into an object file.
+use cranelift_object::ObjectProduct;
use rustc_data_structures::fx::FxHashMap;
use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
use gimli::{RunTimeEndian, SectionId};
-use crate::backend::WriteDebugInfo;
-
+use super::object::WriteDebugInfo;
use super::DebugContext;
impl DebugContext<'_> {
- pub(crate) fn emit<P: WriteDebugInfo>(&mut self, product: &mut P) {
+ pub(crate) fn emit(&mut self, product: &mut ObjectProduct) {
let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
let root = self.dwarf.unit.root();
let root = self.dwarf.unit.get_mut(root);
mod emit;
mod line_info;
+mod object;
mod unwind;
use crate::prelude::*;
--- /dev/null
+use std::convert::{TryFrom, TryInto};
+
+use rustc_data_structures::fx::FxHashMap;
+
+use cranelift_module::FuncId;
+use cranelift_object::ObjectProduct;
+
+use object::write::{Relocation, StandardSegment};
+use object::{RelocationEncoding, SectionKind};
+
+use gimli::SectionId;
+
+use crate::debuginfo::{DebugReloc, DebugRelocName};
+
+pub(super) trait WriteDebugInfo {
+ type SectionId: Copy;
+
+ fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
+ fn add_debug_reloc(
+ &mut self,
+ section_map: &FxHashMap<SectionId, Self::SectionId>,
+ from: &Self::SectionId,
+ reloc: &DebugReloc,
+ );
+}
+
+impl WriteDebugInfo for ObjectProduct {
+ type SectionId = (object::write::SectionId, object::write::SymbolId);
+
+ fn add_debug_section(
+ &mut self,
+ id: SectionId,
+ data: Vec<u8>,
+ ) -> (object::write::SectionId, object::write::SymbolId) {
+ let name = if self.object.format() == object::BinaryFormat::MachO {
+ id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
+ } else {
+ id.name().to_string()
+ }
+ .into_bytes();
+
+ let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
+ // FIXME use SHT_X86_64_UNWIND for .eh_frame
+ let section_id = self.object.add_section(
+ segment,
+ name,
+ if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
+ );
+ self.object
+ .section_mut(section_id)
+ .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
+ let symbol_id = self.object.section_symbol(section_id);
+ (section_id, symbol_id)
+ }
+
+ fn add_debug_reloc(
+ &mut self,
+ section_map: &FxHashMap<SectionId, Self::SectionId>,
+ from: &Self::SectionId,
+ reloc: &DebugReloc,
+ ) {
+ let (symbol, symbol_offset) = match reloc.name {
+ DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
+ DebugRelocName::Symbol(id) => {
+ let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
+ self.object
+ .symbol_section_and_offset(symbol_id)
+ .expect("Debug reloc for undef sym???")
+ }
+ };
+ self.object
+ .add_relocation(
+ from.0,
+ Relocation {
+ offset: u64::from(reloc.offset),
+ symbol,
+ kind: reloc.kind,
+ encoding: RelocationEncoding::Generic,
+ size: reloc.size * 8,
+ addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
+ },
+ )
+ .unwrap();
+ }
+}
use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
+use cranelift_object::ObjectProduct;
use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
use gimli::RunTimeEndian;
-use crate::backend::WriteDebugInfo;
+use super::object::WriteDebugInfo;
pub(crate) struct UnwindContext {
endian: RunTimeEndian,
}
}
- pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
+ pub(crate) fn emit(self, product: &mut ObjectProduct) {
let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{DebugInfo, OutputType};
+use rustc_session::Session;
-use cranelift_object::ObjectModule;
+use cranelift_codegen::isa::TargetIsa;
+use cranelift_object::{ObjectBuilder, ObjectModule};
use crate::{prelude::*, BackendConfig};
}
}
+fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+ let mut builder =
+ ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
+ // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
+ // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
+ // can easily double the amount of time necessary to perform linking.
+ builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
+ ObjectModule::new(builder)
+}
+
fn emit_module(
tcx: TyCtxt<'_>,
backend_config: &BackendConfig,
let mono_items = cgu.items_in_deterministic_order(tcx);
let isa = crate::build_isa(tcx.sess, &backend_config);
- let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
+ let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string());
let mut cx = crate::CodegenCx::new(
tcx,
tcx.sess.abort_if_errors();
let isa = crate::build_isa(tcx.sess, &backend_config);
- let mut allocator_module =
- crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
+ let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string());
assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
let created_alloc_shim =
let tmp_file =
tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
- let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
- crate::metadata::write_metadata(tcx, object);
- });
+ let obj = crate::metadata::new_metadata_object(tcx, &metadata_cgu_name, &metadata);
if let Err(err) = std::fs::write(&tmp_file, obj) {
tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
-#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)]
+#![feature(rustc_private, decl_macro)]
+#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]
mod allocator;
mod analyze;
mod archive;
-mod backend;
mod base;
mod cast;
mod codegen_i128;
//! Writing of the rustc metadata for dylibs
-use rustc_middle::ty::TyCtxt;
+use object::write::{Object, StandardSegment, Symbol, SymbolSection};
+use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope};
-use crate::backend::WriteMetadata;
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
// Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
-pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
+pub(crate) fn new_metadata_object(tcx: TyCtxt<'_>, cgu_name: &str, metadata: &EncodedMetadata) -> Vec<u8> {
use snap::write::FrameEncoder;
use std::io::Write;
- let metadata = tcx.encode_metadata();
let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
- object.add_rustc_section(
- rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
- compressed,
- );
+ let triple = crate::target_triple(tcx.sess);
+
+ let binary_format = match triple.binary_format {
+ target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
+ target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
+ target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
+ binary_format => tcx.sess.fatal(&format!("binary format {} is unsupported", binary_format)),
+ };
+ let architecture = match triple.architecture {
+ target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
+ target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
+ target_lexicon::Architecture::Avr => object::Architecture::Avr,
+ target_lexicon::Architecture::Hexagon => object::Architecture::Hexagon,
+ target_lexicon::Architecture::Mips32(_) => object::Architecture::Mips,
+ target_lexicon::Architecture::Mips64(_) => object::Architecture::Mips64,
+ target_lexicon::Architecture::Msp430 => object::Architecture::Msp430,
+ target_lexicon::Architecture::Powerpc => object::Architecture::PowerPc,
+ target_lexicon::Architecture::Powerpc64 => object::Architecture::PowerPc64,
+ target_lexicon::Architecture::Powerpc64le => todo!(),
+ target_lexicon::Architecture::Riscv32(_) => object::Architecture::Riscv32,
+ target_lexicon::Architecture::Riscv64(_) => object::Architecture::Riscv64,
+ target_lexicon::Architecture::S390x => object::Architecture::S390x,
+ target_lexicon::Architecture::Sparc64 => object::Architecture::Sparc64,
+ target_lexicon::Architecture::Sparcv9 => object::Architecture::Sparc64,
+ target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
+ target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
+ architecture => {
+ tcx.sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
+ }
+ };
+ let endian = match triple.endianness().unwrap() {
+ target_lexicon::Endianness::Little => object::Endianness::Little,
+ target_lexicon::Endianness::Big => object::Endianness::Big,
+ };
+
+ let mut object = Object::new(binary_format, architecture, endian);
+ object.add_file_symbol(cgu_name.as_bytes().to_vec());
+
+ let segment = object.segment_name(StandardSegment::Data).to_vec();
+ let section_id = object.add_section(segment, b".rustc".to_vec(), SectionKind::Data);
+ let offset = object.append_section_data(section_id, &compressed, 1);
+ // For MachO and probably PE this is necessary to prevent the linker from throwing away the
+ // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
+ object.add_symbol(Symbol {
+ name: rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx).into_bytes(),
+ value: offset,
+ size: compressed.len() as u64,
+ kind: SymbolKind::Data,
+ scope: SymbolScope::Dynamic,
+ weak: false,
+ section: SymbolSection::Section(section_id),
+ flags: SymbolFlags::None,
+ });
+
+ object.write().unwrap()
}
--- /dev/null
+name: CI
+
+on:
+ - push
+ - pull_request
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install packages
+ run: sudo apt-get install ninja-build ripgrep
+
+ - name: Download artifact
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ workflow: main.yml
+ name: libgccjit.so
+ path: gcc-build
+ repo: antoyo/gcc
+
+ - name: Setup path to libgccjit
+ run: |
+ echo $(readlink -f gcc-build) > gcc_path
+ ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0
+
+ - name: Set LIBRARY_PATH
+ run: |
+ echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
+ echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
+
+ # https://github.com/actions/cache/issues/133
+ - name: Fixup owner of ~/.cargo/
+ # Don't remove the trailing /. It is necessary to follow the symlink.
+ run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/
+
+ - name: Cache cargo installed crates
+ uses: actions/cache@v1.1.2
+ with:
+ path: ~/.cargo/bin
+ key: cargo-installed-crates2-ubuntu-latest
+
+ - name: Cache cargo registry
+ uses: actions/cache@v1
+ with:
+ path: ~/.cargo/registry
+ key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }}
+
+ - name: Cache cargo index
+ uses: actions/cache@v1
+ with:
+ path: ~/.cargo/git
+ key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
+
+ - name: Cache cargo target dir
+ uses: actions/cache@v1.1.2
+ with:
+ path: target
+ key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
+
+ - name: Build
+ run: |
+ ./prepare_build.sh
+ ./build.sh
+ cargo test
+ ./clean_all.sh
+
+ - name: Prepare dependencies
+ run: |
+ git config --global user.email "user@example.com"
+ git config --global user.name "User"
+ ./prepare.sh
+
+ # Compile is a separate step, as the actions-rs/cargo action supports error annotations
+ - name: Compile
+ uses: actions-rs/cargo@v1.0.3
+ with:
+ command: build
+ args: --release
+
+ - name: Test
+ run: |
+ # Enable backtraces for easier debugging
+ export RUST_BACKTRACE=1
+
+ # Reduce amount of benchmark runs as they are slow
+ export COMPILE_RUNS=2
+ export RUN_RUNS=2
+
+ ./test.sh --release
--- /dev/null
+target
+**/*.rs.bk
+*.rlib
+*.o
+perf.data
+perf.data.old
+*.events
+*.string*
+/build_sysroot/sysroot
+/build_sysroot/sysroot_src
+/build_sysroot/Cargo.lock
+/build_sysroot/test_target/Cargo.lock
+/rust
+/simple-raytracer
+/regex
+gimple*
+*asm
+res
+test-backend
+gcc_path
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ar"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "fm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68fda3cff2cce84c19e5dfa5179a4b35d2c0f18b893f108002b8a6a54984acca"
+dependencies = [
+ "regex",
+]
+
+[[package]]
+name = "gccjit"
+version = "1.0.0"
+source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+dependencies = [
+ "gccjit_sys",
+]
+
+[[package]]
+name = "gccjit_sys"
+version = "0.0.1"
+source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+dependencies = [
+ "libc 0.1.12",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc 0.2.102",
+ "wasi",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "lang_tester"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090"
+dependencies = [
+ "fm",
+ "getopts",
+ "libc 0.2.102",
+ "num_cpus",
+ "termcolor",
+ "threadpool",
+ "wait-timeout",
+ "walkdir",
+]
+
+[[package]]
+name = "libc"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
+
+[[package]]
+name = "libc"
+version = "0.2.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "object"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+dependencies = [
+ "libc 0.2.102",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rustc_codegen_gcc"
+version = "0.1.0"
+dependencies = [
+ "ar",
+ "gccjit",
+ "lang_tester",
+ "object",
+ "target-lexicon",
+ "tempfile",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc 0.2.102",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
--- /dev/null
+[package]
+name = "rustc_codegen_gcc"
+version = "0.1.0"
+authors = ["Antoni Boucher <bouanto@zoho.com>"]
+edition = "2018"
+license = "MIT OR Apache-2.0"
+
+[lib]
+crate-type = ["dylib"]
+
+[[test]]
+name = "lang_tests"
+path = "tests/lib.rs"
+harness = false
+
+[dependencies]
+gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
+
+# Local copy.
+#gccjit = { path = "../gccjit.rs" }
+
+target-lexicon = "0.10.0"
+
+ar = "0.8.0"
+
+[dependencies.object]
+version = "0.25.0"
+default-features = false
+features = ["read", "std", "write"] # We don't need WASM support.
+
+[dev-dependencies]
+lang_tester = "0.3.9"
+tempfile = "3.1.0"
+
+[profile.dev]
+# By compiling dependencies with optimizations, performing tests gets much faster.
+opt-level = 3
+
+[profile.dev.package.rustc_codegen_gcc]
+# Disabling optimizations for cg_gccjit itself makes compilation after a change faster.
+opt-level = 0
+
+# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the
+# execution time of build scripts is so fast that optimizing them slows down the total build time.
+[profile.dev.build-override]
+opt-level = 0
+debug = false
+
+[profile.release.build-override]
+opt-level = 0
+debug = false
--- /dev/null
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
--- /dev/null
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
--- /dev/null
+# WIP libgccjit codegen backend for rust
+
+This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used.
+
+**Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.**
+
+## Motivation
+
+The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM.
+A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc.
+
+## Building
+
+**This requires a patched libgccjit in order to work.
+The patches in [this repostory](https://github.com/antoyo/libgccjit-patches) need to be applied.
+(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.)
+You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
+
+**Put the path to your custom build of libgccjit in the file `gcc_path`.**
+
+```bash
+$ git clone https://github.com/rust-lang/rustc_codegen_gcc.git
+$ cd rustc_codegen_gcc
+$ ./prepare_build.sh # download and patch sysroot src
+$ ./build.sh --release
+```
+
+To run the tests:
+
+```bash
+$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking
+$ ./test.sh --release
+```
+
+## Usage
+
+`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions.
+
+### Cargo
+
+```bash
+$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run
+```
+
+If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely.
+
+### Rustc
+
+> You should prefer using the Cargo method.
+
+```bash
+$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs
+```
+
+## Env vars
+
+<dl>
+ <dt>CG_GCCJIT_INCR_CACHE_DISABLED</dt>
+ <dd>Don't cache object files in the incremental cache. Useful during development of cg_gccjit
+ to make it possible to use incremental mode for all analyses performed by rustc without caching
+ object files when their content should have been changed by a change to cg_gccjit.</dd>
+ <dt>CG_GCCJIT_DISPLAY_CG_TIME</dt>
+ <dd>Display the time it took to perform codegen for a crate</dd>
+</dl>
+
+## Debugging
+
+Sometimes, libgccjit will crash and output an error like this:
+
+```
+during RTL pass: expand
+libgccjit.so: error: in expmed_mode_index, at expmed.h:249
+0x7f0da2e61a35 expmed_mode_index
+ ../../../gcc/gcc/expmed.h:249
+0x7f0da2e61aa4 expmed_op_cost_ptr
+ ../../../gcc/gcc/expmed.h:271
+0x7f0da2e620dc sdiv_cost_ptr
+ ../../../gcc/gcc/expmed.h:540
+0x7f0da2e62129 sdiv_cost
+ ../../../gcc/gcc/expmed.h:558
+0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int)
+ ../../../gcc/gcc/expmed.c:4335
+0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier)
+ ../../../gcc/gcc/expr.c:9240
+0x7f0da2cd1a1e expand_gimple_stmt_1
+ ../../../gcc/gcc/cfgexpand.c:3796
+0x7f0da2cd1c30 expand_gimple_stmt
+ ../../../gcc/gcc/cfgexpand.c:3857
+0x7f0da2cd90a9 expand_gimple_basic_block
+ ../../../gcc/gcc/cfgexpand.c:5898
+0x7f0da2cdade8 execute
+ ../../../gcc/gcc/cfgexpand.c:6582
+```
+
+To see the code which causes this error, call the following function:
+
+```c
+gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */)
+```
+
+This will create a C-like file and add the locations into the IR pointing to this C file.
+Then, rerun the program and it will output the location in the second line:
+
+```
+libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249
+```
+
+Or add a breakpoint to `add_error` in gdb and print the line number using:
+
+```
+p loc->m_line
+```
+
+### How to use a custom-build rustc
+
+ * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`).
+ * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`.
+
+### How to build a cross-compiling libgccjit
+
+#### Building libgccjit
+
+ * Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes:
+ * Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`.
+ * Some shells, like fish, don't define the environment variable `$MACHTYPE`.
+ * Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian).
+
+#### Configuring rustc_codegen_gcc
+
+ * Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh.
+ * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler).
+ * Set `linker='-Clinker=m68k-linux-gcc'`.
+ * Set the path to the cross-compiling libgccjit in `gcc_path`.
+ * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::<i64>();` in `context.rs` (same for u128_type).
+ * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?).
--- /dev/null
+#!/bin/bash
+
+#set -x
+set -e
+
+if [ -f ./gcc_path ]; then
+ export GCC_PATH=$(cat gcc_path)
+else
+ echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
+ exit 1
+fi
+
+export LD_LIBRARY_PATH="$GCC_PATH"
+export LIBRARY_PATH="$GCC_PATH"
+
+if [[ "$1" == "--release" ]]; then
+ export CHANNEL='release'
+ CARGO_INCREMENTAL=1 cargo rustc --release
+else
+ echo $LD_LIBRARY_PATH
+ export CHANNEL='debug'
+ cargo rustc
+fi
+
+source config.sh
+
+rm -r target/out || true
+mkdir -p target/out/gccjit
+
+echo "[BUILD] sysroot"
+time ./build_sysroot/build_sysroot.sh $CHANNEL
--- /dev/null
+[package]
+authors = ["bjorn3 <bjorn3@users.noreply.github.com>"]
+name = "sysroot"
+version = "0.0.0"
+
+[dependencies]
+core = { path = "./sysroot_src/library/core" }
+compiler_builtins = "0.1"
+alloc = { path = "./sysroot_src/library/alloc" }
+std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
+test = { path = "./sysroot_src/library/test" }
+
+[patch.crates-io]
+rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
+rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
+rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
+
+[profile.release]
+debug = true
--- /dev/null
+#!/bin/bash
+
+# Requires the CHANNEL env var to be set to `debug` or `release.`
+
+set -e
+cd $(dirname "$0")
+
+pushd ../ >/dev/null
+source ./config.sh
+popd >/dev/null
+
+# Cleanup for previous run
+# v Clean target dir except for build scripts and incremental cache
+rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true
+rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true
+rm -r sysroot/ 2>/dev/null || true
+
+# Build libs
+export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort"
+if [[ "$1" == "--release" ]]; then
+ sysroot_channel='release'
+ RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release
+else
+ sysroot_channel='debug'
+ cargo build --target $TARGET_TRIPLE
+fi
+
+# Copy files to sysroot
+mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
+cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
--- /dev/null
+#!/bin/bash
+set -e
+cd $(dirname "$0")
+
+SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/"
+DST_DIR="sysroot_src"
+
+if [ ! -e $SRC_DIR ]; then
+ echo "Please install rust-src component"
+ exit 1
+fi
+
+rm -rf $DST_DIR
+mkdir -p $DST_DIR/library
+cp -r $SRC_DIR/library $DST_DIR/
+
+pushd $DST_DIR
+echo "[GIT] init"
+git init
+echo "[GIT] add"
+git add .
+echo "[GIT] commit"
+
+# This is needed on systems where nothing is configured.
+# git really needs something here, or it will fail.
+# Even using --author is not enough.
+git config user.email || git config user.email "none@example.com"
+git config user.name || git config user.name "None"
+
+git commit -m "Initial commit" -q
+for file in $(ls ../../patches/ | grep -v patcha); do
+echo "[GIT] apply" $file
+git apply ../../patches/$file
+git add -A
+git commit --no-gpg-sign -m "Patch $file"
+done
+popd
+
+echo "Successfully prepared libcore for building"
--- /dev/null
+#![no_std]
--- /dev/null
+#!/bin/bash
+
+if [ -z $CHANNEL ]; then
+export CHANNEL='debug'
+fi
+
+pushd $(dirname "$0") >/dev/null
+source config.sh
+
+# read nightly compiler from rust-toolchain file
+TOOLCHAIN=$(cat rust-toolchain)
+
+popd >/dev/null
+
+if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then
+ echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)."
+ echo "Using $(rustc +${TOOLCHAIN} -V)."
+fi
+
+cmd=$1
+shift
+
+RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@
--- /dev/null
+#!/bin/bash --verbose
+set -e
+
+rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old}
+rm -rf regex/ simple-raytracer/
--- /dev/null
+set -e
+
+export CARGO_INCREMENTAL=0
+
+if [ -f ./gcc_path ]; then
+ export GCC_PATH=$(cat gcc_path)
+else
+ echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
+ exit 1
+fi
+
+unamestr=`uname`
+if [[ "$unamestr" == 'Linux' ]]; then
+ dylib_ext='so'
+elif [[ "$unamestr" == 'Darwin' ]]; then
+ dylib_ext='dylib'
+else
+ echo "Unsupported os"
+ exit 1
+fi
+
+HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+TARGET_TRIPLE=$HOST_TRIPLE
+#TARGET_TRIPLE="m68k-unknown-linux-gnu"
+
+linker=''
+RUN_WRAPPER=''
+if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
+ if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then
+ TARGET_TRIPLE="mips-unknown-linux-gnu"
+ linker='-Clinker=m68k-linux-gcc'
+ elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
+ # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+ linker='-Clinker=aarch64-linux-gnu-gcc'
+ RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
+ else
+ echo "Unknown non-native platform"
+ fi
+fi
+
+export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
+
+# FIXME(antoyo): remove once the atomic shim is gone
+if [[ `uname` == 'Darwin' ]]; then
+ export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
+fi
+
+RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out"
+export RUSTC_LOG=warn # display metadata load errors
+
+export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH"
+export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
--- /dev/null
+#![feature(start, box_syntax, core_intrinsics, alloc_prelude, alloc_error_handler)]
+#![no_std]
+
+extern crate alloc;
+extern crate alloc_system;
+
+use alloc::prelude::v1::*;
+
+use alloc_system::System;
+
+#[global_allocator]
+static ALLOC: System = System;
+
+#[link(name = "c")]
+extern "C" {
+ fn puts(s: *const u8) -> i32;
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+ unsafe {
+ core::intrinsics::abort();
+ }
+}
+
+#[alloc_error_handler]
+fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
+ unsafe {
+ core::intrinsics::abort();
+ }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+ let world: Box<&str> = box "Hello World!\0";
+ unsafe {
+ puts(*world as *const str as *const u8);
+ }
+
+ 0
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![no_std]
+#![feature(allocator_api, rustc_private)]
+#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
+
+// The minimum alignment guaranteed by the architecture. This value is used to
+// add fast paths for low alignment values.
+#[cfg(all(any(target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "powerpc",
+ target_arch = "powerpc64")))]
+const MIN_ALIGN: usize = 8;
+#[cfg(all(any(target_arch = "x86_64",
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64")))]
+const MIN_ALIGN: usize = 16;
+
+pub struct System;
+#[cfg(any(windows, unix, target_os = "redox"))]
+mod realloc_fallback {
+ use core::alloc::{GlobalAlloc, Layout};
+ use core::cmp;
+ use core::ptr;
+ impl super::System {
+ pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
+ new_size: usize) -> *mut u8 {
+ // Docs for GlobalAlloc::realloc require this to be valid:
+ let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
+ let new_ptr = GlobalAlloc::alloc(self, new_layout);
+ if !new_ptr.is_null() {
+ let size = cmp::min(old_layout.size(), new_size);
+ ptr::copy_nonoverlapping(ptr, new_ptr, size);
+ GlobalAlloc::dealloc(self, ptr, old_layout);
+ }
+ new_ptr
+ }
+ }
+}
+#[cfg(any(unix, target_os = "redox"))]
+mod platform {
+ extern crate libc;
+ use core::ptr;
+ use MIN_ALIGN;
+ use System;
+ use core::alloc::{GlobalAlloc, Layout};
+ unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::malloc(layout.size()) as *mut u8
+ } else {
+ #[cfg(target_os = "macos")]
+ {
+ if layout.align() > (1 << 31) {
+ return ptr::null_mut()
+ }
+ }
+ aligned_malloc(&layout)
+ }
+ }
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::calloc(layout.size(), 1) as *mut u8
+ } else {
+ let ptr = self.alloc(layout.clone());
+ if !ptr.is_null() {
+ ptr::write_bytes(ptr, 0, layout.size());
+ }
+ ptr
+ }
+ }
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ libc::free(ptr as *mut libc::c_void)
+ }
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+ } else {
+ self.realloc_fallback(ptr, layout, new_size)
+ }
+ }
+ }
+ #[cfg(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris"))]
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ // On android we currently target API level 9 which unfortunately
+ // doesn't have the `posix_memalign` API used below. Instead we use
+ // `memalign`, but this unfortunately has the property on some systems
+ // where the memory returned cannot be deallocated by `free`!
+ //
+ // Upon closer inspection, however, this appears to work just fine with
+ // Android, so for this platform we should be fine to call `memalign`
+ // (which is present in API level 9). Some helpful references could
+ // possibly be chromium using memalign [1], attempts at documenting that
+ // memalign + free is ok [2] [3], or the current source of chromium
+ // which still uses memalign on android [4].
+ //
+ // [1]: https://codereview.chromium.org/10796020/
+ // [2]: https://code.google.com/p/android/issues/detail?id=35391
+ // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+ // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+ // /memory/aligned_memory.cc
+ libc::memalign(layout.align(), layout.size()) as *mut u8
+ }
+ #[cfg(not(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris")))]
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ let mut out = ptr::null_mut();
+ let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
+ if ret != 0 {
+ ptr::null_mut()
+ } else {
+ out as *mut u8
+ }
+ }
+}
+#[cfg(windows)]
+#[allow(nonstandard_style)]
+mod platform {
+ use MIN_ALIGN;
+ use System;
+ use core::alloc::{GlobalAlloc, Layout};
+ type LPVOID = *mut u8;
+ type HANDLE = LPVOID;
+ type SIZE_T = usize;
+ type DWORD = u32;
+ type BOOL = i32;
+ extern "system" {
+ fn GetProcessHeap() -> HANDLE;
+ fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+ fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+ fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+ fn GetLastError() -> DWORD;
+ }
+ #[repr(C)]
+ struct Header(*mut u8);
+ const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+ unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+ &mut *(ptr as *mut Header).offset(-1)
+ }
+ unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+ let aligned = ptr.add(align - (ptr as usize & (align - 1)));
+ *get_header(aligned) = Header(ptr);
+ aligned
+ }
+ #[inline]
+ unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
+ let ptr = if layout.align() <= MIN_ALIGN {
+ HeapAlloc(GetProcessHeap(), flags, layout.size())
+ } else {
+ let size = layout.size() + layout.align();
+ let ptr = HeapAlloc(GetProcessHeap(), flags, size);
+ if ptr.is_null() {
+ ptr
+ } else {
+ align_ptr(ptr, layout.align())
+ }
+ };
+ ptr as *mut u8
+ }
+ unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ allocate_with_flags(layout, 0)
+ }
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ allocate_with_flags(layout, HEAP_ZERO_MEMORY)
+ }
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ if layout.align() <= MIN_ALIGN {
+ let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+ debug_assert!(err != 0, "Failed to free heap memory: {}",
+ GetLastError());
+ } else {
+ let header = get_header(ptr);
+ let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+ debug_assert!(err != 0, "Failed to free heap memory: {}",
+ GetLastError());
+ }
+ }
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN {
+ HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
+ } else {
+ self.realloc_fallback(ptr, layout, new_size)
+ }
+ }
+ }
+}
--- /dev/null
+// Adapted from rustc run-pass test suite
+
+#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
+#![feature(rustc_attrs)]
+
+use std::{
+ ops::{Deref, CoerceUnsized, DispatchFromDyn},
+ marker::Unsize,
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &*self.0
+ }
+}
+
+impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
+
+struct Wrapper<T: ?Sized>(T);
+
+impl<T: ?Sized> Deref for Wrapper<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
+
+
+trait Trait {
+ // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
+ // without unsized_locals), but wrappers arond `Self` currently are not.
+ // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
+ // fn wrapper(self: Wrapper<Self>) -> i32;
+ fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
+ fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
+ fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
+}
+
+impl Trait for i32 {
+ fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 {
+ **self
+ }
+ fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
+ **self
+ }
+ fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
+ ***self
+ }
+}
+
+fn main() {
+ let pw = Ptr(Box::new(Wrapper(5))) as Ptr<Wrapper<dyn Trait>>;
+ assert_eq!(pw.ptr_wrapper(), 5);
+
+ let wp = Wrapper(Ptr(Box::new(6))) as Wrapper<Ptr<dyn Trait>>;
+ assert_eq!(wp.wrapper_ptr(), 6);
+
+ let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
+ assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+struct Foo<T: ?Sized> {
+ a: u16,
+ b: T
+}
+
+trait Bar {
+ fn get(&self) -> usize;
+}
+
+impl Bar for usize {
+ fn get(&self) -> usize { *self }
+}
+
+struct Baz<T: ?Sized> {
+ a: T
+}
+
+struct HasDrop<T: ?Sized> {
+ ptr: Box<usize>,
+ data: T
+}
+
+fn main() {
+ // Test that zero-offset works properly
+ let b : Baz<usize> = Baz { a: 7 };
+ assert_eq!(b.a.get(), 7);
+ let b : &Baz<dyn Bar> = &b;
+ assert_eq!(b.a.get(), 7);
+
+ // Test that the field is aligned properly
+ let f : Foo<usize> = Foo { a: 0, b: 11 };
+ assert_eq!(f.b.get(), 11);
+ let ptr1 : *const u8 = &f.b as *const _ as *const u8;
+
+ let f : &Foo<dyn Bar> = &f;
+ let ptr2 : *const u8 = &f.b as *const _ as *const u8;
+ assert_eq!(f.b.get(), 11);
+
+ // The pointers should be the same
+ assert_eq!(ptr1, ptr2);
+
+ // Test that nested DSTs work properly
+ let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
+ assert_eq!(f.b.b.get(), 17);
+ let f : &Foo<Foo<dyn Bar>> = &f;
+ assert_eq!(f.b.b.get(), 17);
+
+ // Test that get the pointer via destructuring works
+
+ let f : Foo<usize> = Foo { a: 0, b: 11 };
+ let f : &Foo<dyn Bar> = &f;
+ let &Foo { a: _, b: ref bar } = f;
+ assert_eq!(bar.get(), 11);
+
+ // Make sure that drop flags don't screw things up
+
+ let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
+ ptr: Box::new(0),
+ data: Baz { a: [1,2,3,4] }
+ };
+ assert_eq!([1,2,3,4], d.data.a);
+
+ let d : &HasDrop<Baz<[i32]>> = &d;
+ assert_eq!(&[1,2,3,4], &d.data.a);
+}
--- /dev/null
+#![feature(no_core, unboxed_closures)]
+#![no_core]
+#![allow(dead_code)]
+
+extern crate mini_core;
+
+use mini_core::*;
+
+fn abc(a: u8) -> u8 {
+ a * 2
+}
+
+fn bcd(b: bool, a: u8) -> u8 {
+ if b {
+ a * 2
+ } else {
+ a * 3
+ }
+}
+
+fn call() {
+ abc(42);
+}
+
+fn indirect_call() {
+ let f: fn() = call;
+ f();
+}
+
+enum BoolOption {
+ Some(bool),
+ None,
+}
+
+fn option_unwrap_or(o: BoolOption, d: bool) -> bool {
+ match o {
+ BoolOption::Some(b) => b,
+ BoolOption::None => d,
+ }
+}
+
+fn ret_42() -> u8 {
+ 42
+}
+
+fn return_str() -> &'static str {
+ "hello world"
+}
+
+fn promoted_val() -> &'static u8 {
+ &(1 * 2)
+}
+
+fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 {
+ abc as *const u8
+}
+
+fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool {
+ a == b
+}
+
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+ (
+ a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+ b as u32,
+ )
+}
+
+fn char_cast(c: char) -> u8 {
+ c as u8
+}
+
+pub struct DebugTuple(());
+
+fn debug_tuple() -> DebugTuple {
+ DebugTuple(())
+}
+
+fn size_of<T>() -> usize {
+ intrinsics::size_of::<T>()
+}
+
+fn use_size_of() -> usize {
+ size_of::<u64>()
+}
+
+unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) {
+ intrinsics::copy::<u8>(src, dst, 1);
+}
+
+unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) {
+ let copy2 = &intrinsics::copy::<u8>;
+ copy2(src, dst, 1);
+}
+
+const ABC: u8 = 6 * 7;
+
+fn use_const() -> u8 {
+ ABC
+}
+
+pub fn call_closure_3arg() {
+ (|_, _, _| {})(0u8, 42u16, 0u8)
+}
+
+pub fn call_closure_2arg() {
+ (|_, _| {})(0u8, 42u16)
+}
+
+struct IsNotEmpty;
+
+impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty {
+ type Output = (u8, u8);
+
+ #[inline]
+ extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) {
+ self.call_mut(arg)
+ }
+}
+
+impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty {
+ #[inline]
+ extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) {
+ (0, 42)
+ }
+}
+
+pub fn call_is_not_empty() {
+ IsNotEmpty.call_once((&(&[0u16] as &[_]),));
+}
+
+fn eq_char(a: char, b: char) -> bool {
+ a == b
+}
+
+unsafe fn transmute(c: char) -> u32 {
+ intrinsics::transmute(c)
+}
+
+unsafe fn deref_str_ptr(s: *const str) -> &'static str {
+ &*s
+}
+
+fn use_array(arr: [u8; 3]) -> u8 {
+ arr[1]
+}
+
+fn repeat_array() -> [u8; 3] {
+ [0; 3]
+}
+
+fn array_as_slice(arr: &[u8; 3]) -> &[u8] {
+ arr
+}
+
+unsafe fn use_ctlz_nonzero(a: u16) -> u16 {
+ intrinsics::ctlz_nonzero(a)
+}
+
+fn ptr_as_usize(ptr: *const u8) -> usize {
+ ptr as usize
+}
+
+fn float_cast(a: f32, b: f64) -> (f64, f32) {
+ (a as f64, b as f32)
+}
+
+fn int_to_float(a: u8, b: i32) -> (f64, f32) {
+ (a as f64, b as f32)
+}
+
+fn make_array() -> [u8; 3] {
+ [42, 0, 5]
+}
+
+fn some_promoted_tuple() -> &'static (&'static str, &'static str) {
+ &("abc", "some")
+}
+
+fn index_slice(s: &[u8]) -> u8 {
+ s[2]
+}
+
+pub struct StrWrapper {
+ s: str,
+}
+
+fn str_wrapper_get(w: &StrWrapper) -> &str {
+ &w.s
+}
+
+fn i16_as_i8(a: i16) -> i8 {
+ a as i8
+}
+
+struct Unsized(u8, str);
+
+fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 {
+ &u.0
+}
+
+fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str {
+ &u.1
+}
+
+pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 {
+ a.0
+}
--- /dev/null
+#![feature(
+ no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
+ untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits,
+ thread_local
+)]
+#![no_core]
+#![allow(dead_code)]
+
+#[no_mangle]
+unsafe extern "C" fn _Unwind_Resume() {
+ intrinsics::unreachable();
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "dispatch_from_dyn"]
+pub trait DispatchFromDyn<T> {}
+
+// &T -> &U
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+// &mut T -> &mut U
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+// *const T -> *const U
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+// *mut T -> *mut U
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
+
+#[lang = "receiver"]
+pub trait Receiver {}
+
+impl<T: ?Sized> Receiver for &T {}
+impl<T: ?Sized> Receiver for &mut T {}
+impl<T: ?Sized> Receiver for Box<T> {}
+
+#[lang = "copy"]
+pub unsafe trait Copy {}
+
+unsafe impl Copy for bool {}
+unsafe impl Copy for u8 {}
+unsafe impl Copy for u16 {}
+unsafe impl Copy for u32 {}
+unsafe impl Copy for u64 {}
+unsafe impl Copy for usize {}
+unsafe impl Copy for i8 {}
+unsafe impl Copy for i16 {}
+unsafe impl Copy for i32 {}
+unsafe impl Copy for isize {}
+unsafe impl Copy for f32 {}
+unsafe impl Copy for char {}
+unsafe impl<'a, T: ?Sized> Copy for &'a T {}
+unsafe impl<T: ?Sized> Copy for *const T {}
+unsafe impl<T: ?Sized> Copy for *mut T {}
+
+#[lang = "sync"]
+pub unsafe trait Sync {}
+
+unsafe impl Sync for bool {}
+unsafe impl Sync for u8 {}
+unsafe impl Sync for u16 {}
+unsafe impl Sync for u32 {}
+unsafe impl Sync for u64 {}
+unsafe impl Sync for usize {}
+unsafe impl Sync for i8 {}
+unsafe impl Sync for i16 {}
+unsafe impl Sync for i32 {}
+unsafe impl Sync for isize {}
+unsafe impl Sync for char {}
+unsafe impl<'a, T: ?Sized> Sync for &'a T {}
+unsafe impl Sync for [u8; 16] {}
+
+#[lang = "freeze"]
+unsafe auto trait Freeze {}
+
+unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
+unsafe impl<T: ?Sized> Freeze for *const T {}
+unsafe impl<T: ?Sized> Freeze for *mut T {}
+unsafe impl<T: ?Sized> Freeze for &T {}
+unsafe impl<T: ?Sized> Freeze for &mut T {}
+
+#[lang = "structural_peq"]
+pub trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+pub trait StructuralEq {}
+
+#[lang = "not"]
+pub trait Not {
+ type Output;
+
+ fn not(self) -> Self::Output;
+}
+
+impl Not for bool {
+ type Output = bool;
+
+ fn not(self) -> bool {
+ !self
+ }
+}
+
+#[lang = "mul"]
+pub trait Mul<RHS = Self> {
+ type Output;
+
+ #[must_use]
+ fn mul(self, rhs: RHS) -> Self::Output;
+}
+
+impl Mul for u8 {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
+impl Mul for usize {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
+#[lang = "add"]
+pub trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+ type Output;
+
+ fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for u8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i16 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+#[lang = "rem"]
+pub trait Rem<RHS = Self> {
+ type Output;
+
+ fn rem(self, rhs: RHS) -> Self::Output;
+}
+
+impl Rem for usize {
+ type Output = Self;
+
+ fn rem(self, rhs: Self) -> Self {
+ self % rhs
+ }
+}
+
+#[lang = "bitor"]
+pub trait BitOr<RHS = Self> {
+ type Output;
+
+ #[must_use]
+ fn bitor(self, rhs: RHS) -> Self::Output;
+}
+
+impl BitOr for bool {
+ type Output = bool;
+
+ fn bitor(self, rhs: bool) -> bool {
+ self | rhs
+ }
+}
+
+impl<'a> BitOr<bool> for &'a bool {
+ type Output = bool;
+
+ fn bitor(self, rhs: bool) -> bool {
+ *self | rhs
+ }
+}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+ fn eq(&self, other: &Rhs) -> bool;
+ fn ne(&self, other: &Rhs) -> bool;
+}
+
+impl PartialEq for u8 {
+ fn eq(&self, other: &u8) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u8) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for u16 {
+ fn eq(&self, other: &u16) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u16) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for u32 {
+ fn eq(&self, other: &u32) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u32) -> bool {
+ (*self) != (*other)
+ }
+}
+
+
+impl PartialEq for u64 {
+ fn eq(&self, other: &u64) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u64) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for usize {
+ fn eq(&self, other: &usize) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &usize) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for i8 {
+ fn eq(&self, other: &i8) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &i8) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for i32 {
+ fn eq(&self, other: &i32) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &i32) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for isize {
+ fn eq(&self, other: &isize) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &isize) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for char {
+ fn eq(&self, other: &char) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &char) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl<T: ?Sized> PartialEq for *const T {
+ fn eq(&self, other: &*const T) -> bool {
+ *self == *other
+ }
+ fn ne(&self, other: &*const T) -> bool {
+ *self != *other
+ }
+}
+
+#[lang = "neg"]
+pub trait Neg {
+ type Output;
+
+ fn neg(self) -> Self::Output;
+}
+
+impl Neg for i8 {
+ type Output = i8;
+
+ fn neg(self) -> i8 {
+ -self
+ }
+}
+
+impl Neg for i16 {
+ type Output = i16;
+
+ fn neg(self) -> i16 {
+ self
+ }
+}
+
+impl Neg for isize {
+ type Output = isize;
+
+ fn neg(self) -> isize {
+ -self
+ }
+}
+
+impl Neg for f32 {
+ type Output = f32;
+
+ fn neg(self) -> f32 {
+ -self
+ }
+}
+
+pub enum Option<T> {
+ Some(T),
+ None,
+}
+
+pub use Option::*;
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+pub trait FnOnce<Args> {
+ #[lang = "fn_once_output"]
+ type Output;
+
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+pub trait FnMut<Args>: FnOnce<Args> {
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "panic"]
+#[track_caller]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\n\0" as *const str as *const u8);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "eh_personality"]
+fn eh_personality() -> ! {
+ loop {}
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+ type Target: ?Sized;
+
+ fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized>(*mut T);
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
+
+impl<T: ?Sized> Drop for Box<T> {
+ fn drop(&mut self) {
+ // drop is currently performed by compiler.
+ }
+}
+
+impl<T> Deref for Box<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &**self
+ }
+}
+
+#[lang = "exchange_malloc"]
+unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
+ libc::malloc(size)
+}
+
+#[lang = "box_free"]
+unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+ libc::free(ptr as *mut u8);
+}
+
+#[lang = "drop"]
+pub trait Drop {
+ fn drop(&mut self);
+}
+
+#[lang = "manually_drop"]
+#[repr(transparent)]
+pub struct ManuallyDrop<T: ?Sized> {
+ pub value: T,
+}
+
+#[lang = "maybe_uninit"]
+#[repr(transparent)]
+pub union MaybeUninit<T> {
+ pub uninit: (),
+ pub value: ManuallyDrop<T>,
+}
+
+pub mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ pub fn size_of<T>() -> usize;
+ pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
+ pub fn min_align_of<T>() -> usize;
+ pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
+ pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
+ pub fn transmute<T, U>(e: T) -> U;
+ pub fn ctlz_nonzero<T>(x: T) -> T;
+ pub fn needs_drop<T>() -> bool;
+ pub fn bitreverse<T>(x: T) -> T;
+ pub fn bswap<T>(x: T) -> T;
+ pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+ pub fn unreachable() -> !;
+ }
+}
+
+pub mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn puts(s: *const u8) -> i32;
+ pub fn printf(format: *const i8, ...) -> i32;
+ pub fn malloc(size: usize) -> *mut u8;
+ pub fn free(ptr: *mut u8);
+ pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);
+ pub fn memmove(dst: *mut u8, src: *const u8, size: usize);
+ pub fn strncpy(dst: *mut u8, src: *const u8, size: usize);
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+extern {
+ type VaListImpl;
+}
+
+#[lang = "va_list"]
+#[repr(transparent)]
+pub struct VaList<'a>(&'a mut VaListImpl);
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro stringify($($t:tt)*) { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro file() { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro line() { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro cfg() { /* compiler built-in */ }
+
+pub static A_STATIC: u8 = 42;
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[no_mangle]
+pub fn get_tls() -> u8 {
+ #[thread_local]
+ static A: u8 = 42;
+
+ A
+}
--- /dev/null
+// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
+
+#![feature(
+ no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage,
+ extern_types, thread_local
+)]
+#![no_core]
+#![allow(dead_code, non_camel_case_types)]
+
+extern crate mini_core;
+
+use mini_core::*;
+use mini_core::libc::*;
+
+unsafe extern "C" fn my_puts(s: *const u8) {
+ puts(s);
+}
+
+#[lang = "termination"]
+trait Termination {
+ fn report(self) -> i32;
+}
+
+impl Termination for () {
+ fn report(self) -> i32 {
+ unsafe {
+ NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
+ *NUM_REF as i32
+ }
+ }
+}
+
+trait SomeTrait {
+ fn object_safe(&self);
+}
+
+impl SomeTrait for &'static str {
+ fn object_safe(&self) {
+ unsafe {
+ puts(*self as *const str as *const u8);
+ }
+ }
+}
+
+struct NoisyDrop {
+ text: &'static str,
+ inner: NoisyDropInner,
+}
+
+struct NoisyDropInner;
+
+impl Drop for NoisyDrop {
+ fn drop(&mut self) {
+ unsafe {
+ puts(self.text as *const str as *const u8);
+ }
+ }
+}
+
+impl Drop for NoisyDropInner {
+ fn drop(&mut self) {
+ unsafe {
+ puts("Inner got dropped!\0" as *const str as *const u8);
+ }
+ }
+}
+
+impl SomeTrait for NoisyDrop {
+ fn object_safe(&self) {}
+}
+
+enum Ordering {
+ Less = -1,
+ Equal = 0,
+ Greater = 1,
+}
+
+#[lang = "start"]
+fn start<T: Termination + 'static>(
+ main: fn() -> T,
+ argc: isize,
+ argv: *const *const u8,
+) -> isize {
+ if argc == 3 {
+ unsafe { puts(*argv); }
+ unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); }
+ unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); }
+ }
+
+ main().report();
+ 0
+}
+
+static mut NUM: u8 = 6 * 7;
+static NUM_REF: &'static u8 = unsafe { &NUM };
+
+macro_rules! assert {
+ ($e:expr) => {
+ if !$e {
+ panic(stringify!(! $e));
+ }
+ };
+}
+
+macro_rules! assert_eq {
+ ($l:expr, $r: expr) => {
+ if $l != $r {
+ panic(stringify!($l != $r));
+ }
+ }
+}
+
+struct Unique<T: ?Sized> {
+ pointer: *const T,
+ _marker: PhantomData<T>,
+}
+
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
+
+unsafe fn zeroed<T>() -> T {
+ let mut uninit = MaybeUninit { uninit: () };
+ intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1);
+ uninit.value.value
+}
+
+fn take_f32(_f: f32) {}
+fn take_unique(_u: Unique<()>) {}
+
+fn return_u128_pair() -> (u128, u128) {
+ (0, 0)
+}
+
+fn call_return_u128_pair() {
+ return_u128_pair();
+}
+
+fn main() {
+ take_unique(Unique {
+ pointer: 0 as *const (),
+ _marker: PhantomData,
+ });
+ take_f32(0.1);
+
+ //call_return_u128_pair();
+
+ let slice = &[0, 1] as &[i32];
+ let slice_ptr = slice as *const [i32] as *const i32;
+
+ assert_eq!(slice_ptr as usize % 4, 0);
+
+ //return;
+
+ unsafe {
+ printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
+
+ let hello: &[u8] = b"Hello\0" as &[u8; 6];
+ let ptr: *const u8 = hello as *const [u8] as *const u8;
+ puts(ptr);
+
+ let world: Box<&str> = box "World!\0";
+ puts(*world as *const str as *const u8);
+ world as Box<dyn SomeTrait>;
+
+ assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8);
+
+ assert_eq!(intrinsics::bswap(0xabu8), 0xabu8);
+ assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16);
+ assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32);
+ assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64);
+
+ assert_eq!(intrinsics::size_of_val(hello) as u8, 6);
+
+ let chars = &['C', 'h', 'a', 'r', 's'];
+ let chars = chars as &[char];
+ assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5);
+
+ let a: &dyn SomeTrait = &"abc\0";
+ a.object_safe();
+
+ assert_eq!(intrinsics::size_of_val(a) as u8, 16);
+ assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
+
+ assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
+ assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
+
+ assert!(!intrinsics::needs_drop::<u8>());
+ assert!(intrinsics::needs_drop::<NoisyDrop>());
+
+ Unique {
+ pointer: 0 as *const &str,
+ _marker: PhantomData,
+ } as Unique<dyn SomeTrait>;
+
+ struct MyDst<T: ?Sized>(T);
+
+ intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>);
+
+ struct Foo {
+ x: u8,
+ y: !,
+ }
+
+ unsafe fn uninitialized<T>() -> T {
+ MaybeUninit { uninit: () }.value.value
+ }
+
+ zeroed::<(u8, u8)>();
+ #[allow(unreachable_code)]
+ {
+ if false {
+ zeroed::<!>();
+ zeroed::<Foo>();
+ uninitialized::<Foo>();
+ }
+ }
+ }
+
+ let _ = box NoisyDrop {
+ text: "Boxed outer got dropped!\0",
+ inner: NoisyDropInner,
+ } as Box<dyn SomeTrait>;
+
+ const FUNC_REF: Option<fn()> = Some(main);
+ match FUNC_REF {
+ Some(_) => {},
+ None => assert!(false),
+ }
+
+ match Ordering::Less {
+ Ordering::Less => {},
+ _ => assert!(false),
+ }
+
+ [NoisyDropInner, NoisyDropInner];
+
+ let x = &[0u32, 42u32] as &[u32];
+ match x {
+ [] => assert_eq!(0u32, 1),
+ [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize),
+ }
+
+ assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
+
+ extern {
+ #[linkage = "weak"]
+ static ABC: *const u8;
+ }
+
+ {
+ extern {
+ #[linkage = "weak"]
+ static ABC: *const u8;
+ }
+ }
+
+ // TODO(antoyo): to make this work, support weak linkage.
+ //unsafe { assert_eq!(ABC as usize, 0); }
+
+ &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>;
+
+ let f = 1000.0;
+ assert_eq!(f as u8, 255);
+ let f2 = -1000.0;
+ assert_eq!(f2 as i8, -128);
+ assert_eq!(f2 as u8, 0);
+
+ static ANOTHER_STATIC: &u8 = &A_STATIC;
+ assert_eq!(*ANOTHER_STATIC, 42);
+
+ check_niche_behavior();
+
+ extern "C" {
+ type ExternType;
+ }
+
+ struct ExternTypeWrapper {
+ _a: ExternType,
+ }
+
+ let nullptr = 0 as *const ();
+ let extern_nullptr = nullptr as *const ExternTypeWrapper;
+ extern_nullptr as *const ();
+ let slice_ptr = &[] as *const [u8];
+ slice_ptr as *const u8;
+
+ #[cfg(not(jit))]
+ test_tls();
+}
+
+#[repr(C)]
+enum c_void {
+ _1,
+ _2,
+}
+
+type c_int = i32;
+type c_ulong = u64;
+
+type pthread_t = c_ulong;
+
+#[repr(C)]
+struct pthread_attr_t {
+ __size: [u64; 7],
+}
+
+#[link(name = "pthread")]
+extern "C" {
+ fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
+
+ fn pthread_create(
+ native: *mut pthread_t,
+ attr: *const pthread_attr_t,
+ f: extern "C" fn(_: *mut c_void) -> *mut c_void,
+ value: *mut c_void
+ ) -> c_int;
+
+ fn pthread_join(
+ native: pthread_t,
+ value: *mut *mut c_void
+ ) -> c_int;
+}
+
+#[thread_local]
+#[cfg(not(jit))]
+static mut TLS: u8 = 42;
+
+#[cfg(not(jit))]
+extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
+ unsafe { TLS = 0; }
+ 0 as *mut c_void
+}
+
+#[cfg(not(jit))]
+fn test_tls() {
+ unsafe {
+ let mut attr: pthread_attr_t = zeroed();
+ let mut thread: pthread_t = 0;
+
+ assert_eq!(TLS, 42);
+
+ if pthread_attr_init(&mut attr) != 0 {
+ assert!(false);
+ }
+
+ if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 {
+ assert!(false);
+ }
+
+ let mut res = 0 as *mut c_void;
+ pthread_join(thread, &mut res);
+
+ // TLS of main thread must not have been changed by the other thread.
+ assert_eq!(TLS, 42);
+
+ puts("TLS works!\n\0" as *const str as *const u8);
+ }
+}
+
+// Copied ui/issues/issue-61696.rs
+
+pub enum Infallible {}
+
+// The check that the `bool` field of `V1` is encoding a "niche variant"
+// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect,
+// causing valid `V1` values to be interpreted as other variants.
+pub enum E1 {
+ V1 { f: bool },
+ V2 { f: Infallible },
+ V3,
+ V4,
+}
+
+// Computing the discriminant used to be done using the niche type (here `u8`,
+// from the `bool` field of `V1`), overflowing for variants with large enough
+// indices (`V3` and `V4`), causing them to be interpreted as other variants.
+pub enum E2<X> {
+ V1 { f: bool },
+
+ /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
+ _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
+ _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
+ _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
+ _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
+ _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
+ _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
+ _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
+ _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
+ _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
+ _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
+ _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
+ _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
+ _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
+ _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
+ _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
+ _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
+ _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
+ _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
+ _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
+ _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
+ _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
+ _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
+ _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
+ _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
+ _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
+ _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
+ _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
+ _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
+ _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
+ _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
+ _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
+
+ V3,
+ V4,
+}
+
+fn check_niche_behavior () {
+ if let E1::V2 { .. } = (E1::V1 { f: true }) {
+ intrinsics::abort();
+ }
+
+ if let E2::V1 { .. } = E2::V3::<Infallible> {
+ intrinsics::abort();
+ }
+}
--- /dev/null
+#![feature(start, box_syntax, core_intrinsics, lang_items)]
+#![no_std]
+
+#[link(name = "c")]
+extern {}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+ unsafe {
+ core::intrinsics::abort();
+ }
+}
+
+#[lang="eh_personality"]
+fn eh_personality(){}
+
+// Required for rustc_codegen_llvm
+#[no_mangle]
+unsafe extern "C" fn _Unwind_Resume() {
+ core::intrinsics::unreachable();
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+ for i in 2..100_000_000 {
+ black_box((i + 1) % i);
+ }
+
+ 0
+}
+
+#[inline(never)]
+fn black_box(i: u32) {
+ if i != 1 {
+ unsafe { core::intrinsics::abort(); }
+ }
+}
--- /dev/null
+#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+
+use std::arch::x86_64::*;
+use std::io::Write;
+use std::ops::Generator;
+
+extern {
+ pub fn printf(format: *const i8, ...) -> i32;
+}
+
+fn main() {
+ let mutex = std::sync::Mutex::new(());
+ let _guard = mutex.lock().unwrap();
+
+ let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
+ let stderr = ::std::io::stderr();
+ let mut stderr = stderr.lock();
+
+ std::thread::spawn(move || {
+ println!("Hello from another thread!");
+ });
+
+ writeln!(stderr, "some {} text", "<unknown>").unwrap();
+
+ let _ = std::process::Command::new("true").env("c", "d").spawn();
+
+ println!("cargo:rustc-link-lib=z");
+
+ static ONCE: std::sync::Once = std::sync::Once::new();
+ ONCE.call_once(|| {});
+
+ let _eq = LoopState::Continue(()) == LoopState::Break(());
+
+ // Make sure ByValPair values with differently sized components are correctly passed
+ map(None::<(u8, Box<Instruction>)>);
+
+ println!("{}", 2.3f32.exp());
+ println!("{}", 2.3f32.exp2());
+ println!("{}", 2.3f32.abs());
+ println!("{}", 2.3f32.sqrt());
+ println!("{}", 2.3f32.floor());
+ println!("{}", 2.3f32.ceil());
+ println!("{}", 2.3f32.min(1.0));
+ println!("{}", 2.3f32.max(1.0));
+ println!("{}", 2.3f32.powi(2));
+ println!("{}", 2.3f32.log2());
+ assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
+ println!("{}", 2.3f32.powf(2.0));
+
+ assert_eq!(-128i8, (-128i8).saturating_sub(1));
+ assert_eq!(127i8, 127i8.saturating_sub(-128));
+ assert_eq!(-128i8, (-128i8).saturating_add(-128));
+ assert_eq!(127i8, 127i8.saturating_add(1));
+
+ assert_eq!(-32768i16, (-32768i16).saturating_add(-32768));
+ assert_eq!(32767i16, 32767i16.saturating_add(1));
+
+ assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
+ assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
+
+ let _d = 0i128.checked_div(2i128);
+ let _d = 0u128.checked_div(2u128);
+ assert_eq!(1u128 + 2, 3);
+
+ assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
+ assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
+ assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
+
+ let tmp = 353985398u128;
+ assert_eq!(tmp * 932490u128, 330087843781020u128);
+
+ let tmp = -0x1234_5678_9ABC_DEF0i64;
+ assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
+
+ // Check that all u/i128 <-> float casts work correctly.
+ let houndred_u128 = 100u128;
+ let houndred_i128 = 100i128;
+ let houndred_f32 = 100.0f32;
+ let houndred_f64 = 100.0f64;
+ assert_eq!(houndred_u128 as f32, 100.0);
+ assert_eq!(houndred_u128 as f64, 100.0);
+ assert_eq!(houndred_f32 as u128, 100);
+ assert_eq!(houndred_f64 as u128, 100);
+ assert_eq!(houndred_i128 as f32, 100.0);
+ assert_eq!(houndred_i128 as f64, 100.0);
+ assert_eq!(houndred_f32 as i128, 100);
+ assert_eq!(houndred_f64 as i128, 100);
+
+ let _a = 1u32 << 2u8;
+
+ let empty: [i32; 0] = [];
+ assert!(empty.is_sorted());
+
+ println!("{:?}", std::intrinsics::caller_location());
+
+ /*unsafe {
+ test_simd();
+ }*/
+
+ Box::pin(move |mut _task_context| {
+ yield ();
+ }).as_mut().resume(0);
+
+ println!("End");
+}
+
+/*#[target_feature(enable = "sse2")]
+unsafe fn test_simd() {
+ let x = _mm_setzero_si128();
+ let y = _mm_set1_epi16(7);
+ let or = _mm_or_si128(x, y);
+ let cmp_eq = _mm_cmpeq_epi8(y, y);
+ let cmp_lt = _mm_cmplt_epi8(y, y);
+
+ /*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
+ assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
+ assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
+
+ test_mm_slli_si128();
+ test_mm_movemask_epi8();
+ test_mm256_movemask_epi8();
+ test_mm_add_epi8();
+ test_mm_add_pd();
+ test_mm_cvtepi8_epi16();
+ test_mm_cvtsi128_si64();
+
+ // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
+ //test_mm_extract_epi8();
+
+ let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
+ assert_eq!(mask1, 1);*/
+}*/
+
+/*#[target_feature(enable = "sse2")]
+unsafe fn test_mm_slli_si128() {
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ );
+ let r = _mm_slli_si128(a, 1);
+ let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+ assert_eq_m128i(r, e);
+
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ );
+ let r = _mm_slli_si128(a, 15);
+ let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+ assert_eq_m128i(r, e);
+
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ );
+ let r = _mm_slli_si128(a, 16);
+ assert_eq_m128i(r, _mm_set1_epi8(0));
+
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ );
+ let r = _mm_slli_si128(a, -1);
+ assert_eq_m128i(_mm_set1_epi8(0), r);
+
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ );
+ let r = _mm_slli_si128(a, -0x80000000);
+ assert_eq_m128i(r, _mm_set1_epi8(0));
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_movemask_epi8() {
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
+ 0b0101, 0b1111_0000u8 as i8, 0, 0,
+ 0, 0, 0b1111_0000u8 as i8, 0b0101,
+ 0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
+ );
+ let r = _mm_movemask_epi8(a);
+ assert_eq!(r, 0b10100100_00100101);
+}
+
+#[target_feature(enable = "avx2")]
+unsafe fn test_mm256_movemask_epi8() {
+ let a = _mm256_set1_epi8(-1);
+ let r = _mm256_movemask_epi8(a);
+ let e = -1;
+ assert_eq!(r, e);
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_add_epi8() {
+ let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+ #[rustfmt::skip]
+ let b = _mm_setr_epi8(
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ );
+ let r = _mm_add_epi8(a, b);
+ #[rustfmt::skip]
+ let e = _mm_setr_epi8(
+ 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
+ );
+ assert_eq_m128i(r, e);
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_add_pd() {
+ let a = _mm_setr_pd(1.0, 2.0);
+ let b = _mm_setr_pd(5.0, 10.0);
+ let r = _mm_add_pd(a, b);
+ assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
+}
+
+fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
+ unsafe {
+ assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
+ }
+}
+
+#[target_feature(enable = "sse2")]
+pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
+ if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
+ panic!("{:?} != {:?}", a, b);
+ }
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_cvtsi128_si64() {
+ let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
+ assert_eq!(r, 5);
+}
+
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_cvtepi8_epi16() {
+ let a = _mm_set1_epi8(10);
+ let r = _mm_cvtepi8_epi16(a);
+ let e = _mm_set1_epi16(10);
+ assert_eq_m128i(r, e);
+ let a = _mm_set1_epi8(-10);
+ let r = _mm_cvtepi8_epi16(a);
+ let e = _mm_set1_epi16(-10);
+ assert_eq_m128i(r, e);
+}
+
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_extract_epi8() {
+ #[rustfmt::skip]
+ let a = _mm_setr_epi8(
+ -1, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15
+ );
+ let r1 = _mm_extract_epi8(a, 0);
+ let r2 = _mm_extract_epi8(a, 19);
+ assert_eq!(r1, 0xFF);
+ assert_eq!(r2, 3);
+}*/
+
+#[derive(PartialEq)]
+enum LoopState {
+ Continue(()),
+ Break(())
+}
+
+pub enum Instruction {
+ Increment,
+ Loop,
+}
+
+fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
+ match a {
+ None => None,
+ Some((_, instr)) => Some(instr),
+ }
+}
--- /dev/null
+// Based on https://github.com/rust-lang/rust/blob/c5840f9d252c2f5cc16698dbf385a29c5de3ca07/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
+
+// Test that array subslice patterns are correctly handled in const evaluation.
+
+// run-pass
+
+#[derive(PartialEq, Debug, Clone)]
+struct N(u8);
+
+#[derive(PartialEq, Debug, Clone)]
+struct Z;
+
+macro_rules! n {
+ ($($e:expr),* $(,)?) => {
+ [$(N($e)),*]
+ }
+}
+
+// This macro has an unused variable so that it can be repeated base on the
+// number of times a repeated variable (`$e` in `z`) occurs.
+macro_rules! zed {
+ ($e:expr) => { Z }
+}
+
+macro_rules! z {
+ ($($e:expr),* $(,)?) => {
+ [$(zed!($e)),*]
+ }
+}
+
+// Compare constant evaluation and runtime evaluation of a given expression.
+macro_rules! compare_evaluation {
+ ($e:expr, $t:ty $(,)?) => {{
+ const CONST_EVAL: $t = $e;
+ const fn const_eval() -> $t { $e }
+ static CONST_EVAL2: $t = const_eval();
+ let runtime_eval = $e;
+ assert_eq!(CONST_EVAL, runtime_eval);
+ assert_eq!(CONST_EVAL2, runtime_eval);
+ }}
+}
+
+// Repeat `$test`, substituting the given macro variables with the given
+// identifiers.
+//
+// For example:
+//
+// repeat! {
+// ($name); X; Y:
+// struct $name;
+// }
+//
+// Expands to:
+//
+// struct X; struct Y;
+//
+// This is used to repeat the tests using both the `N` and `Z`
+// types.
+macro_rules! repeat {
+ (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => {
+ macro_rules! single {
+ ($($dollar $placeholder:ident),*) => { $($test)* }
+ }
+ $(single!($($values),+);)*
+ }
+}
+
+fn main() {
+ repeat! {
+ ($arr $Ty); n, N; z, Z:
+ compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]);
+ compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
+ compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
+
+ compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]);
+ compare_evaluation!(
+ { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x },
+ &'static [$Ty; 0],
+ );
+ compare_evaluation!(
+ { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x },
+ &'static [$Ty; 0],
+ );
+
+ compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty);
+ compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty);
+ compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty);
+ }
+
+ compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8);
+ compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8);
+ compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8);
+
+ compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8);
+ compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8);
+ compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8);
+}
--- /dev/null
+// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
+
+// run-pass
+
+use std::panic::Location;
+
+#[track_caller]
+fn tracked() -> &'static Location<'static> {
+ Location::caller()
+}
+
+fn nested_intrinsic() -> &'static Location<'static> {
+ Location::caller()
+}
+
+fn nested_tracked() -> &'static Location<'static> {
+ tracked()
+}
+
+fn main() {
+ let location = Location::caller();
+ assert_eq!(location.file(), file!());
+ assert_eq!(location.line(), 21);
+ assert_eq!(location.column(), 20);
+
+ let tracked = tracked();
+ assert_eq!(tracked.file(), file!());
+ assert_eq!(tracked.line(), 26);
+ assert_eq!(tracked.column(), 19);
+
+ let nested = nested_intrinsic();
+ assert_eq!(nested.file(), file!());
+ assert_eq!(nested.line(), 13);
+ assert_eq!(nested.column(), 5);
+
+ let contained = nested_tracked();
+ assert_eq!(contained.file(), file!());
+ assert_eq!(contained.line(), 17);
+ assert_eq!(contained.column(), 5);
+}
--- /dev/null
+From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Sun, 24 Nov 2019 15:10:23 +0100
+Subject: [PATCH] [core] Disable not compiling tests
+
+---
+ library/core/tests/Cargo.toml | 8 ++++++++
+ library/core/tests/num/flt2dec/mod.rs | 1 -
+ library/core/tests/num/int_macros.rs | 2 ++
+ library/core/tests/num/uint_macros.rs | 2 ++
+ library/core/tests/ptr.rs | 2 ++
+ library/core/tests/slice.rs | 2 ++
+ 6 files changed, 16 insertions(+), 1 deletion(-)
+ create mode 100644 library/core/tests/Cargo.toml
+
+diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
+new file mode 100644
+index 0000000..46fd999
+--- /dev/null
++++ b/library/core/tests/Cargo.toml
+@@ -0,0 +1,8 @@
++[package]
++name = "core"
++version = "0.0.0"
++edition = "2018"
++
++[lib]
++name = "coretests"
++path = "lib.rs"
+diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
+index a35897e..f0bf645 100644
+--- a/library/core/tests/num/flt2dec/mod.rs
++++ b/library/core/tests/num/flt2dec/mod.rs
+@@ -13,7 +13,6 @@ mod strategy {
+ mod dragon;
+ mod grisu;
+ }
+-mod random;
+
+ pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+ match decode(v).1 {
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 6609bc3..241b497 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() {
+ }
+ }
+
++/*
+ #[test]
+ #[cfg(not(target_arch = "wasm32"))]
+ fn sort_unstable() {
+@@ -1394,6 +1395,7 @@ fn partition_at_index() {
+ v.select_nth_unstable(0);
+ assert!(v == [0xDEADBEEF]);
+ }
++*/
+
+ #[test]
+ #[should_panic(expected = "index 0 greater than length of slice")]
+--
+2.21.0 (Apple Git-122)
--- /dev/null
+From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Sun, 24 Nov 2019 15:34:06 +0100
+Subject: [PATCH] [core] Ignore failing tests
+
+---
+ library/core/tests/iter.rs | 4 ++++
+ library/core/tests/num/bignum.rs | 10 ++++++++++
+ library/core/tests/num/mod.rs | 5 +++--
+ library/core/tests/time.rs | 1 +
+ 4 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
+index 4bc44e9..8e3c7a4 100644
+--- a/library/core/tests/array.rs
++++ b/library/core/tests/array.rs
+@@ -242,6 +242,7 @@ fn iterator_drops() {
+ assert_eq!(i.get(), 5);
+ }
+
++/*
+ // This test does not work on targets without panic=unwind support.
+ // To work around this problem, test is marked is should_panic, so it will
+ // be automagically skipped on unsuitable targets, such as
+@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
+ assert_eq!(COUNTER.load(Relaxed), 0);
+ panic!("test succeeded")
+ }
++*/
+
+ #[test]
+ fn empty_array_is_always_default() {
+@@ -304,6 +304,7 @@ fn array_map() {
+ assert_eq!(b, [1, 2, 3]);
+ }
+
++/*
+ // See note on above test for why `should_panic` is used.
+ #[test]
+ #[should_panic(expected = "test succeeded")]
+@@ -332,6 +333,7 @@ fn array_map_drop_safety() {
+ assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
+ panic!("test succeeded")
+ }
++*/
+
+ #[test]
+ fn cell_allows_array_cycle() {
+-- 2.21.0 (Apple Git-122)
--- /dev/null
+#!/bin/bash --verbose
+set -e
+
+source prepare_build.sh
+
+cargo install hyperfine || echo "Skipping hyperfine install"
+
+git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
+pushd regex
+git checkout -- .
+git checkout 341f207c1071f7290e3f228c710817c280c8dca1
+popd
+
+git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned"
+pushd simple-raytracer
+git checkout -- .
+git checkout 804a7a21b9e673a482797aa289a18ed480e4d813
+
+# build with cg_llvm for perf comparison
+cargo build
+mv target/debug/main raytracer_cg_llvm
+popd
--- /dev/null
+#!/bin/bash --verbose
+set -e
+
+rustup component add rust-src rustc-dev llvm-tools-preview
+./build_sysroot/prepare_sysroot_src.sh
--- /dev/null
+nightly-2021-09-28
--- /dev/null
+#!/bin/bash
+
+set -e
+
+case $1 in
+ "prepare")
+ TOOLCHAIN=$(date +%Y-%m-%d)
+
+ echo "=> Installing new nightly"
+ rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists
+ echo nightly-${TOOLCHAIN} > rust-toolchain
+
+ echo "=> Uninstalling all old nighlies"
+ for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do
+ rustup toolchain uninstall $nightly
+ done
+
+ ./clean_all.sh
+ ./prepare.sh
+ ;;
+ "commit")
+ git add rust-toolchain
+ git commit -m "Rustup to $(rustc -V)"
+ ;;
+ *)
+ echo "Unknown command '$1'"
+ echo "Usage: ./rustup.sh prepare|commit"
+ ;;
+esac
--- /dev/null
+use gccjit::{ToRValue, Type};
+use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::Ty;
+use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::intrinsic::ArgAbiExt;
+use crate::type_of::LayoutGccExt;
+
+impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+ fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
+ // TODO(antoyo)
+ }
+
+ fn get_param(&self, index: usize) -> Self::Value {
+ self.cx.current_func.borrow().expect("current func")
+ .get_param(index as i32)
+ .to_rvalue()
+ }
+}
+
+impl GccType for CastTarget {
+ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
+ let rest_gcc_unit = self.rest.unit.gcc_type(cx);
+ let (rest_count, rem_bytes) =
+ if self.rest.unit.size.bytes() == 0 {
+ (0, 0)
+ }
+ else {
+ (self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes())
+ };
+
+ if self.prefix.iter().all(|x| x.is_none()) {
+ // Simplify to a single unit when there is no prefix and size <= unit size
+ if self.rest.total <= self.rest.unit.size {
+ return rest_gcc_unit;
+ }
+
+ // Simplify to array when all chunks are the same size and type
+ if rem_bytes == 0 {
+ return cx.type_array(rest_gcc_unit, rest_count);
+ }
+ }
+
+ // Create list of fields in the main structure
+ let mut args: Vec<_> = self
+ .prefix
+ .iter()
+ .flat_map(|option_kind| {
+ option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx))
+ })
+ .chain((0..rest_count).map(|_| rest_gcc_unit))
+ .collect();
+
+ // Append final integer
+ if rem_bytes != 0 {
+ // Only integers can be really split further.
+ assert_eq!(self.rest.unit.kind, RegKind::Integer);
+ args.push(cx.type_ix(rem_bytes * 8));
+ }
+
+ cx.type_struct(&args, false)
+ }
+}
+
+pub trait GccType {
+ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>;
+}
+
+impl GccType for Reg {
+ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
+ match self.kind {
+ RegKind::Integer => cx.type_ix(self.size.bits()),
+ RegKind::Float => {
+ match self.size.bits() {
+ 32 => cx.type_f32(),
+ 64 => cx.type_f64(),
+ _ => bug!("unsupported float: {:?}", self),
+ }
+ },
+ RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()),
+ }
+ }
+}
+
+pub trait FnAbiGccExt<'gcc, 'tcx> {
+ // TODO(antoyo): return a function pointer type instead?
+ fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool);
+ fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+}
+
+impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
+ fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool) {
+ let args_capacity: usize = self.args.iter().map(|arg|
+ if arg.pad.is_some() {
+ 1
+ }
+ else {
+ 0
+ } +
+ if let PassMode::Pair(_, _) = arg.mode {
+ 2
+ } else {
+ 1
+ }
+ ).sum();
+ let mut argument_tys = Vec::with_capacity(
+ if let PassMode::Indirect { .. } = self.ret.mode {
+ 1
+ }
+ else {
+ 0
+ } + args_capacity,
+ );
+
+ let return_ty =
+ match self.ret.mode {
+ PassMode::Ignore => cx.type_void(),
+ PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
+ PassMode::Cast(cast) => cast.gcc_type(cx),
+ PassMode::Indirect { .. } => {
+ argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
+ cx.type_void()
+ }
+ };
+
+ for arg in &self.args {
+ // add padding
+ if let Some(ty) = arg.pad {
+ argument_tys.push(ty.gcc_type(cx));
+ }
+
+ let arg_ty = match arg.mode {
+ PassMode::Ignore => continue,
+ PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
+ PassMode::Pair(..) => {
+ argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true));
+ argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true));
+ continue;
+ }
+ PassMode::Indirect { extra_attrs: Some(_), .. } => {
+ unimplemented!();
+ }
+ PassMode::Cast(cast) => cast.gcc_type(cx),
+ PassMode::Indirect { extra_attrs: None, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
+ };
+ argument_tys.push(arg_ty);
+ }
+
+ (return_ty, argument_tys, self.c_variadic)
+ }
+
+ fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+ let (return_type, params, variadic) = self.gcc_type(cx);
+ let pointer_type = cx.context.new_function_pointer_type(None, return_type, ¶ms, variadic);
+ pointer_type
+ }
+}
--- /dev/null
+use gccjit::{FunctionType, ToRValue};
+use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_middle::bug;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::sym;
+
+use crate::GccContext;
+
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+ let context = &mods.context;
+ let usize =
+ match tcx.sess.target.pointer_width {
+ 16 => context.new_type::<u16>(),
+ 32 => context.new_type::<u32>(),
+ 64 => context.new_type::<u64>(),
+ tws => bug!("Unsupported target word size for int: {}", tws),
+ };
+ let i8 = context.new_type::<i8>();
+ let i8p = i8.make_pointer();
+ let void = context.new_type::<()>();
+
+ for method in ALLOCATOR_METHODS {
+ let mut types = Vec::with_capacity(method.inputs.len());
+ for ty in method.inputs.iter() {
+ match *ty {
+ AllocatorTy::Layout => {
+ types.push(usize);
+ types.push(usize);
+ }
+ AllocatorTy::Ptr => types.push(i8p),
+ AllocatorTy::Usize => types.push(usize),
+
+ AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
+ }
+ }
+ let output = match method.output {
+ AllocatorTy::ResultPtr => Some(i8p),
+ AllocatorTy::Unit => None,
+
+ AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+ panic!("invalid allocator output")
+ }
+ };
+ let name = format!("__rust_{}", method.name);
+
+ let args: Vec<_> = types.iter().enumerate()
+ .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+ .collect();
+ let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
+
+ if tcx.sess.target.options.default_hidden_visibility {
+ // TODO(antoyo): set visibility.
+ }
+ if tcx.sess.must_emit_unwind_tables() {
+ // TODO(antoyo): emit unwind tables.
+ }
+
+ let callee = kind.fn_name(method.name);
+ let args: Vec<_> = types.iter().enumerate()
+ .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+ .collect();
+ let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
+ // TODO(antoyo): set visibility.
+
+ let block = func.new_block("entry");
+
+ let args = args
+ .iter()
+ .enumerate()
+ .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+ .collect::<Vec<_>>();
+ let ret = context.new_call(None, callee, &args);
+ //llvm::LLVMSetTailCall(ret, True);
+ if output.is_some() {
+ block.end_with_return(None, ret);
+ }
+ else {
+ block.end_with_void_return(None);
+ }
+
+ // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
+ // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
+ }
+
+ let types = [usize, usize];
+ let name = "__rust_alloc_error_handler".to_string();
+ let args: Vec<_> = types.iter().enumerate()
+ .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+ .collect();
+ let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
+
+ let kind =
+ if has_alloc_error_handler {
+ AllocatorKind::Global
+ }
+ else {
+ AllocatorKind::Default
+ };
+ let callee = kind.fn_name(sym::oom);
+ let args: Vec<_> = types.iter().enumerate()
+ .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+ .collect();
+ let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false);
+ //llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+ let block = func.new_block("entry");
+
+ let args = args
+ .iter()
+ .enumerate()
+ .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+ .collect::<Vec<_>>();
+ let _ret = context.new_call(None, callee, &args);
+ //llvm::LLVMSetTailCall(ret, True);
+ block.end_with_void_return(None);
+}
--- /dev/null
+use std::fs::File;
+use std::path::{Path, PathBuf};
+
+use rustc_session::Session;
+use rustc_codegen_ssa::back::archive::ArchiveBuilder;
+
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
+
+
+struct ArchiveConfig<'a> {
+ sess: &'a Session,
+ dst: PathBuf,
+ use_native_ar: bool,
+ use_gnu_style_archive: bool,
+}
+
+#[derive(Debug)]
+enum ArchiveEntry {
+ FromArchive {
+ archive_index: usize,
+ entry_index: usize,
+ },
+ File(PathBuf),
+}
+
+pub struct ArArchiveBuilder<'a> {
+ config: ArchiveConfig<'a>,
+ src_archives: Vec<(PathBuf, ar::Archive<File>)>,
+ // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
+ // the end of an archive for linkers to not get confused.
+ entries: Vec<(String, ArchiveEntry)>,
+}
+
+impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
+ fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
+ let config = ArchiveConfig {
+ sess,
+ dst: output.to_path_buf(),
+ use_native_ar: false,
+ // FIXME test for linux and System V derivatives instead
+ use_gnu_style_archive: sess.target.options.archive_format == "gnu",
+ };
+
+ let (src_archives, entries) = if let Some(input) = input {
+ let mut archive = ar::Archive::new(File::open(input).unwrap());
+ let mut entries = Vec::new();
+
+ let mut i = 0;
+ while let Some(entry) = archive.next_entry() {
+ let entry = entry.unwrap();
+ entries.push((
+ String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
+ ArchiveEntry::FromArchive {
+ archive_index: 0,
+ entry_index: i,
+ },
+ ));
+ i += 1;
+ }
+
+ (vec![(input.to_owned(), archive)], entries)
+ } else {
+ (vec![], Vec::new())
+ };
+
+ ArArchiveBuilder {
+ config,
+ src_archives,
+ entries,
+ }
+ }
+
+ fn src_files(&mut self) -> Vec<String> {
+ self.entries.iter().map(|(name, _)| name.clone()).collect()
+ }
+
+ fn remove_file(&mut self, name: &str) {
+ let index = self
+ .entries
+ .iter()
+ .position(|(entry_name, _)| entry_name == name)
+ .expect("Tried to remove file not existing in src archive");
+ self.entries.remove(index);
+ }
+
+ fn add_file(&mut self, file: &Path) {
+ self.entries.push((
+ file.file_name().unwrap().to_str().unwrap().to_string(),
+ ArchiveEntry::File(file.to_owned()),
+ ));
+ }
+
+ fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()>
+ where
+ F: FnMut(&str) -> bool + 'static,
+ {
+ let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
+ let archive_index = self.src_archives.len();
+
+ let mut i = 0;
+ while let Some(entry) = archive.next_entry() {
+ let entry = entry?;
+ let file_name = String::from_utf8(entry.header().identifier().to_vec())
+ .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
+ if !skip(&file_name) {
+ self.entries
+ .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
+ }
+ i += 1;
+ }
+
+ self.src_archives.push((archive_path.to_owned(), archive));
+ Ok(())
+ }
+
+ fn update_symbols(&mut self) {
+ }
+
+ fn build(mut self) {
+ use std::process::Command;
+
+ fn add_file_using_ar(archive: &Path, file: &Path) {
+ Command::new("ar")
+ .arg("r") // add or replace file
+ .arg("-c") // silence created file message
+ .arg(archive)
+ .arg(&file)
+ .status()
+ .unwrap();
+ }
+
+ enum BuilderKind<'a> {
+ Bsd(ar::Builder<File>),
+ Gnu(ar::GnuBuilder<File>),
+ NativeAr(&'a Path),
+ }
+
+ let mut builder = if self.config.use_native_ar {
+ BuilderKind::NativeAr(&self.config.dst)
+ } else if self.config.use_gnu_style_archive {
+ BuilderKind::Gnu(ar::GnuBuilder::new(
+ File::create(&self.config.dst).unwrap(),
+ self.entries
+ .iter()
+ .map(|(name, _)| name.as_bytes().to_vec())
+ .collect(),
+ ))
+ } else {
+ BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
+ };
+
+ // Add all files
+ for (entry_name, entry) in self.entries.into_iter() {
+ match entry {
+ ArchiveEntry::FromArchive {
+ archive_index,
+ entry_index,
+ } => {
+ let (ref src_archive_path, ref mut src_archive) =
+ self.src_archives[archive_index];
+ let entry = src_archive.jump_to_entry(entry_index).unwrap();
+ let header = entry.header().clone();
+
+ match builder {
+ BuilderKind::Bsd(ref mut builder) => {
+ builder.append(&header, entry).unwrap()
+ }
+ BuilderKind::Gnu(ref mut builder) => {
+ builder.append(&header, entry).unwrap()
+ }
+ BuilderKind::NativeAr(archive_file) => {
+ Command::new("ar")
+ .arg("x")
+ .arg(src_archive_path)
+ .arg(&entry_name)
+ .status()
+ .unwrap();
+ add_file_using_ar(archive_file, Path::new(&entry_name));
+ std::fs::remove_file(entry_name).unwrap();
+ }
+ }
+ }
+ ArchiveEntry::File(file) =>
+ match builder {
+ BuilderKind::Bsd(ref mut builder) => {
+ builder
+ .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder"))
+ .unwrap()
+ },
+ BuilderKind::Gnu(ref mut builder) => {
+ builder
+ .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file)))
+ .unwrap()
+ },
+ BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
+ },
+ }
+ }
+
+ // Finalize archive
+ std::mem::drop(builder);
+
+ // Run ranlib to be able to link the archive
+ let status = std::process::Command::new("ranlib")
+ .arg(self.config.dst)
+ .status()
+ .expect("Couldn't run ranlib");
+
+ if !status.success() {
+ self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
+ }
+ }
+
+ fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
+ unimplemented!();
+ }
+}
--- /dev/null
+use gccjit::{LValue, RValue, ToRValue, Type};
+use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_codegen_ssa::mir::operand::OperandValue;
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
+
+use rustc_hir::LlvmInlineAsmInner;
+use rustc_middle::{bug, ty::Instance};
+use rustc_span::{Span, Symbol};
+use rustc_target::asm::*;
+
+use std::borrow::Cow;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+
+// Rust asm! and GCC Extended Asm semantics differ substantially.
+//
+// 1. Rust asm operands go along as one list of operands. Operands themselves indicate
+// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be
+// both "in" and "out" (`inout(reg)`).
+//
+// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit,
+// this means that all "out" operands must go before "in" operands. "In" and "out" operands
+// cannot interleave.
+//
+// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important
+// because the asm template refers to operands by index.
+//
+// Mapping from Rust to GCC index would be 1-1 if it wasn't for...
+//
+// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
+// Contrary, Rust expresses clobbers through "out" operands that aren't tied to
+// a variable (`_`), and such "clobbers" do have index.
+//
+// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
+// (like `out("eax")`) directly, offering so-called "local register variables"
+// as a workaround. These variables need to be declared and initialized *before*
+// the Extended Asm block but *after* normal local variables
+// (see comment in `codegen_inline_asm` for explanation).
+//
+// With that in mind, let's see how we translate Rust syntax to GCC
+// (from now on, `CC` stands for "constraint code"):
+//
+// * `out(reg_class) var` -> translated to output operand: `"=CC"(var)`
+// * `inout(reg_class) var` -> translated to output operand: `"+CC"(var)`
+// * `in(reg_class) var` -> translated to input operand: `"CC"(var)`
+//
+// * `out(reg_class) _` -> translated to one `=r(tmp)`, where "tmp" is a temporary unused variable
+//
+// * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list
+//
+// * `inout(reg_class) in_var => out_var` -> translated to two operands:
+// output: `"=CC"(in_var)`
+// input: `"num"(out_var)` where num is the GCC index
+// of the corresponding output operand
+//
+// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`,
+// where "tmp" is a temporary unused variable
+//
+// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above
+// with `"r"(var)` constraint,
+// and one register variable assigned to the desired register.
+//
+
+const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t";
+const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix";
+
+
+struct AsmOutOperand<'a, 'tcx, 'gcc> {
+ rust_idx: usize,
+ constraint: &'a str,
+ late: bool,
+ readwrite: bool,
+
+ tmp_var: LValue<'gcc>,
+ out_place: Option<PlaceRef<'tcx, RValue<'gcc>>>
+}
+
+struct AsmInOperand<'a, 'tcx> {
+ rust_idx: usize,
+ constraint: Cow<'a, str>,
+ val: RValue<'tcx>
+}
+
+impl AsmOutOperand<'_, '_, '_> {
+ fn to_constraint(&self) -> String {
+ let mut res = String::with_capacity(self.constraint.len() + self.late as usize + 1);
+
+ let sign = if self.readwrite { '+' } else { '=' };
+ res.push(sign);
+ if !self.late {
+ res.push('&');
+ }
+
+ res.push_str(&self.constraint);
+ res
+ }
+}
+
+enum ConstraintOrRegister {
+ Constraint(&'static str),
+ Register(&'static str)
+}
+
+
+impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+ fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
+ self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
+ .help("consider using the `asm!` macro instead")
+ .emit();
+
+ // We return `true` even if we've failed to generate the asm
+ // because we want to suppress the "malformed inline assembly" error
+ // generated by the frontend.
+ true
+ }
+
+ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+ let asm_arch = self.tcx.sess.asm_arch.unwrap();
+ let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
+ let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
+ let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX);
+
+ // GCC index of an output operand equals its position in the array
+ let mut outputs = vec![];
+
+ // GCC index of an input operand equals its position in the array
+ // added to `outputs.len()`
+ let mut inputs = vec![];
+
+ // Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
+ let mut clobbers = vec![];
+
+ // We're trying to preallocate space for the template
+ let mut constants_len = 0;
+
+ // There are rules we must adhere to if we want GCC to do the right thing:
+ //
+ // * Every local variable that the asm block uses as an output must be declared *before*
+ // the asm block.
+ // * There must be no instructions whatsoever between the register variables and the asm.
+ //
+ // Therefore, the backend must generate the instructions strictly in this order:
+ //
+ // 1. Output variables.
+ // 2. Register variables.
+ // 3. The asm block.
+ //
+ // We also must make sure that no input operands are emitted before output operands.
+ //
+ // This is why we work in passes, first emitting local vars, then local register vars.
+ // Also, we don't emit any asm operands immediately; we save them to
+ // the one of the buffers to be emitted later.
+
+ // 1. Normal variables (and saving operands to buffers).
+ for (rust_idx, op) in rust_operands.iter().enumerate() {
+ match *op {
+ InlineAsmOperandRef::Out { reg, late, place } => {
+ use ConstraintOrRegister::*;
+
+ let (constraint, ty) = match (reg_to_gcc(reg), place) {
+ (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)),
+ // When `reg` is a class and not an explicit register but the out place is not specified,
+ // we need to create an unused output variable to assign the output to. This var
+ // needs to be of a type that's "compatible" with the register class, but specific type
+ // doesn't matter.
+ (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())),
+ (Register(_), Some(_)) => {
+ // left for the next pass
+ continue
+ },
+ (Register(reg_name), None) => {
+ // `clobber_abi` can add lots of clobbers that are not supported by the target,
+ // such as AVX-512 registers, so we just ignore unsupported registers
+ let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
+ .any(|&(_, feature)| {
+ if let Some(feature) = feature {
+ self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+ } else {
+ true // Register class is unconditionally supported
+ }
+ });
+
+ if is_target_supported && !clobbers.contains(®_name) {
+ clobbers.push(reg_name);
+ }
+ continue
+ }
+ };
+
+ let tmp_var = self.current_func().new_local(None, ty, "output_register");
+ outputs.push(AsmOutOperand {
+ constraint,
+ rust_idx,
+ late,
+ readwrite: false,
+ tmp_var,
+ out_place: place
+ });
+ }
+
+ InlineAsmOperandRef::In { reg, value } => {
+ if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
+ inputs.push(AsmInOperand {
+ constraint: Cow::Borrowed(constraint),
+ rust_idx,
+ val: value.immediate()
+ });
+ }
+ else {
+ // left for the next pass
+ continue
+ }
+ }
+
+ InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
+ let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
+ constraint
+ }
+ else {
+ // left for the next pass
+ continue
+ };
+
+ // Rustc frontend guarantees that input and output types are "compatible",
+ // so we can just use input var's type for the output variable.
+ //
+ // This decision is also backed by the fact that LLVM needs in and out
+ // values to be of *exactly the same type*, not just "compatible".
+ // I'm not sure if GCC is so picky too, but better safe than sorry.
+ let ty = in_value.layout.gcc_type(self.cx, false);
+ let tmp_var = self.current_func().new_local(None, ty, "output_register");
+
+ // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate
+ // it to one "readwrite (+) output variable", otherwise we translate it to two
+ // "out and tied in" vars as described above.
+ let readwrite = out_place.is_none();
+ outputs.push(AsmOutOperand {
+ constraint,
+ rust_idx,
+ late,
+ readwrite,
+ tmp_var,
+ out_place,
+ });
+
+ if !readwrite {
+ let out_gcc_idx = outputs.len() - 1;
+ let constraint = Cow::Owned(out_gcc_idx.to_string());
+
+ inputs.push(AsmInOperand {
+ constraint,
+ rust_idx,
+ val: in_value.immediate()
+ });
+ }
+ }
+
+ InlineAsmOperandRef::Const { ref string } => {
+ constants_len += string.len() + att_dialect as usize;
+ }
+
+ InlineAsmOperandRef::SymFn { instance } => {
+ constants_len += self.tcx.symbol_name(instance).name.len();
+ }
+ InlineAsmOperandRef::SymStatic { def_id } => {
+ constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
+ }
+ }
+ }
+
+ // 2. Register variables.
+ for (rust_idx, op) in rust_operands.iter().enumerate() {
+ match *op {
+ // `out("explicit register") var`
+ InlineAsmOperandRef::Out { reg, late, place } => {
+ if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+ let out_place = if let Some(place) = place {
+ place
+ }
+ else {
+ // processed in the previous pass
+ continue
+ };
+
+ let ty = out_place.layout.gcc_type(self.cx, false);
+ let tmp_var = self.current_func().new_local(None, ty, "output_register");
+ tmp_var.set_register_name(reg_name);
+
+ outputs.push(AsmOutOperand {
+ constraint: "r".into(),
+ rust_idx,
+ late,
+ readwrite: false,
+ tmp_var,
+ out_place: Some(out_place)
+ });
+ }
+
+ // processed in the previous pass
+ }
+
+ // `in("explicit register") var`
+ InlineAsmOperandRef::In { reg, value } => {
+ if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+ let ty = value.layout.gcc_type(self.cx, false);
+ let reg_var = self.current_func().new_local(None, ty, "input_register");
+ reg_var.set_register_name(reg_name);
+ self.llbb().add_assignment(None, reg_var, value.immediate());
+
+ inputs.push(AsmInOperand {
+ constraint: "r".into(),
+ rust_idx,
+ val: reg_var.to_rvalue()
+ });
+ }
+
+ // processed in the previous pass
+ }
+
+ // `inout("explicit register") in_var => out_var`
+ InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
+ if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+ let out_place = if let Some(place) = out_place {
+ place
+ }
+ else {
+ // processed in the previous pass
+ continue
+ };
+
+ // See explanation in the first pass.
+ let ty = in_value.layout.gcc_type(self.cx, false);
+ let tmp_var = self.current_func().new_local(None, ty, "output_register");
+ tmp_var.set_register_name(reg_name);
+
+ outputs.push(AsmOutOperand {
+ constraint: "r".into(),
+ rust_idx,
+ late,
+ readwrite: false,
+ tmp_var,
+ out_place: Some(out_place)
+ });
+
+ let constraint = Cow::Owned((outputs.len() - 1).to_string());
+ inputs.push(AsmInOperand {
+ constraint,
+ rust_idx,
+ val: in_value.immediate()
+ });
+ }
+
+ // processed in the previous pass
+ }
+
+ InlineAsmOperandRef::Const { .. }
+ | InlineAsmOperandRef::SymFn { .. }
+ | InlineAsmOperandRef::SymStatic { .. } => {
+ // processed in the previous pass
+ }
+ }
+ }
+
+ // 3. Build the template string
+
+ let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect));
+ if !intel_dialect {
+ template_str.push_str(ATT_SYNTAX_INS);
+ }
+
+ for piece in template {
+ match *piece {
+ InlineAsmTemplatePiece::String(ref string) => {
+ // TODO(@Commeownist): switch to `Iterator::intersperse` once it's stable
+ let mut iter = string.split('%');
+ if let Some(s) = iter.next() {
+ template_str.push_str(s);
+ }
+
+ for s in iter {
+ template_str.push_str("%%");
+ template_str.push_str(s);
+ }
+ }
+ InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => {
+ let mut push_to_template = |modifier, gcc_idx| {
+ use std::fmt::Write;
+
+ template_str.push('%');
+ if let Some(modifier) = modifier {
+ template_str.push(modifier);
+ }
+ write!(template_str, "{}", gcc_idx).expect("pushing to string failed");
+ };
+
+ match rust_operands[operand_idx] {
+ InlineAsmOperandRef::Out { reg, .. } => {
+ let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+ let gcc_index = outputs.iter()
+ .position(|op| operand_idx == op.rust_idx)
+ .expect("wrong rust index");
+ push_to_template(modifier, gcc_index);
+ }
+
+ InlineAsmOperandRef::In { reg, .. } => {
+ let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+ let in_gcc_index = inputs.iter()
+ .position(|op| operand_idx == op.rust_idx)
+ .expect("wrong rust index");
+ let gcc_index = in_gcc_index + outputs.len();
+ push_to_template(modifier, gcc_index);
+ }
+
+ InlineAsmOperandRef::InOut { reg, .. } => {
+ let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+
+ // The input register is tied to the output, so we can just use the index of the output register
+ let gcc_index = outputs.iter()
+ .position(|op| operand_idx == op.rust_idx)
+ .expect("wrong rust index");
+ push_to_template(modifier, gcc_index);
+ }
+
+ InlineAsmOperandRef::SymFn { instance } => {
+ let name = self.tcx.symbol_name(instance).name;
+ template_str.push_str(name);
+ }
+
+ InlineAsmOperandRef::SymStatic { def_id } => {
+ // TODO(@Commeownist): This may not be sufficient for all kinds of statics.
+ // Some statics may need the `@plt` suffix, like thread-local vars.
+ let instance = Instance::mono(self.tcx, def_id);
+ let name = self.tcx.symbol_name(instance).name;
+ template_str.push_str(name);
+ }
+
+ InlineAsmOperandRef::Const { ref string } => {
+ // Const operands get injected directly into the template
+ if att_dialect {
+ template_str.push('$');
+ }
+ template_str.push_str(string);
+ }
+ }
+ }
+ }
+ }
+
+ if !intel_dialect {
+ template_str.push_str(INTEL_SYNTAX_INS);
+ }
+
+ // 4. Generate Extended Asm block
+
+ let block = self.llbb();
+ let extended_asm = block.add_extended_asm(None, &template_str);
+
+ for op in &outputs {
+ extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var);
+ }
+
+ for op in &inputs {
+ extended_asm.add_input_operand(None, &op.constraint, op.val);
+ }
+
+ for clobber in clobbers.iter() {
+ extended_asm.add_clobber(clobber);
+ }
+
+ if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
+ // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient
+ // on all architectures. For instance, what about FP stack?
+ extended_asm.add_clobber("cc");
+ }
+ if !options.contains(InlineAsmOptions::NOMEM) {
+ extended_asm.add_clobber("memory");
+ }
+ if !options.contains(InlineAsmOptions::PURE) {
+ extended_asm.set_volatile_flag(true);
+ }
+ if !options.contains(InlineAsmOptions::NOSTACK) {
+ // TODO(@Commeownist): figure out how to align stack
+ }
+ if options.contains(InlineAsmOptions::NORETURN) {
+ let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
+ let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
+ self.call(self.type_void(), builtin_unreachable, &[], None);
+ }
+
+ // Write results to outputs.
+ //
+ // We need to do this because:
+ // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases
+ // (especially with current `rustc_backend_ssa` API).
+ // 2. Not every output operand has an `out_place`, and it's required by `add_output_operand`.
+ //
+ // Instead, we generate a temporary output variable for each output operand, and then this loop,
+ // generates `out_place = tmp_var;` assignments if out_place exists.
+ for op in &outputs {
+ if let Some(place) = op.out_place {
+ OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);
+ }
+ }
+
+ }
+}
+
+fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize {
+ let len: usize = template.iter().map(|piece| {
+ match *piece {
+ InlineAsmTemplatePiece::String(ref string) => {
+ string.len()
+ }
+ InlineAsmTemplatePiece::Placeholder { .. } => {
+ // '%' + 1 char modifier + 1 char index
+ 3
+ }
+ }
+ })
+ .sum();
+
+ // increase it by 5% to account for possible '%' signs that'll be duplicated
+ // I pulled the number out of blue, but should be fair enough
+ // as the upper bound
+ let mut res = (len as f32 * 1.05) as usize + constants_len;
+
+ if att_dialect {
+ res += INTEL_SYNTAX_INS.len() + ATT_SYNTAX_INS.len();
+ }
+ res
+}
+
+/// Converts a register class to a GCC constraint code.
+fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
+ let constraint = match reg {
+ // For vector registers LLVM wants the register name to match the type size.
+ InlineAsmRegOrRegClass::Reg(reg) => {
+ match reg {
+ InlineAsmReg::X86(_) => {
+ // TODO(antoyo): add support for vector register.
+ //
+ // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
+ return ConstraintOrRegister::Register(match reg.name() {
+ // Some of registers' names does not map 1-1 from rust to gcc
+ "st(0)" => "st",
+
+ name => name,
+ });
+ }
+
+ _ => unimplemented!(),
+ }
+ },
+ InlineAsmRegOrRegClass::RegClass(reg) => match reg {
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(),
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(),
+ InlineAsmRegClass::Bpf(_) => unimplemented!(),
+ InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+ | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+ unreachable!("clobber-only")
+ },
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+ | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+ InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
+ InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+ ) => unreachable!("clobber-only"),
+ InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+ bug!("GCC backend does not support SPIR-V")
+ }
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::Err => unreachable!(),
+ }
+ };
+
+ ConstraintOrRegister::Constraint(constraint)
+}
+
+/// Type to use for outputs that are discarded. It doesn't really matter what
+/// the type is, as long as it is valid for the constraint code.
+fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegClass) -> Type<'gcc> {
+ match reg {
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
+ | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
+ unimplemented!()
+ }
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
+ unimplemented!()
+ }
+ InlineAsmRegClass::Bpf(_) => unimplemented!(),
+ InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+ | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+ unreachable!("clobber-only")
+ },
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
+ | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::mmx_reg) => unimplemented!(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+ | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
+ | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+ InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
+ InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+ bug!("LLVM backend does not support SPIR-V")
+ },
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+ InlineAsmRegClass::Err => unreachable!(),
+ }
+}
+
+impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
+ fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) {
+ let asm_arch = self.tcx.sess.asm_arch.unwrap();
+
+ // Default to Intel syntax on x86
+ let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
+ && !options.contains(InlineAsmOptions::ATT_SYNTAX);
+
+ // Build the template string
+ let mut template_str = String::new();
+ for piece in template {
+ match *piece {
+ InlineAsmTemplatePiece::String(ref string) => {
+ for line in string.lines() {
+ // NOTE: gcc does not allow inline comment, so remove them.
+ let line =
+ if let Some(index) = line.rfind("//") {
+ &line[..index]
+ }
+ else {
+ line
+ };
+ template_str.push_str(line);
+ template_str.push('\n');
+ }
+ },
+ InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
+ match operands[operand_idx] {
+ GlobalAsmOperandRef::Const { ref string } => {
+ // Const operands get injected directly into the
+ // template. Note that we don't need to escape %
+ // here unlike normal inline assembly.
+ template_str.push_str(string);
+ }
+ }
+ }
+ }
+ }
+
+ let template_str =
+ if intel_syntax {
+ format!("{}\n\t.intel_syntax noprefix", template_str)
+ }
+ else {
+ format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str)
+ };
+ // NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually.
+ let template_str = format!(".pushsection .text\n{}\n.popsection", template_str);
+ self.context.add_top_level_asm(None, &template_str);
+ }
+}
+
+fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option<char>) -> Option<char> {
+ match reg {
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => modifier,
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
+ | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
+ unimplemented!()
+ }
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
+ unimplemented!()
+ }
+ InlineAsmRegClass::Bpf(_) => unimplemented!(),
+ InlineAsmRegClass::Hexagon(_) => unimplemented!(),
+ InlineAsmRegClass::Mips(_) => unimplemented!(),
+ InlineAsmRegClass::Nvptx(_) => unimplemented!(),
+ InlineAsmRegClass::PowerPC(_) => unimplemented!(),
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
+ | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
+ | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
+ None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') },
+ Some('l') => Some('b'),
+ Some('h') => Some('h'),
+ Some('x') => Some('w'),
+ Some('e') => Some('k'),
+ Some('r') => Some('q'),
+ _ => unreachable!(),
+ },
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None,
+ InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg)
+ | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg)
+ | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) {
+ (X86InlineAsmRegClass::xmm_reg, None) => Some('x'),
+ (X86InlineAsmRegClass::ymm_reg, None) => Some('t'),
+ (X86InlineAsmRegClass::zmm_reg, None) => Some('g'),
+ (_, Some('x')) => Some('x'),
+ (_, Some('y')) => Some('t'),
+ (_, Some('z')) => Some('g'),
+ _ => unreachable!(),
+ },
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+ unreachable!("clobber-only")
+ }
+ InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
+ InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+ bug!("LLVM backend does not support SPIR-V")
+ },
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
+ InlineAsmRegClass::Err => unreachable!(),
+ }
+}
--- /dev/null
+pub mod write;
--- /dev/null
+use std::fs;
+
+use gccjit::OutputKind;
+use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
+use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig};
+use rustc_errors::Handler;
+use rustc_session::config::OutputType;
+use rustc_span::fatal_error::FatalError;
+use rustc_target::spec::SplitDebuginfo;
+
+use crate::{GccCodegenBackend, GccContext};
+
+pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+ let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &module.name[..]);
+ {
+ let context = &module.module_llvm.context;
+
+ let module_name = module.name.clone();
+ let module_name = Some(&module_name[..]);
+
+ let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+ let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
+
+ if config.bitcode_needed() {
+ // TODO(antoyo)
+ }
+
+ if config.emit_ir {
+ unimplemented!();
+ }
+
+ if config.emit_asm {
+ let _timer = cgcx
+ .prof
+ .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
+ let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+ context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
+ }
+
+ match config.emit_obj {
+ EmitObj::ObjectCode(_) => {
+ let _timer = cgcx
+ .prof
+ .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
+ match &*module.name {
+ "std_example.7rcbfp3g-cgu.15" => {
+ println!("Dumping reproducer {}", module.name);
+ let _ = fs::create_dir("/tmp/reproducers");
+ // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
+ // transmuting an rvalue to an lvalue.
+ // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
+ context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
+ println!("Dumped reproducer {}", module.name);
+ },
+ _ => (),
+ }
+ context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
+ }
+
+ EmitObj::Bitcode => {
+ // TODO(antoyo)
+ }
+
+ EmitObj::None => {}
+ }
+ }
+
+ Ok(module.into_compiled_module(
+ config.emit_obj != EmitObj::None,
+ cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+ config.emit_bc,
+ &cgcx.output_filenames,
+ ))
+}
+
+pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
+ unimplemented!();
+}
--- /dev/null
+use std::env;
+use std::time::Instant;
+
+use gccjit::{
+ Context,
+ FunctionType,
+ GlobalKind,
+};
+use rustc_middle::dep_graph;
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::middle::exported_symbols;
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::mono::Linkage;
+use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
+use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
+use rustc_codegen_ssa::mono_item::MonoItemExt;
+use rustc_codegen_ssa::traits::DebugInfoMethods;
+use rustc_session::config::DebugInfo;
+use rustc_span::Symbol;
+
+use crate::GccContext;
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
+ match linkage {
+ Linkage::External => GlobalKind::Imported,
+ Linkage::AvailableExternally => GlobalKind::Imported,
+ Linkage::LinkOnceAny => unimplemented!(),
+ Linkage::LinkOnceODR => unimplemented!(),
+ Linkage::WeakAny => unimplemented!(),
+ Linkage::WeakODR => unimplemented!(),
+ Linkage::Appending => unimplemented!(),
+ Linkage::Internal => GlobalKind::Internal,
+ Linkage::Private => GlobalKind::Internal,
+ Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage.
+ Linkage::Common => unimplemented!(),
+ }
+}
+
+pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
+ match linkage {
+ Linkage::External => FunctionType::Exported,
+ Linkage::AvailableExternally => FunctionType::Extern,
+ Linkage::LinkOnceAny => unimplemented!(),
+ Linkage::LinkOnceODR => unimplemented!(),
+ Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce.
+ Linkage::WeakODR => unimplemented!(),
+ Linkage::Appending => unimplemented!(),
+ Linkage::Internal => FunctionType::Internal,
+ Linkage::Private => FunctionType::Internal,
+ Linkage::ExternalWeak => unimplemented!(),
+ Linkage::Common => unimplemented!(),
+ }
+}
+
+pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<GccContext>, u64) {
+ let prof_timer = tcx.prof.generic_activity("codegen_module");
+ let start_time = Instant::now();
+
+ let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
+ let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+ let time_to_codegen = start_time.elapsed();
+ drop(prof_timer);
+
+ // We assume that the cost to run GCC on a CGU is proportional to
+ // the time we needed for codegenning it.
+ let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
+
+ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<GccContext> {
+ let cgu = tcx.codegen_unit(cgu_name);
+ // Instantiate monomorphizations without filling out definitions yet...
+ //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
+ let context = Context::default();
+ // TODO(antoyo): only set on x86 platforms.
+ context.add_command_line_option("-masm=intel");
+ for arg in &tcx.sess.opts.cg.llvm_args {
+ context.add_command_line_option(arg);
+ }
+ context.add_command_line_option("-fno-semantic-interposition");
+ if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
+ context.set_dump_code_on_compile(true);
+ }
+ if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") {
+ context.set_dump_initial_gimple(true);
+ }
+ context.set_debug_info(true);
+ if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") {
+ context.set_dump_everything(true);
+ }
+ if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") {
+ context.set_keep_intermediates(true);
+ }
+
+ {
+ let cx = CodegenCx::new(&context, cgu, tcx);
+
+ let mono_items = cgu.items_in_deterministic_order(tcx);
+ for &(mono_item, (linkage, visibility)) in &mono_items {
+ mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
+ }
+
+ // ... and now that we have everything pre-defined, fill out those definitions.
+ for &(mono_item, _) in &mono_items {
+ mono_item.define::<Builder<'_, '_, '_>>(&cx);
+ }
+
+ // If this codegen unit contains the main function, also create the
+ // wrapper here
+ maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx);
+
+ // Finalize debuginfo
+ if cx.sess().opts.debuginfo != DebugInfo::None {
+ cx.debuginfo_finalize();
+ }
+ }
+
+ ModuleCodegen {
+ name: cgu_name.to_string(),
+ module_llvm: GccContext {
+ context
+ },
+ kind: ModuleKind::Regular,
+ }
+ }
+
+ (module, cost)
+}
+
+pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) {
+ use snap::write::FrameEncoder;
+ use std::io::Write;
+
+ // Historical note:
+ //
+ // When using link.exe it was seen that the section name `.note.rustc`
+ // was getting shortened to `.note.ru`, and according to the PE and COFF
+ // specification:
+ //
+ // > Executable images do not use a string table and do not support
+ // > section names longer than 8 characters
+ //
+ // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+ //
+ // As a result, we choose a slightly shorter name! As to why
+ // `.note.rustc` works on MinGW, see
+ // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
+ let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
+
+ let context = &gcc_module.context;
+ let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
+ FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
+
+ let name = exported_symbols::metadata_symbol_name(tcx);
+ let typ = context.new_array_type(None, context.new_type::<u8>(), compressed.len() as i32);
+ let global = context.new_global(None, GlobalKind::Exported, typ, name);
+ global.global_set_initializer(&compressed);
+ global.set_link_section(section_name);
+
+ // Also generate a .section directive to force no
+ // flags, at least for ELF outputs, so that the
+ // metadata doesn't get loaded into memory.
+ let directive = format!(".section {}", section_name);
+ context.add_top_level_asm(None, &directive);
+}
--- /dev/null
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::convert::TryFrom;
+use std::ops::Deref;
+
+use gccjit::FunctionType;
+use gccjit::{
+ BinaryOp,
+ Block,
+ ComparisonOp,
+ Function,
+ LValue,
+ RValue,
+ ToRValue,
+ Type,
+ UnaryOp,
+};
+use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope};
+use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{
+ BackendTypes,
+ BaseTypeMethods,
+ BuilderMethods,
+ ConstMethods,
+ DerivedTypeMethods,
+ LayoutTypeMethods,
+ HasCodegen,
+ OverflowOp,
+ StaticBuilderMethods,
+};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
+use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{
+ self,
+ call::FnAbi,
+ Align,
+ HasDataLayout,
+ Size,
+ TargetDataLayout,
+ WrappingRange,
+};
+use rustc_target::spec::{HasTargetSpec, Target};
+
+use crate::common::{SignType, TypeReflection, type_is_pointer};
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+// TODO(antoyo)
+type Funclet = ();
+
+// TODO(antoyo): remove this variable.
+static mut RETURN_VALUE_COUNT: usize = 0;
+
+enum ExtremumOperation {
+ Max,
+ Min,
+}
+
+trait EnumClone {
+ fn clone(&self) -> Self;
+}
+
+impl EnumClone for AtomicOrdering {
+ fn clone(&self) -> Self {
+ match *self {
+ AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic,
+ AtomicOrdering::Unordered => AtomicOrdering::Unordered,
+ AtomicOrdering::Monotonic => AtomicOrdering::Monotonic,
+ AtomicOrdering::Acquire => AtomicOrdering::Acquire,
+ AtomicOrdering::Release => AtomicOrdering::Release,
+ AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease,
+ AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent,
+ }
+ }
+}
+
+pub struct Builder<'a: 'gcc, 'gcc, 'tcx> {
+ pub cx: &'a CodegenCx<'gcc, 'tcx>,
+ pub block: Option<Block<'gcc>>,
+ stack_var_count: Cell<usize>,
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+ fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>) -> Self {
+ Builder {
+ cx,
+ block: None,
+ stack_var_count: Cell::new(0),
+ }
+ }
+
+ fn atomic_extremum(&mut self, operation: ExtremumOperation, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
+ let size = self.cx.int_width(src.get_type()) / 8;
+
+ let func = self.current_func();
+
+ let load_ordering =
+ match order {
+ // TODO(antoyo): does this make sense?
+ AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire,
+ _ => order.clone(),
+ };
+ let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size));
+ let previous_var = func.new_local(None, previous_value.get_type(), "previous_value");
+ let return_value = func.new_local(None, previous_value.get_type(), "return_value");
+ self.llbb().add_assignment(None, previous_var, previous_value);
+ self.llbb().add_assignment(None, return_value, previous_var.to_rvalue());
+
+ let while_block = func.new_block("while");
+ let after_block = func.new_block("after_while");
+ self.llbb().end_with_jump(None, while_block);
+
+ // NOTE: since jumps were added and compare_exchange doesn't expect this, the current blocks in the
+ // state need to be updated.
+ self.block = Some(while_block);
+ *self.cx.current_block.borrow_mut() = Some(while_block);
+
+ let comparison_operator =
+ match operation {
+ ExtremumOperation::Max => ComparisonOp::LessThan,
+ ExtremumOperation::Min => ComparisonOp::GreaterThan,
+ };
+
+ let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type()));
+ let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false);
+ let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange);
+ let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2);
+
+ while_block.end_with_conditional(None, cond, while_block, after_block);
+
+ // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+ // state need to be updated.
+ self.block = Some(after_block);
+ *self.cx.current_block.borrow_mut() = Some(after_block);
+
+ return_value.to_rvalue()
+ }
+
+ fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+ let size = self.cx.int_width(src.get_type());
+ let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8));
+ let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+ let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc());
+ let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32);
+
+ let void_ptr_type = self.context.new_type::<*mut ()>();
+ let volatile_void_ptr_type = void_ptr_type.make_volatile();
+ let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
+ let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type);
+
+ // NOTE: not sure why, but we have the wrong type here.
+ let int_type = compare_exchange.get_param(2).to_rvalue().get_type();
+ let src = self.context.new_cast(None, src, int_type);
+ self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order])
+ }
+
+ pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) {
+ self.llbb().add_assignment(None, lvalue, value);
+ }
+
+ fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
+ let mut all_args_match = true;
+ let mut param_types = vec![];
+ let param_count = func.get_param_count();
+ for (index, arg) in args.iter().enumerate().take(param_count) {
+ let param = func.get_param(index as i32);
+ let param = param.to_rvalue().get_type();
+ if param != arg.get_type() {
+ all_args_match = false;
+ }
+ param_types.push(param);
+ }
+
+ if all_args_match {
+ return Cow::Borrowed(args);
+ }
+
+ let casted_args: Vec<_> = param_types
+ .into_iter()
+ .zip(args.iter())
+ .enumerate()
+ .map(|(_i, (expected_ty, &actual_val))| {
+ let actual_ty = actual_val.get_type();
+ if expected_ty != actual_ty {
+ self.bitcast(actual_val, expected_ty)
+ }
+ else {
+ actual_val
+ }
+ })
+ .collect();
+
+ Cow::Owned(casted_args)
+ }
+
+ fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
+ let mut all_args_match = true;
+ let mut param_types = vec![];
+ let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+ for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) {
+ let param = gcc_func.get_param_type(index);
+ if param != arg.get_type() {
+ all_args_match = false;
+ }
+ param_types.push(param);
+ }
+
+ if all_args_match {
+ return Cow::Borrowed(args);
+ }
+
+ let casted_args: Vec<_> = param_types
+ .into_iter()
+ .zip(args.iter())
+ .enumerate()
+ .map(|(_i, (expected_ty, &actual_val))| {
+ let actual_ty = actual_val.get_type();
+ if expected_ty != actual_ty {
+ self.bitcast(actual_val, expected_ty)
+ }
+ else {
+ actual_val
+ }
+ })
+ .collect();
+
+ Cow::Owned(casted_args)
+ }
+
+ fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
+ let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here.
+ let stored_ty = self.cx.val_ty(val);
+ let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
+
+ if dest_ptr_ty == stored_ptr_ty {
+ ptr
+ }
+ else {
+ self.bitcast(ptr, stored_ptr_ty)
+ }
+ }
+
+ pub fn current_func(&self) -> Function<'gcc> {
+ self.block.expect("block").get_function()
+ }
+
+ fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ // TODO(antoyo): remove when the API supports a different type for functions.
+ let func: Function<'gcc> = self.cx.rvalue_as_function(func);
+ let args = self.check_call("call", func, args);
+
+ // gccjit requires to use the result of functions, even when it's not used.
+ // That's why we assign the result to a local or call add_eval().
+ let return_type = func.get_return_type();
+ let current_block = self.current_block.borrow().expect("block");
+ let void_type = self.context.new_type::<()>();
+ let current_func = current_block.get_function();
+ if return_type != void_type {
+ unsafe { RETURN_VALUE_COUNT += 1 };
+ let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+ current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
+ result.to_rvalue()
+ }
+ else {
+ current_block.add_eval(None, self.cx.context.new_call(None, func, &args));
+ // Return dummy value when not having return value.
+ self.context.new_rvalue_from_long(self.isize_type, 0)
+ }
+ }
+
+ fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ let args = self.check_ptr_call("call", func_ptr, args);
+
+ // gccjit requires to use the result of functions, even when it's not used.
+ // That's why we assign the result to a local or call add_eval().
+ let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+ let mut return_type = gcc_func.get_return_type();
+ let current_block = self.current_block.borrow().expect("block");
+ let void_type = self.context.new_type::<()>();
+ let current_func = current_block.get_function();
+
+ // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
+ if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" {
+ return_type = self.int_type;
+ }
+
+ if return_type != void_type {
+ unsafe { RETURN_VALUE_COUNT += 1 };
+ let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+ current_block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
+ result.to_rvalue()
+ }
+ else {
+ if gcc_func.get_param_count() == 0 {
+ // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
+ current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[]));
+ }
+ else {
+ current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
+ }
+ // Return dummy value when not having return value.
+ let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed");
+ current_block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0));
+ result.to_rvalue()
+ }
+ }
+
+ pub fn overflow_call(&mut self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ // gccjit requires to use the result of functions, even when it's not used.
+ // That's why we assign the result to a local.
+ let return_type = self.context.new_type::<bool>();
+ let current_block = self.current_block.borrow().expect("block");
+ let current_func = current_block.get_function();
+ // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects.
+ unsafe { RETURN_VALUE_COUNT += 1 };
+ let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+ current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
+ result.to_rvalue()
+ }
+}
+
+impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> {
+ type CodegenCx = CodegenCx<'gcc, 'tcx>;
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.cx.tcx()
+ }
+}
+
+impl HasDataLayout for Builder<'_, '_, '_> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ self.cx.data_layout()
+ }
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+ type LayoutOfResult = TyAndLayout<'tcx>;
+
+ #[inline]
+ fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+ self.cx.handle_layout_err(err, span, ty)
+ }
+}
+
+impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+ type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+ #[inline]
+ fn handle_fn_abi_err(
+ &self,
+ err: FnAbiError<'tcx>,
+ span: Span,
+ fn_abi_request: FnAbiRequest<'tcx>,
+ ) -> ! {
+ self.cx.handle_fn_abi_err(err, span, fn_abi_request)
+ }
+}
+
+impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> {
+ type Target = CodegenCx<'gcc, 'tcx>;
+
+ fn deref(&self) -> &Self::Target {
+ self.cx
+ }
+}
+
+impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
+ type Value = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Value;
+ type Function = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Function;
+ type BasicBlock = <CodegenCx<'gcc, 'tcx> as BackendTypes>::BasicBlock;
+ type Type = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Type;
+ type Funclet = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Funclet;
+
+ type DIScope = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIScope;
+ type DILocation = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DILocation;
+ type DIVariable = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIVariable;
+}
+
+impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
+ fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self {
+ let mut bx = Builder::with_cx(cx);
+ *cx.current_block.borrow_mut() = Some(block);
+ bx.block = Some(block);
+ bx
+ }
+
+ fn build_sibling_block(&mut self, name: &str) -> Self {
+ let block = self.append_sibling_block(name);
+ Self::build(self.cx, block)
+ }
+
+ fn llbb(&self) -> Block<'gcc> {
+ self.block.expect("block")
+ }
+
+ fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> {
+ let func = cx.rvalue_as_function(func);
+ func.new_block(name)
+ }
+
+ fn append_sibling_block(&mut self, name: &str) -> Block<'gcc> {
+ let func = self.current_func();
+ func.new_block(name)
+ }
+
+ fn ret_void(&mut self) {
+ self.llbb().end_with_void_return(None)
+ }
+
+ fn ret(&mut self, value: RValue<'gcc>) {
+ let value =
+ if self.structs_as_pointer.borrow().contains(&value) {
+ // NOTE: hack to workaround a limitation of the rustc API: see comment on
+ // CodegenCx.structs_as_pointer
+ value.dereference(None).to_rvalue()
+ }
+ else {
+ value
+ };
+ self.llbb().end_with_return(None, value);
+ }
+
+ fn br(&mut self, dest: Block<'gcc>) {
+ self.llbb().end_with_jump(None, dest)
+ }
+
+ fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) {
+ self.llbb().end_with_conditional(None, cond, then_block, else_block)
+ }
+
+ fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator<Item = (u128, Block<'gcc>)>) {
+ let mut gcc_cases = vec![];
+ let typ = self.val_ty(value);
+ for (on_val, dest) in cases {
+ let on_val = self.const_uint_big(typ, on_val);
+ gcc_cases.push(self.context.new_case(on_val, on_val, dest));
+ }
+ self.block.expect("block").end_with_switch(None, value, default_block, &gcc_cases);
+ }
+
+ fn invoke(&mut self, _typ: Type<'gcc>, _func: RValue<'gcc>, _args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ let condition = self.context.new_rvalue_from_int(self.bool_type, 0);
+ self.llbb().end_with_conditional(None, condition, then, catch);
+ self.context.new_rvalue_from_int(self.int_type, 0)
+
+ // TODO(antoyo)
+ }
+
+ fn unreachable(&mut self) {
+ let func = self.context.get_builtin_function("__builtin_unreachable");
+ let block = self.block.expect("block");
+ block.add_eval(None, self.context.new_call(None, func, &[]));
+ let return_type = block.get_function().get_return_type();
+ let void_type = self.context.new_type::<()>();
+ if return_type == void_type {
+ block.end_with_void_return(None)
+ }
+ else {
+ let return_value = self.current_func()
+ .new_local(None, return_type, "unreachableReturn");
+ block.end_with_return(None, return_value)
+ }
+ }
+
+ fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+ // FIXME(antoyo): this should not be required.
+ if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) {
+ b = self.context.new_cast(None, b, a.get_type());
+ }
+ a + b
+ }
+
+ fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a + b
+ }
+
+ fn sub(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+ if a.get_type() != b.get_type() {
+ b = self.context.new_cast(None, b, a.get_type());
+ }
+ a - b
+ }
+
+ fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a - b
+ }
+
+ fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a * b
+ }
+
+ fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a * b
+ }
+
+ fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): convert the arguments to unsigned?
+ a / b
+ }
+
+ fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): convert the arguments to unsigned?
+ // TODO(antoyo): poison if not exact.
+ a / b
+ }
+
+ fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): convert the arguments to signed?
+ a / b
+ }
+
+ fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): posion if not exact.
+ // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
+ // should be the same.
+ let typ = a.get_type().to_signed(self);
+ let b = self.context.new_cast(None, b, typ);
+ a / b
+ }
+
+ fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a / b
+ }
+
+ fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a % b
+ }
+
+ fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a % b
+ }
+
+ fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ if a.get_type() == self.cx.float_type {
+ let fmodf = self.context.get_builtin_function("fmodf");
+ // FIXME(antoyo): this seems to produce the wrong result.
+ return self.context.new_call(None, fmodf, &[a, b]);
+ }
+ assert_eq!(a.get_type(), self.cx.double_type);
+
+ let fmod = self.context.get_builtin_function("fmod");
+ return self.context.new_call(None, fmod, &[a, b]);
+ }
+
+ fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+ let a_type = a.get_type();
+ let b_type = b.get_type();
+ if a_type.is_unsigned(self) && b_type.is_signed(self) {
+ let a = self.context.new_cast(None, a, b_type);
+ let result = a << b;
+ self.context.new_cast(None, result, a_type)
+ }
+ else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+ let b = self.context.new_cast(None, b, a_type);
+ a << b
+ }
+ else {
+ a << b
+ }
+ }
+
+ fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+ // TODO(antoyo): cast to unsigned to do a logical shift if that does not work.
+ let a_type = a.get_type();
+ let b_type = b.get_type();
+ if a_type.is_unsigned(self) && b_type.is_signed(self) {
+ let a = self.context.new_cast(None, a, b_type);
+ let result = a >> b;
+ self.context.new_cast(None, result, a_type)
+ }
+ else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+ let b = self.context.new_cast(None, b, a_type);
+ a >> b
+ }
+ else {
+ a >> b
+ }
+ }
+
+ fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): check whether behavior is an arithmetic shift for >> .
+ // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+ let a_type = a.get_type();
+ let b_type = b.get_type();
+ if a_type.is_unsigned(self) && b_type.is_signed(self) {
+ let a = self.context.new_cast(None, a, b_type);
+ let result = a >> b;
+ self.context.new_cast(None, result, a_type)
+ }
+ else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+ let b = self.context.new_cast(None, b, a_type);
+ a >> b
+ }
+ else {
+ a >> b
+ }
+ }
+
+ fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+ // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
+ // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
+ if a.get_type() != b.get_type() {
+ b = self.context.new_cast(None, b, a.get_type());
+ }
+ let res = self.current_func().new_local(None, b.get_type(), "andResult");
+ self.llbb().add_assignment(None, res, a & b);
+ res.to_rvalue()
+ }
+
+ fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
+ // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
+ let res = self.current_func().new_local(None, b.get_type(), "orResult");
+ self.llbb().add_assignment(None, res, a | b);
+ res.to_rvalue()
+ }
+
+ fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a ^ b
+ }
+
+ fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): use new_unary_op()?
+ self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a
+ }
+
+ fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+ self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
+ }
+
+ fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+ let operation =
+ if a.get_type().is_bool() {
+ UnaryOp::LogicalNegate
+ }
+ else {
+ UnaryOp::BitwiseNegate
+ };
+ self.cx.context.new_unary_op(None, operation, a.get_type(), a)
+ }
+
+ fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a + b
+ }
+
+ fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a + b
+ }
+
+ fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a - b
+ }
+
+ fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): should generate poison value?
+ a - b
+ }
+
+ fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a * b
+ }
+
+ fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+ a * b
+ }
+
+ fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
+ use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*};
+
+ let new_kind =
+ match typ.kind() {
+ Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
+ Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
+ t @ (Uint(_) | Int(_)) => t.clone(),
+ _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
+ };
+
+ // TODO(antoyo): remove duplication with intrinsic?
+ let name =
+ match oop {
+ OverflowOp::Add =>
+ match new_kind {
+ Int(I8) => "__builtin_add_overflow",
+ Int(I16) => "__builtin_add_overflow",
+ Int(I32) => "__builtin_sadd_overflow",
+ Int(I64) => "__builtin_saddll_overflow",
+ Int(I128) => "__builtin_add_overflow",
+
+ Uint(U8) => "__builtin_add_overflow",
+ Uint(U16) => "__builtin_add_overflow",
+ Uint(U32) => "__builtin_uadd_overflow",
+ Uint(U64) => "__builtin_uaddll_overflow",
+ Uint(U128) => "__builtin_add_overflow",
+
+ _ => unreachable!(),
+ },
+ OverflowOp::Sub =>
+ match new_kind {
+ Int(I8) => "__builtin_sub_overflow",
+ Int(I16) => "__builtin_sub_overflow",
+ Int(I32) => "__builtin_ssub_overflow",
+ Int(I64) => "__builtin_ssubll_overflow",
+ Int(I128) => "__builtin_sub_overflow",
+
+ Uint(U8) => "__builtin_sub_overflow",
+ Uint(U16) => "__builtin_sub_overflow",
+ Uint(U32) => "__builtin_usub_overflow",
+ Uint(U64) => "__builtin_usubll_overflow",
+ Uint(U128) => "__builtin_sub_overflow",
+
+ _ => unreachable!(),
+ },
+ OverflowOp::Mul =>
+ match new_kind {
+ Int(I8) => "__builtin_mul_overflow",
+ Int(I16) => "__builtin_mul_overflow",
+ Int(I32) => "__builtin_smul_overflow",
+ Int(I64) => "__builtin_smulll_overflow",
+ Int(I128) => "__builtin_mul_overflow",
+
+ Uint(U8) => "__builtin_mul_overflow",
+ Uint(U16) => "__builtin_mul_overflow",
+ Uint(U32) => "__builtin_umul_overflow",
+ Uint(U64) => "__builtin_umulll_overflow",
+ Uint(U128) => "__builtin_mul_overflow",
+
+ _ => unreachable!(),
+ },
+ };
+
+ let intrinsic = self.context.get_builtin_function(&name);
+ let res = self.current_func()
+ // TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
+ .new_local(None, rhs.get_type(), "binopResult")
+ .get_address(None);
+ let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
+ (res.dereference(None).to_rvalue(), overflow)
+ }
+
+ fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> {
+ // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
+ // Ideally, we shouldn't need to do this check.
+ let aligned_type =
+ if ty == self.cx.u128_type || ty == self.cx.i128_type {
+ ty
+ }
+ else {
+ ty.get_aligned(align.bytes())
+ };
+ // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial.
+ self.stack_var_count.set(self.stack_var_count.get() + 1);
+ self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None)
+ }
+
+ fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+ // TODO(antoyo): use ty.
+ let block = self.llbb();
+ let function = block.get_function();
+ // NOTE: instead of returning the dereference here, we have to assign it to a variable in
+ // the current basic block. Otherwise, it could be used in another basic block, causing a
+ // dereference after a drop, for instance.
+ // TODO(antoyo): handle align.
+ let deref = ptr.dereference(None).to_rvalue();
+ let value_type = deref.get_type();
+ unsafe { RETURN_VALUE_COUNT += 1 };
+ let loaded_value = function.new_local(None, value_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }));
+ block.add_assignment(None, loaded_value, deref);
+ loaded_value.to_rvalue()
+ }
+
+ fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): use ty.
+ let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile());
+ ptr.dereference(None).to_rvalue()
+ }
+
+ fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> {
+ // TODO(antoyo): use ty.
+ // TODO(antoyo): handle alignment.
+ let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes()));
+ let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+
+ let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+ let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
+ self.context.new_call(None, atomic_load, &[ptr, ordering])
+ }
+
+ fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> {
+ assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
+
+ if place.layout.is_zst() {
+ return OperandRef::new_zst(self, place.layout);
+ }
+
+ fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) {
+ let vr = scalar.valid_range.clone();
+ match scalar.value {
+ abi::Int(..) => {
+ if !scalar.is_always_valid(bx) {
+ bx.range_metadata(load, scalar.valid_range);
+ }
+ }
+ abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
+ bx.nonnull_metadata(load);
+ }
+ _ => {}
+ }
+ }
+
+ let val =
+ if let Some(llextra) = place.llextra {
+ OperandValue::Ref(place.llval, Some(llextra), place.align)
+ }
+ else if place.layout.is_gcc_immediate() {
+ let load = self.load(place.llval.get_type(), place.llval, place.align);
+ if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
+ scalar_load_metadata(self, load, scalar);
+ }
+ OperandValue::Immediate(self.to_immediate(load, place.layout))
+ }
+ else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
+ let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
+ let pair_type = place.layout.gcc_type(self, false);
+
+ let mut load = |i, scalar: &abi::Scalar, align| {
+ let llptr = self.struct_gep(pair_type, place.llval, i as u64);
+ let load = self.load(llptr.get_type(), llptr, align);
+ scalar_load_metadata(self, load, scalar);
+ if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
+ };
+
+ OperandValue::Pair(
+ load(0, a, place.align),
+ load(1, b, place.align.restrict_for_offset(b_offset)),
+ )
+ }
+ else {
+ OperandValue::Ref(place.llval, None, place.align)
+ };
+
+ OperandRef { val, layout: place.layout }
+ }
+
+ fn write_operand_repeatedly(mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) -> Self {
+ let zero = self.const_usize(0);
+ let count = self.const_usize(count);
+ let start = dest.project_index(&mut self, zero).llval;
+ let end = dest.project_index(&mut self, count).llval;
+
+ let mut header_bx = self.build_sibling_block("repeat_loop_header");
+ let mut body_bx = self.build_sibling_block("repeat_loop_body");
+ let next_bx = self.build_sibling_block("repeat_loop_next");
+
+ let ptr_type = start.get_type();
+ let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var");
+ let current_val = current.to_rvalue();
+ self.assign(current, start);
+
+ self.br(header_bx.llbb());
+
+ let keep_going = header_bx.icmp(IntPredicate::IntNE, current_val, end);
+ header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
+
+ let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
+ cg_elem.val.store(&mut body_bx, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
+
+ let next = body_bx.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]);
+ body_bx.llbb().add_assignment(None, current, next);
+ body_bx.br(header_bx.llbb());
+
+ next_bx
+ }
+
+ fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) {
+ // TODO(antoyo)
+ }
+
+ fn nonnull_metadata(&mut self, _load: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
+ self.store_with_flags(val, ptr, align, MemFlags::empty())
+ }
+
+ fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, _align: Align, _flags: MemFlags) -> RValue<'gcc> {
+ let ptr = self.check_store(val, ptr);
+ self.llbb().add_assignment(None, ptr.dereference(None), val);
+ // TODO(antoyo): handle align and flags.
+ // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
+ self.cx.context.new_rvalue_zero(self.type_i32())
+ }
+
+ fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) {
+ // TODO(antoyo): handle alignment.
+ let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes()));
+ let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+ let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+ let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
+
+ // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because
+ // the following cast is required to avoid this error:
+ // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int __attribute__((aligned(4))))
+ let int_type = atomic_store.get_param(1).to_rvalue().get_type();
+ let value = self.context.new_cast(None, value, int_type);
+ self.llbb()
+ .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering]));
+ }
+
+ fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+ let mut result = ptr;
+ for index in indices {
+ result = self.context.new_array_access(None, result, *index).get_address(None).to_rvalue();
+ }
+ result
+ }
+
+ fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+ // FIXME(antoyo): would be safer if doing the same thing (loop) as gep.
+ // TODO(antoyo): specify inbounds somehow.
+ match indices.len() {
+ 1 => {
+ self.context.new_array_access(None, ptr, indices[0]).get_address(None)
+ },
+ 2 => {
+ let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0?
+ self.context.new_array_access(None, array, indices[1]).get_address(None)
+ },
+ _ => unimplemented!(),
+ }
+ }
+
+ fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+ // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+ assert_eq!(idx as usize as u64, idx);
+ let value = ptr.dereference(None).to_rvalue();
+
+ if value_type.is_array().is_some() {
+ let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+ let element = self.context.new_array_access(None, value, index);
+ element.get_address(None)
+ }
+ else if let Some(vector_type) = value_type.is_vector() {
+ let array_type = vector_type.get_element_type().make_pointer();
+ let array = self.bitcast(ptr, array_type);
+ let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+ let element = self.context.new_array_access(None, array, index);
+ element.get_address(None)
+ }
+ else if let Some(struct_type) = value_type.is_struct() {
+ ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None)
+ }
+ else {
+ panic!("Unexpected type {:?}", value_type);
+ }
+ }
+
+ /* Casts */
+ fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): check that it indeed truncate the value.
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): check that it indeed sign extend the value.
+ if dest_ty.is_vector().is_some() {
+ // TODO(antoyo): nothing to do as it is only for LLVM?
+ return value;
+ }
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): make sure it truncates.
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.context.new_cast(None, value, dest_ty)
+ }
+
+ fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.cx.ptrtoint(self.block.expect("block"), value, dest_ty)
+ }
+
+ fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.cx.inttoptr(self.block.expect("block"), value, dest_ty)
+ }
+
+ fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.cx.const_bitcast(value, dest_ty)
+ }
+
+ fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> {
+ // NOTE: is_signed is for value, not dest_typ.
+ self.cx.context.new_cast(None, value, dest_typ)
+ }
+
+ fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ let val_type = value.get_type();
+ match (type_is_pointer(val_type), type_is_pointer(dest_ty)) {
+ (false, true) => {
+ // NOTE: Projecting a field of a pointer type will attemp a cast from a signed char to
+ // a pointer, which is not supported by gccjit.
+ return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty);
+ },
+ (false, false) => {
+ // When they are not pointers, we want a transmute (or reinterpret_cast).
+ self.bitcast(value, dest_ty)
+ },
+ (true, true) => self.cx.context.new_cast(None, value, dest_ty),
+ (true, false) => unimplemented!(),
+ }
+ }
+
+ /* Comparisons */
+ fn icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
+ let left_type = lhs.get_type();
+ let right_type = rhs.get_type();
+ if left_type != right_type {
+ // NOTE: because libgccjit cannot compare function pointers.
+ if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() {
+ lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
+ rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
+ }
+ // NOTE: hack because we try to cast a vector type to the same vector type.
+ else if format!("{:?}", left_type) != format!("{:?}", right_type) {
+ rhs = self.context.new_cast(None, rhs, left_type);
+ }
+ }
+ self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
+ }
+
+ fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
+ self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
+ }
+
+ /* Miscellaneous instructions */
+ fn memcpy(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) {
+ if flags.contains(MemFlags::NONTEMPORAL) {
+ // HACK(nox): This is inefficient but there is no nontemporal memcpy.
+ let val = self.load(src.get_type(), src, src_align);
+ let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
+ self.store_with_flags(val, ptr, dst_align, flags);
+ return;
+ }
+ let size = self.intcast(size, self.type_size_t(), false);
+ let _is_volatile = flags.contains(MemFlags::VOLATILE);
+ let dst = self.pointercast(dst, self.type_i8p());
+ let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
+ let memcpy = self.context.get_builtin_function("memcpy");
+ let block = self.block.expect("block");
+ // TODO(antoyo): handle aligns and is_volatile.
+ block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size]));
+ }
+
+ fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) {
+ if flags.contains(MemFlags::NONTEMPORAL) {
+ // HACK(nox): This is inefficient but there is no nontemporal memmove.
+ let val = self.load(src.get_type(), src, src_align);
+ let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
+ self.store_with_flags(val, ptr, dst_align, flags);
+ return;
+ }
+ let size = self.intcast(size, self.type_size_t(), false);
+ let _is_volatile = flags.contains(MemFlags::VOLATILE);
+ let dst = self.pointercast(dst, self.type_i8p());
+ let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
+
+ let memmove = self.context.get_builtin_function("memmove");
+ let block = self.block.expect("block");
+ // TODO(antoyo): handle is_volatile.
+ block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size]));
+ }
+
+ fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) {
+ let _is_volatile = flags.contains(MemFlags::VOLATILE);
+ let ptr = self.pointercast(ptr, self.type_i8p());
+ let memset = self.context.get_builtin_function("memset");
+ let block = self.block.expect("block");
+ // TODO(antoyo): handle align and is_volatile.
+ let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type);
+ let size = self.intcast(size, self.type_size_t(), false);
+ block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size]));
+ }
+
+ fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> {
+ let func = self.current_func();
+ let variable = func.new_local(None, then_val.get_type(), "selectVar");
+ let then_block = func.new_block("then");
+ let else_block = func.new_block("else");
+ let after_block = func.new_block("after");
+ self.llbb().end_with_conditional(None, cond, then_block, else_block);
+
+ then_block.add_assignment(None, variable, then_val);
+ then_block.end_with_jump(None, after_block);
+
+ if then_val.get_type() != else_val.get_type() {
+ else_val = self.context.new_cast(None, else_val, then_val.get_type());
+ }
+ else_block.add_assignment(None, variable, else_val);
+ else_block.end_with_jump(None, after_block);
+
+ // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+ // state need to be updated.
+ self.block = Some(after_block);
+ *self.cx.current_block.borrow_mut() = Some(after_block);
+
+ variable.to_rvalue()
+ }
+
+ #[allow(dead_code)]
+ fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn extract_value(&mut self, aggregate_value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+ // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+ assert_eq!(idx as usize as u64, idx);
+ let value_type = aggregate_value.get_type();
+
+ if value_type.is_array().is_some() {
+ let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+ let element = self.context.new_array_access(None, aggregate_value, index);
+ element.get_address(None)
+ }
+ else if value_type.is_vector().is_some() {
+ panic!();
+ }
+ else if let Some(pointer_type) = value_type.get_pointee() {
+ if let Some(struct_type) = pointer_type.is_struct() {
+ // NOTE: hack to workaround a limitation of the rustc API: see comment on
+ // CodegenCx.structs_as_pointer
+ aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue()
+ }
+ else {
+ panic!("Unexpected type {:?}", value_type);
+ }
+ }
+ else if let Some(struct_type) = value_type.is_struct() {
+ aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue()
+ }
+ else {
+ panic!("Unexpected type {:?}", value_type);
+ }
+ }
+
+ fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+ // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+ assert_eq!(idx as usize as u64, idx);
+ let value_type = aggregate_value.get_type();
+
+ let lvalue =
+ if value_type.is_array().is_some() {
+ let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+ self.context.new_array_access(None, aggregate_value, index)
+ }
+ else if value_type.is_vector().is_some() {
+ panic!();
+ }
+ else if let Some(pointer_type) = value_type.get_pointee() {
+ if let Some(struct_type) = pointer_type.is_struct() {
+ // NOTE: hack to workaround a limitation of the rustc API: see comment on
+ // CodegenCx.structs_as_pointer
+ aggregate_value.dereference_field(None, struct_type.get_field(idx as i32))
+ }
+ else {
+ panic!("Unexpected type {:?}", value_type);
+ }
+ }
+ else {
+ panic!("Unexpected type {:?}", value_type);
+ };
+
+ let lvalue_type = lvalue.to_rvalue().get_type();
+ let value =
+ // NOTE: sometimes, rustc will create a value with the wrong type.
+ if lvalue_type != value.get_type() {
+ self.context.new_cast(None, value, lvalue_type)
+ }
+ else {
+ value
+ };
+
+ self.llbb().add_assignment(None, lvalue, value);
+
+ aggregate_value
+ }
+
+ fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> {
+ let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1");
+ let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
+ let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
+ self.current_func().new_local(None, struct_type.as_type(), "landing_pad")
+ .to_rvalue()
+ // TODO(antoyo): Properly implement unwinding.
+ // the above is just to make the compilation work as it seems
+ // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
+ }
+
+ fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn cleanup_pad(&mut self, _parent: Option<RValue<'gcc>>, _args: &[RValue<'gcc>]) -> Funclet {
+ unimplemented!();
+ }
+
+ fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn catch_pad(&mut self, _parent: RValue<'gcc>, _args: &[RValue<'gcc>]) -> Funclet {
+ unimplemented!();
+ }
+
+ fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) {
+ unimplemented!();
+ }
+
+ fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ // Atomic Operations
+ fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+ let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
+ self.llbb().add_assignment(None, expected, cmp);
+ let success = self.compare_exchange(dst, expected, src, order, failure_order, weak);
+
+ let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
+ let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
+ let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align.
+
+ let value_type = result.to_rvalue().get_type();
+ if let Some(struct_type) = value_type.is_struct() {
+ self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align);
+ // NOTE: since success contains the call to the intrinsic, it must be stored before
+ // expected so that we store expected after the call.
+ self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
+ }
+ // TODO(antoyo): handle when value is not a struct.
+
+ result.to_rvalue()
+ }
+
+ fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
+ let size = self.cx.int_width(src.get_type()) / 8;
+ let name =
+ match op {
+ AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size),
+ AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size),
+ AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size),
+ AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size),
+ AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size),
+ AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size),
+ AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size),
+ AtomicRmwBinOp::AtomicMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order),
+ AtomicRmwBinOp::AtomicMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order),
+ AtomicRmwBinOp::AtomicUMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order),
+ AtomicRmwBinOp::AtomicUMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order),
+ };
+
+
+ let atomic_function = self.context.get_builtin_function(name);
+ let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+
+ let void_ptr_type = self.context.new_type::<*mut ()>();
+ let volatile_void_ptr_type = void_ptr_type.make_volatile();
+ let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
+ // FIXME(antoyo): not sure why, but we have the wrong type here.
+ let new_src_type = atomic_function.get_param(1).to_rvalue().get_type();
+ let src = self.context.new_cast(None, src, new_src_type);
+ let res = self.context.new_call(None, atomic_function, &[dst, src, order]);
+ self.context.new_cast(None, res, src.get_type())
+ }
+
+ fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) {
+ let name =
+ match scope {
+ SynchronizationScope::SingleThread => "__atomic_signal_fence",
+ SynchronizationScope::CrossThread => "__atomic_thread_fence",
+ };
+ let thread_fence = self.context.get_builtin_function(name);
+ let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+ self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order]));
+ }
+
+ fn set_invariant_load(&mut self, load: RValue<'gcc>) {
+ // NOTE: Hack to consider vtable function pointer as non-global-variable function pointer.
+ self.normal_function_addresses.borrow_mut().insert(load);
+ // TODO(antoyo)
+ }
+
+ fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) {
+ // TODO(antoyo)
+ }
+
+ fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) {
+ // TODO(antoyo)
+ }
+
+ fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> {
+ // FIXME(antoyo): remove when having a proper API.
+ let gcc_func = unsafe { std::mem::transmute(func) };
+ if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+ self.function_call(func, args, funclet)
+ }
+ else {
+ // If it's a not function that was defined, it's a function pointer.
+ self.function_ptr_call(func, args, funclet)
+ }
+ }
+
+ fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
+ // FIXME(antoyo): this does not zero-extend.
+ if value.get_type().is_bool() && dest_typ.is_i8(&self.cx) {
+ // FIXME(antoyo): hack because base::from_immediate converts i1 to i8.
+ // Fix the code in codegen_ssa::base::from_immediate.
+ return value;
+ }
+ self.context.new_cast(None, value, dest_typ)
+ }
+
+ fn cx(&self) -> &CodegenCx<'gcc, 'tcx> {
+ self.cx
+ }
+
+ fn do_not_inline(&mut self, _llret: RValue<'gcc>) {
+ unimplemented!();
+ }
+
+ fn set_span(&mut self, _span: Span) {}
+
+ fn from_immediate(&mut self, val: Self::Value) -> Self::Value {
+ if self.cx().val_ty(val) == self.cx().type_i1() {
+ self.zext(val, self.cx().type_i8())
+ }
+ else {
+ val
+ }
+ }
+
+ fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value {
+ if scalar.is_bool() {
+ return self.trunc(val, self.cx().type_i1());
+ }
+ val
+ }
+
+ fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
+ None
+ }
+
+ fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
+ None
+ }
+
+ fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) {
+ unimplemented!();
+ }
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+ pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
+ let return_type = v1.get_type();
+ let params = [
+ self.context.new_parameter(None, return_type, "v1"),
+ self.context.new_parameter(None, return_type, "v2"),
+ self.context.new_parameter(None, mask.get_type(), "mask"),
+ ];
+ let shuffle = self.context.new_function(None, FunctionType::Extern, return_type, ¶ms, "_mm_shuffle_epi8", false);
+ self.context.new_call(None, shuffle, &[v1, v2, mask])
+ }
+}
+
+impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> {
+ fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> {
+ // Forward to the `get_static` method of `CodegenCx`
+ self.cx().get_static(def_id).get_address(None)
+ }
+}
+
+impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
+ fn param_env(&self) -> ParamEnv<'tcx> {
+ self.cx.param_env()
+ }
+}
+
+impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.cx.target_spec()
+ }
+}
+
+trait ToGccComp {
+ fn to_gcc_comparison(&self) -> ComparisonOp;
+}
+
+impl ToGccComp for IntPredicate {
+ fn to_gcc_comparison(&self) -> ComparisonOp {
+ match *self {
+ IntPredicate::IntEQ => ComparisonOp::Equals,
+ IntPredicate::IntNE => ComparisonOp::NotEquals,
+ IntPredicate::IntUGT => ComparisonOp::GreaterThan,
+ IntPredicate::IntUGE => ComparisonOp::GreaterThanEquals,
+ IntPredicate::IntULT => ComparisonOp::LessThan,
+ IntPredicate::IntULE => ComparisonOp::LessThanEquals,
+ IntPredicate::IntSGT => ComparisonOp::GreaterThan,
+ IntPredicate::IntSGE => ComparisonOp::GreaterThanEquals,
+ IntPredicate::IntSLT => ComparisonOp::LessThan,
+ IntPredicate::IntSLE => ComparisonOp::LessThanEquals,
+ }
+ }
+}
+
+impl ToGccComp for RealPredicate {
+ fn to_gcc_comparison(&self) -> ComparisonOp {
+ // TODO(antoyo): check that ordered vs non-ordered is respected.
+ match *self {
+ RealPredicate::RealPredicateFalse => unreachable!(),
+ RealPredicate::RealOEQ => ComparisonOp::Equals,
+ RealPredicate::RealOGT => ComparisonOp::GreaterThan,
+ RealPredicate::RealOGE => ComparisonOp::GreaterThanEquals,
+ RealPredicate::RealOLT => ComparisonOp::LessThan,
+ RealPredicate::RealOLE => ComparisonOp::LessThanEquals,
+ RealPredicate::RealONE => ComparisonOp::NotEquals,
+ RealPredicate::RealORD => unreachable!(),
+ RealPredicate::RealUNO => unreachable!(),
+ RealPredicate::RealUEQ => ComparisonOp::Equals,
+ RealPredicate::RealUGT => ComparisonOp::GreaterThan,
+ RealPredicate::RealUGE => ComparisonOp::GreaterThan,
+ RealPredicate::RealULT => ComparisonOp::LessThan,
+ RealPredicate::RealULE => ComparisonOp::LessThan,
+ RealPredicate::RealUNE => ComparisonOp::NotEquals,
+ RealPredicate::RealPredicateTrue => unreachable!(),
+ }
+ }
+}
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+enum MemOrdering {
+ __ATOMIC_RELAXED,
+ __ATOMIC_CONSUME,
+ __ATOMIC_ACQUIRE,
+ __ATOMIC_RELEASE,
+ __ATOMIC_ACQ_REL,
+ __ATOMIC_SEQ_CST,
+}
+
+trait ToGccOrdering {
+ fn to_gcc(self) -> i32;
+}
+
+impl ToGccOrdering for AtomicOrdering {
+ fn to_gcc(self) -> i32 {
+ use MemOrdering::*;
+
+ let ordering =
+ match self {
+ AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
+ AtomicOrdering::Unordered => __ATOMIC_RELAXED,
+ AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
+ AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
+ AtomicOrdering::Release => __ATOMIC_RELEASE,
+ AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL,
+ AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST,
+ };
+ ordering as i32
+ }
+}
--- /dev/null
+use gccjit::{FunctionType, RValue};
+use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+
+use crate::abi::FnAbiGccExt;
+use crate::context::CodegenCx;
+
+/// Codegens a reference to a fn/method item, monomorphizing and
+/// inlining as it goes.
+///
+/// # Parameters
+///
+/// - `cx`: the crate context
+/// - `instance`: the instance to be instantiated
+pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> {
+ let tcx = cx.tcx();
+
+ assert!(!instance.substs.needs_infer());
+ assert!(!instance.substs.has_escaping_bound_vars());
+
+ if let Some(&func) = cx.function_instances.borrow().get(&instance) {
+ return func;
+ }
+
+ let sym = tcx.symbol_name(instance).name;
+
+ let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
+
+ let func =
+ if let Some(func) = cx.get_declared_value(&sym) {
+ // Create a fn pointer with the new signature.
+ let ptrty = fn_abi.ptr_to_gcc_type(cx);
+
+ // This is subtle and surprising, but sometimes we have to bitcast
+ // the resulting fn pointer. The reason has to do with external
+ // functions. If you have two crates that both bind the same C
+ // library, they may not use precisely the same types: for
+ // example, they will probably each declare their own structs,
+ // which are distinct types from LLVM's point of view (nominal
+ // types).
+ //
+ // Now, if those two crates are linked into an application, and
+ // they contain inlined code, you can wind up with a situation
+ // where both of those functions wind up being loaded into this
+ // application simultaneously. In that case, the same function
+ // (from LLVM's point of view) requires two types. But of course
+ // LLVM won't allow one function to have two types.
+ //
+ // What we currently do, therefore, is declare the function with
+ // one of the two types (whichever happens to come first) and then
+ // bitcast as needed when the function is referenced to make sure
+ // it has the type we expect.
+ //
+ // This can occur on either a crate-local or crate-external
+ // reference. It also occurs when testing libcore and in some
+ // other weird situations. Annoying.
+ if cx.val_ty(func) != ptrty {
+ // TODO(antoyo): cast the pointer.
+ func
+ }
+ else {
+ func
+ }
+ }
+ else {
+ cx.linkage.set(FunctionType::Extern);
+ let func = cx.declare_fn(&sym, &fn_abi);
+
+ // TODO(antoyo): set linkage and attributes.
+ func
+ };
+
+ cx.function_instances.borrow_mut().insert(instance, func);
+
+ func
+}
--- /dev/null
+use std::convert::TryFrom;
+use std::convert::TryInto;
+
+use gccjit::LValue;
+use gccjit::{Block, CType, RValue, Type, ToRValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{
+ BaseTypeMethods,
+ ConstMethods,
+ DerivedTypeMethods,
+ MiscMethods,
+ StaticMethods,
+};
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty::ScalarInt;
+use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
+use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_span::Symbol;
+use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
+
+use crate::consts::const_alloc_to_gcc;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> {
+ bytes_in_context(self, bytes)
+ }
+
+ fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> {
+ // TODO(antoyo): handle null_terminated.
+ if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) {
+ return value;
+ }
+
+ let global = self.global_string(&*symbol.as_str());
+
+ self.const_cstr_cache.borrow_mut().insert(symbol, global);
+ global
+ }
+
+ fn global_string(&self, string: &str) -> LValue<'gcc> {
+ // TODO(antoyo): handle non-null-terminated strings.
+ let string = self.context.new_string_literal(&*string);
+ let sym = self.generate_local_symbol_name("str");
+ let global = self.declare_private_global(&sym, self.val_ty(string));
+ global.global_set_initializer_value(string);
+ global
+ // TODO(antoyo): set linkage.
+ }
+
+ pub fn inttoptr(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ let func = block.get_function();
+ let local = func.new_local(None, value.get_type(), "intLocal");
+ block.add_assignment(None, local, value);
+ let value_address = local.get_address(None);
+
+ let ptr = self.context.new_cast(None, value_address, dest_ty.make_pointer());
+ ptr.dereference(None).to_rvalue()
+ }
+
+ pub fn ptrtoint(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): when libgccjit allow casting from pointer to int, remove this.
+ let func = block.get_function();
+ let local = func.new_local(None, value.get_type(), "ptrLocal");
+ block.add_assignment(None, local, value);
+ let ptr_address = local.get_address(None);
+
+ let ptr = self.context.new_cast(None, ptr_address, dest_ty.make_pointer());
+ ptr.dereference(None).to_rvalue()
+ }
+}
+
+pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
+ let context = &cx.context;
+ let byte_type = context.new_type::<u8>();
+ let typ = context.new_array_type(None, byte_type, bytes.len() as i32);
+ let elements: Vec<_> =
+ bytes.iter()
+ .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
+ .collect();
+ context.new_rvalue_from_array(None, typ, &elements)
+}
+
+pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool {
+ typ.get_pointee().is_some()
+}
+
+impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
+ if type_is_pointer(typ) {
+ self.context.new_null(typ)
+ }
+ else {
+ self.const_int(typ, 0)
+ }
+ }
+
+ fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
+ let local = self.current_func.borrow().expect("func")
+ .new_local(None, typ, "undefined");
+ if typ.is_struct().is_some() {
+ // NOTE: hack to workaround a limitation of the rustc API: see comment on
+ // CodegenCx.structs_as_pointer
+ let pointer = local.get_address(None);
+ self.structs_as_pointer.borrow_mut().insert(pointer);
+ pointer
+ }
+ else {
+ local.to_rvalue()
+ }
+ }
+
+ fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
+ self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from"))
+ }
+
+ fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
+ self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64)
+ }
+
+ fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
+ let num64: Result<i64, _> = num.try_into();
+ if let Ok(num) = num64 {
+ // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant.
+ // The operations >> 64 and | low are making the normal case a non-constant.
+ return self.context.new_rvalue_from_long(typ, num as i64);
+ }
+
+ if num >> 64 != 0 {
+ // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
+ let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
+ let high = self.context.new_rvalue_from_long(typ, (num >> 64) as u64 as i64);
+
+ let sixty_four = self.context.new_rvalue_from_long(typ, 64);
+ (high << sixty_four) | self.context.new_cast(None, low, typ)
+ }
+ else if typ.is_i128(self) {
+ let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
+ self.context.new_cast(None, num, typ)
+ }
+ else {
+ self.context.new_rvalue_from_long(typ, num as u64 as i64)
+ }
+ }
+
+ fn const_bool(&self, val: bool) -> RValue<'gcc> {
+ self.const_uint(self.type_i1(), val as u64)
+ }
+
+ fn const_i32(&self, i: i32) -> RValue<'gcc> {
+ self.const_int(self.type_i32(), i as i64)
+ }
+
+ fn const_u32(&self, i: u32) -> RValue<'gcc> {
+ self.const_uint(self.type_u32(), i as u64)
+ }
+
+ fn const_u64(&self, i: u64) -> RValue<'gcc> {
+ self.const_uint(self.type_u64(), i)
+ }
+
+ fn const_usize(&self, i: u64) -> RValue<'gcc> {
+ let bit_size = self.data_layout().pointer_size.bits();
+ if bit_size < 64 {
+ // make sure it doesn't overflow
+ assert!(i < (1 << bit_size));
+ }
+
+ self.const_uint(self.usize_type, i)
+ }
+
+ fn const_u8(&self, _i: u8) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
+ let len = s.as_str().len();
+ let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None),
+ self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
+ );
+ (cs, self.const_usize(len as u64))
+ }
+
+ fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> {
+ let fields: Vec<_> = values.iter()
+ .map(|value| value.get_type())
+ .collect();
+ // TODO(antoyo): cache the type? It's anonymous, so probably not.
+ let typ = self.type_struct(&fields, packed);
+ let struct_type = typ.is_struct().expect("struct type");
+ self.context.new_rvalue_from_struct(None, struct_type, values)
+ }
+
+ fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
+ // TODO(antoyo)
+ None
+ }
+
+ fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option<u128> {
+ // TODO(antoyo)
+ None
+ }
+
+ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
+ let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
+ match cv {
+ Scalar::Int(ScalarInt::ZST) => {
+ assert_eq!(0, layout.value.size(self).bytes());
+ self.const_undef(self.type_ix(0))
+ }
+ Scalar::Int(int) => {
+ let data = int.assert_bits(layout.value.size(self));
+
+ // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
+ // the paths for floating-point values.
+ if ty == self.float_type {
+ return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
+ }
+ else if ty == self.double_type {
+ return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
+ }
+
+ let value = self.const_uint_big(self.type_ix(bitsize), data);
+ if layout.value == Pointer {
+ self.inttoptr(self.current_block.borrow().expect("block"), value, ty)
+ } else {
+ self.const_bitcast(value, ty)
+ }
+ }
+ Scalar::Ptr(ptr, _size) => {
+ let (alloc_id, offset) = ptr.into_parts();
+ let base_addr =
+ match self.tcx.global_alloc(alloc_id) {
+ GlobalAlloc::Memory(alloc) => {
+ let init = const_alloc_to_gcc(self, alloc);
+ let value =
+ match alloc.mutability {
+ Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
+ _ => self.static_addr_of(init, alloc.align, None),
+ };
+ if !self.sess().fewer_names() {
+ // TODO(antoyo): set value name.
+ }
+ value
+ },
+ GlobalAlloc::Function(fn_instance) => {
+ self.get_fn_addr(fn_instance)
+ },
+ GlobalAlloc::Static(def_id) => {
+ assert!(self.tcx.is_static(def_id));
+ self.get_static(def_id).get_address(None)
+ },
+ };
+ let ptr_type = base_addr.get_type();
+ let base_addr = self.const_bitcast(base_addr, self.usize_type);
+ let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
+ let ptr = self.const_bitcast(base_addr + offset, ptr_type);
+ if layout.value != Pointer {
+ self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
+ }
+ else {
+ self.const_bitcast(ptr, ty)
+ }
+ }
+ }
+ }
+
+ fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+ const_alloc_to_gcc(self, alloc)
+ }
+
+ fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
+ assert_eq!(alloc.align, layout.align.abi);
+ let ty = self.type_ptr_to(layout.gcc_type(self, true));
+ let value =
+ if layout.size == Size::ZERO {
+ let value = self.const_usize(alloc.align.bytes());
+ self.context.new_cast(None, value, ty)
+ }
+ else {
+ let init = const_alloc_to_gcc(self, alloc);
+ let base_addr = self.static_addr_of(init, alloc.align, None);
+
+ let array = self.const_bitcast(base_addr, self.type_i8p());
+ let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None);
+ self.const_bitcast(value, ty)
+ };
+ PlaceRef::new_sized(value, layout)
+ }
+
+ fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> {
+ self.context.new_cast(None, val, ty)
+ }
+}
+
+pub trait SignType<'gcc, 'tcx> {
+ fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+ fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+}
+
+impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
+ fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.is_i8(cx) || self.is_i16(cx) || self.is_i32(cx) || self.is_i64(cx) || self.is_i128(cx)
+ }
+
+ fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.is_u8(cx) || self.is_u16(cx) || self.is_u32(cx) || self.is_u64(cx) || self.is_u128(cx)
+ }
+
+ fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+ if self.is_u8(cx) {
+ cx.i8_type
+ }
+ else if self.is_u16(cx) {
+ cx.i16_type
+ }
+ else if self.is_u32(cx) {
+ cx.i32_type
+ }
+ else if self.is_u64(cx) {
+ cx.i64_type
+ }
+ else if self.is_u128(cx) {
+ cx.i128_type
+ }
+ else {
+ self.clone()
+ }
+ }
+
+ fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+ if self.is_i8(cx) {
+ cx.u8_type
+ }
+ else if self.is_i16(cx) {
+ cx.u16_type
+ }
+ else if self.is_i32(cx) {
+ cx.u32_type
+ }
+ else if self.is_i64(cx) {
+ cx.u64_type
+ }
+ else if self.is_i128(cx) {
+ cx.u128_type
+ }
+ else {
+ self.clone()
+ }
+ }
+}
+
+pub trait TypeReflection<'gcc, 'tcx> {
+ fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+
+ fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+
+ fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+ fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+}
+
+impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
+ fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.u8_type
+ }
+
+ fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.u16_type
+ }
+
+ fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.uint_type
+ }
+
+ fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.ulong_type
+ }
+
+ fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.ulonglong_type
+ }
+
+ fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.i8_type
+ }
+
+ fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.u8_type
+ }
+
+ fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.i16_type
+ }
+
+ fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.u16_type
+ }
+
+ fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.i32_type
+ }
+
+ fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.u32_type
+ }
+
+ fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.i64_type
+ }
+
+ fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.u64_type
+ }
+
+ fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.context.new_c_type(CType::Int128t)
+ }
+
+ fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.context.new_c_type(CType::UInt128t)
+ }
+
+ fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.context.new_type::<f32>()
+ }
+
+ fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+ self.unqualified() == cx.context.new_type::<f64>()
+ }
+}
--- /dev/null
+use gccjit::{LValue, RValue, ToRValue, Type};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods};
+use rustc_hir as hir;
+use rustc_hir::Node;
+use rustc_middle::{bug, span_bug};
+use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
+use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
+
+use crate::base;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
+ if value.get_type() == self.bool_type.make_pointer() {
+ if let Some(pointee) = typ.get_pointee() {
+ if pointee.is_vector().is_some() {
+ panic!()
+ }
+ }
+ }
+ self.context.new_bitcast(None, value, typ)
+ }
+}
+
+impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
+ fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
+ if let Some(global_value) = self.const_globals.borrow().get(&cv) {
+ // TODO(antoyo): upgrade alignment.
+ return *global_value;
+ }
+ let global_value = self.static_addr_of_mut(cv, align, kind);
+ // TODO(antoyo): set global constant.
+ self.const_globals.borrow_mut().insert(cv, global_value);
+ global_value
+ }
+
+ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
+ let attrs = self.tcx.codegen_fn_attrs(def_id);
+
+ let value =
+ match codegen_static_initializer(&self, def_id) {
+ Ok((value, _)) => value,
+ // Error has already been reported
+ Err(_) => return,
+ };
+
+ let global = self.get_static(def_id);
+
+ // boolean SSA values are i1, but they have to be stored in i8 slots,
+ // otherwise some LLVM optimization passes don't work as expected
+ let val_llty = self.val_ty(value);
+ let value =
+ if val_llty == self.type_i1() {
+ unimplemented!();
+ }
+ else {
+ value
+ };
+
+ let instance = Instance::mono(self.tcx, def_id);
+ let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+ let gcc_type = self.layout_of(ty).gcc_type(self, true);
+
+ // TODO(antoyo): set alignment.
+
+ let value =
+ if value.get_type() != gcc_type {
+ self.context.new_bitcast(None, value, gcc_type)
+ }
+ else {
+ value
+ };
+ global.global_set_initializer_value(value);
+
+ // As an optimization, all shared statics which do not have interior
+ // mutability are placed into read-only memory.
+ if !is_mutable {
+ if self.type_is_freeze(ty) {
+ // TODO(antoyo): set global constant.
+ }
+ }
+
+ if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+ // Do not allow LLVM to change the alignment of a TLS on macOS.
+ //
+ // By default a global's alignment can be freely increased.
+ // This allows LLVM to generate more performant instructions
+ // e.g., using load-aligned into a SIMD register.
+ //
+ // However, on macOS 10.10 or below, the dynamic linker does not
+ // respect any alignment given on the TLS (radar 24221680).
+ // This will violate the alignment assumption, and causing segfault at runtime.
+ //
+ // This bug is very easy to trigger. In `println!` and `panic!`,
+ // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
+ // which the values would be `mem::replace`d on initialization.
+ // The implementation of `mem::replace` will use SIMD
+ // whenever the size is 32 bytes or higher. LLVM notices SIMD is used
+ // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
+ // which macOS's dyld disregarded and causing crashes
+ // (see issues #51794, #51758, #50867, #48866 and #44056).
+ //
+ // To workaround the bug, we trick LLVM into not increasing
+ // the global's alignment by explicitly assigning a section to it
+ // (equivalent to automatically generating a `#[link_section]` attribute).
+ // See the comment in the `GlobalValue::canIncreaseAlignment()` function
+ // of `lib/IR/Globals.cpp` for why this works.
+ //
+ // When the alignment is not increased, the optimized `mem::replace`
+ // will use load-unaligned instructions instead, and thus avoiding the crash.
+ //
+ // We could remove this hack whenever we decide to drop macOS 10.10 support.
+ if self.tcx.sess.target.options.is_like_osx {
+ // The `inspect` method is okay here because we checked relocations, and
+ // because we are doing this access to inspect the final interpreter state
+ // (not as part of the interpreter execution).
+ //
+ // FIXME: This check requires that the (arbitrary) value of undefined bytes
+ // happens to be zero. Instead, we should only check the value of defined bytes
+ // and set all undefined bytes to zero if this allocation is headed for the
+ // BSS.
+ unimplemented!();
+ }
+ }
+
+ // Wasm statics with custom link sections get special treatment as they
+ // go into custom sections of the wasm executable.
+ if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+ if let Some(_section) = attrs.link_section {
+ unimplemented!();
+ }
+ } else {
+ // TODO(antoyo): set link section.
+ }
+
+ if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+ self.add_used_global(global.to_rvalue());
+ }
+ }
+
+ /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
+ fn add_used_global(&self, _global: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ fn add_compiler_used_global(&self, _global: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
+ let global =
+ match kind {
+ Some(kind) if !self.tcx.sess.fewer_names() => {
+ let name = self.generate_local_symbol_name(kind);
+ // TODO(antoyo): check if it's okay that TLS is off here.
+ // TODO(antoyo): check if it's okay that link_section is None here.
+ // TODO(antoyo): set alignment here as well.
+ let global = self.define_global(&name[..], self.val_ty(cv), false, None);
+ // TODO(antoyo): set linkage.
+ global
+ }
+ _ => {
+ let typ = self.val_ty(cv).get_aligned(align.bytes());
+ let global = self.declare_unnamed_global(typ);
+ global
+ },
+ };
+ // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used
+ // globally.
+ global.global_set_initializer_value(cv);
+ // TODO(antoyo): set unnamed address.
+ global.get_address(None)
+ }
+
+ pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
+ let instance = Instance::mono(self.tcx, def_id);
+ let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+ if let Some(&global) = self.instances.borrow().get(&instance) {
+ return global;
+ }
+
+ let defined_in_current_codegen_unit =
+ self.codegen_unit.items().contains_key(&MonoItem::Static(def_id));
+ assert!(
+ !defined_in_current_codegen_unit,
+ "consts::get_static() should always hit the cache for \
+ statics defined in the same CGU, but did not for `{:?}`",
+ def_id
+ );
+
+ let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+ let sym = self.tcx.symbol_name(instance).name;
+
+ let global =
+ if let Some(def_id) = def_id.as_local() {
+ let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+ let llty = self.layout_of(ty).gcc_type(self, true);
+ // FIXME: refactor this to work without accessing the HIR
+ let global = match self.tcx.hir().get(id) {
+ Node::Item(&hir::Item { span, kind: hir::ItemKind::Static(..), .. }) => {
+ if let Some(global) = self.get_declared_value(&sym) {
+ if self.val_ty(global) != self.type_ptr_to(llty) {
+ span_bug!(span, "Conflicting types for static");
+ }
+ }
+
+ let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+ let global = self.declare_global(&sym, llty, is_tls, fn_attrs.link_section);
+
+ if !self.tcx.is_reachable_non_generic(def_id) {
+ // TODO(antoyo): set visibility.
+ }
+
+ global
+ }
+
+ Node::ForeignItem(&hir::ForeignItem {
+ span,
+ kind: hir::ForeignItemKind::Static(..),
+ ..
+ }) => {
+ let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+ check_and_apply_linkage(&self, &fn_attrs, ty, sym, span)
+ }
+
+ item => bug!("get_static: expected static, found {:?}", item),
+ };
+
+ global
+ }
+ else {
+ // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
+ //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
+
+ let attrs = self.tcx.codegen_fn_attrs(def_id);
+ let span = self.tcx.def_span(def_id);
+ let global = check_and_apply_linkage(&self, &attrs, ty, sym, span);
+
+ let needs_dll_storage_attr = false; // TODO(antoyo)
+
+ // If this assertion triggers, there's something wrong with commandline
+ // argument validation.
+ debug_assert!(
+ !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
+ && self.tcx.sess.target.options.is_like_msvc
+ && self.tcx.sess.opts.cg.prefer_dynamic)
+ );
+
+ if needs_dll_storage_attr {
+ // This item is external but not foreign, i.e., it originates from an external Rust
+ // crate. Since we don't know whether this crate will be linked dynamically or
+ // statically in the final application, we always mark such symbols as 'dllimport'.
+ // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs
+ // to make things work.
+ //
+ // However, in some scenarios we defer emission of statics to downstream
+ // crates, so there are cases where a static with an upstream DefId
+ // is actually present in the current crate. We can find out via the
+ // is_codegened_item query.
+ if !self.tcx.is_codegened_item(def_id) {
+ unimplemented!();
+ }
+ }
+ global
+ };
+
+ // TODO(antoyo): set dll storage class.
+
+ self.instances.borrow_mut().insert(instance, global);
+ global
+ }
+}
+
+pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> {
+ let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
+ let dl = cx.data_layout();
+ let pointer_size = dl.pointer_size.bytes() as usize;
+
+ let mut next_offset = 0;
+ for &(offset, alloc_id) in alloc.relocations().iter() {
+ let offset = offset.bytes();
+ assert_eq!(offset as usize as u64, offset);
+ let offset = offset as usize;
+ if offset > next_offset {
+ // This `inspect` is okay since we have checked that it is not within a relocation, it
+ // is within the bounds of the allocation, and it doesn't affect interpreter execution
+ // (we inspect the result after interpreter execution). Any undef byte is replaced with
+ // some arbitrary byte value.
+ //
+ // FIXME: relay undef bytes to codegen as undef const bytes
+ let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
+ llvals.push(cx.const_bytes(bytes));
+ }
+ let ptr_offset =
+ read_target_uint( dl.endian,
+ // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
+ // affect interpreter execution (we inspect the result after interpreter execution),
+ // and we properly interpret the relocation as a relocation pointer offset.
+ alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
+ )
+ .expect("const_alloc_to_llvm: could not read relocation pointer")
+ as u64;
+ llvals.push(cx.scalar_to_backend(
+ InterpScalar::from_pointer(
+ interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
+ &cx.tcx,
+ ),
+ abi::Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
+ cx.type_i8p(),
+ ));
+ next_offset = offset + pointer_size;
+ }
+ if alloc.len() >= next_offset {
+ let range = next_offset..alloc.len();
+ // This `inspect` is okay since we have check that it is after all relocations, it is
+ // within the bounds of the allocation, and it doesn't affect interpreter execution (we
+ // inspect the result after interpreter execution). Any undef byte is replaced with some
+ // arbitrary byte value.
+ //
+ // FIXME: relay undef bytes to codegen as undef const bytes
+ let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
+ llvals.push(cx.const_bytes(bytes));
+ }
+
+ cx.const_struct(&llvals, true)
+}
+
+pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
+ let alloc = cx.tcx.eval_static_initializer(def_id)?;
+ Ok((const_alloc_to_gcc(cx, alloc), alloc))
+}
+
+fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> {
+ let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+ let llty = cx.layout_of(ty).gcc_type(cx, true);
+ if let Some(linkage) = attrs.linkage {
+ // If this is a static with a linkage specified, then we need to handle
+ // it a little specially. The typesystem prevents things like &T and
+ // extern "C" fn() from being non-null, so we can't just declare a
+ // static and call it a day. Some linkages (like weak) will make it such
+ // that the static actually has a null value.
+ let llty2 =
+ if let ty::RawPtr(ref mt) = ty.kind() {
+ cx.layout_of(mt.ty).gcc_type(cx, true)
+ }
+ else {
+ cx.sess().span_fatal(
+ span,
+ "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
+ )
+ };
+ // Declare a symbol `foo` with the desired linkage.
+ let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage));
+
+ // Declare an internal global `extern_with_linkage_foo` which
+ // is initialized with the address of `foo`. If `foo` is
+ // discarded during linking (for example, if `foo` has weak
+ // linkage and there are no definitions), then
+ // `extern_with_linkage_foo` will instead be initialized to
+ // zero.
+ let mut real_name = "_rust_extern_with_linkage_".to_string();
+ real_name.push_str(&sym);
+ let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section);
+ // TODO(antoyo): set linkage.
+ global2.global_set_initializer_value(global1.get_address(None));
+ // TODO(antoyo): use global_set_initializer() when it will work.
+ global2
+ }
+ else {
+ // Generate an external declaration.
+ // FIXME(nagisa): investigate whether it can be changed into define_global
+
+ // Thread-local statics in some other crate need to *always* be linked
+ // against in a thread-local fashion, so we need to be sure to apply the
+ // thread-local attribute locally if it was present remotely. If we
+ // don't do this then linker errors can be generated where the linker
+ // complains that one object files has a thread local version of the
+ // symbol and another one doesn't.
+ cx.declare_global(&sym, llty, is_tls, attrs.link_section)
+ }
+}
--- /dev/null
+use std::cell::{Cell, RefCell};
+
+use gccjit::{
+ Block,
+ Context,
+ CType,
+ Function,
+ FunctionType,
+ LValue,
+ RValue,
+ Struct,
+ Type,
+};
+use rustc_codegen_ssa::base::wants_msvc_seh;
+use rustc_codegen_ssa::traits::{
+ BackendTypes,
+ MiscMethods,
+};
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_middle::span_bug;
+use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
+use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
+
+use crate::callee::get_fn;
+use crate::declare::mangle_name;
+
+#[derive(Clone)]
+pub struct FuncSig<'gcc> {
+ pub params: Vec<Type<'gcc>>,
+ pub return_type: Type<'gcc>,
+}
+
+pub struct CodegenCx<'gcc, 'tcx> {
+ pub check_overflow: bool,
+ pub codegen_unit: &'tcx CodegenUnit<'tcx>,
+ pub context: &'gcc Context<'gcc>,
+
+ // TODO(antoyo): First set it to a dummy block to avoid using Option?
+ pub current_block: RefCell<Option<Block<'gcc>>>,
+ pub current_func: RefCell<Option<Function<'gcc>>>,
+ pub normal_function_addresses: RefCell<FxHashSet<RValue<'gcc>>>,
+
+ pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
+
+ pub tls_model: gccjit::TlsModel,
+
+ pub bool_type: Type<'gcc>,
+ pub i8_type: Type<'gcc>,
+ pub i16_type: Type<'gcc>,
+ pub i32_type: Type<'gcc>,
+ pub i64_type: Type<'gcc>,
+ pub i128_type: Type<'gcc>,
+ pub isize_type: Type<'gcc>,
+
+ pub u8_type: Type<'gcc>,
+ pub u16_type: Type<'gcc>,
+ pub u32_type: Type<'gcc>,
+ pub u64_type: Type<'gcc>,
+ pub u128_type: Type<'gcc>,
+ pub usize_type: Type<'gcc>,
+
+ pub int_type: Type<'gcc>,
+ pub uint_type: Type<'gcc>,
+ pub long_type: Type<'gcc>,
+ pub ulong_type: Type<'gcc>,
+ pub ulonglong_type: Type<'gcc>,
+ pub sizet_type: Type<'gcc>,
+
+ pub float_type: Type<'gcc>,
+ pub double_type: Type<'gcc>,
+
+ pub linkage: Cell<FunctionType>,
+ pub scalar_types: RefCell<FxHashMap<Ty<'tcx>, Type<'gcc>>>,
+ pub types: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), Type<'gcc>>>,
+ pub tcx: TyCtxt<'tcx>,
+
+ pub struct_types: RefCell<FxHashMap<Vec<Type<'gcc>>, Type<'gcc>>>,
+
+ pub types_with_fields_to_set: RefCell<FxHashMap<Type<'gcc>, (Struct<'gcc>, TyAndLayout<'tcx>)>>,
+
+ /// Cache instances of monomorphic and polymorphic items
+ pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
+ /// Cache function instances of monomorphic and polymorphic items
+ pub function_instances: RefCell<FxHashMap<Instance<'tcx>, RValue<'gcc>>>,
+ /// Cache generated vtables
+ pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
+
+ /// Cache of emitted const globals (value -> global)
+ pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
+
+ /// Cache of constant strings,
+ pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+
+ /// Cache of globals.
+ pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
+
+ /// A counter that is used for generating local symbol names
+ local_gen_sym_counter: Cell<usize>,
+ pub global_gen_sym_counter: Cell<usize>,
+
+ eh_personality: Cell<Option<RValue<'gcc>>>,
+
+ pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
+
+ /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
+ /// `const_undef()` returns struct as pointer so that they can later be assigned a value.
+ /// As such, this set remembers which of these pointers were returned by this function so that
+ /// they can be deferenced later.
+ /// FIXME(antoyo): fix the rustc API to avoid having this hack.
+ pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+ let check_overflow = tcx.sess.overflow_checks();
+ // TODO(antoyo): fix this mess. libgccjit seems to return random type when using new_int_type().
+ let isize_type = context.new_c_type(CType::LongLong);
+ let usize_type = context.new_c_type(CType::ULongLong);
+ let bool_type = context.new_type::<bool>();
+ let i8_type = context.new_type::<i8>();
+ let i16_type = context.new_type::<i16>();
+ let i32_type = context.new_type::<i32>();
+ let i64_type = context.new_c_type(CType::LongLong);
+ let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
+ let u8_type = context.new_type::<u8>();
+ let u16_type = context.new_type::<u16>();
+ let u32_type = context.new_type::<u32>();
+ let u64_type = context.new_c_type(CType::ULongLong);
+ let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
+
+ let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
+
+ let float_type = context.new_type::<f32>();
+ let double_type = context.new_type::<f64>();
+
+ let int_type = context.new_c_type(CType::Int);
+ let uint_type = context.new_c_type(CType::UInt);
+ let long_type = context.new_c_type(CType::Long);
+ let ulong_type = context.new_c_type(CType::ULong);
+ let ulonglong_type = context.new_c_type(CType::ULongLong);
+ let sizet_type = context.new_c_type(CType::SizeT);
+
+ assert_eq!(isize_type, i64_type);
+ assert_eq!(usize_type, u64_type);
+
+ let mut functions = FxHashMap::default();
+ let builtins = [
+ "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
+ "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
+ "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow",
+ "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow",
+ "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos",
+ "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf",
+ "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf",
+ "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round",
+ "__builtin_expect_with_probability",
+ ];
+
+ for builtin in builtins.iter() {
+ functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
+ }
+
+ Self {
+ check_overflow,
+ codegen_unit,
+ context,
+ current_block: RefCell::new(None),
+ current_func: RefCell::new(None),
+ normal_function_addresses: Default::default(),
+ functions: RefCell::new(functions),
+
+ tls_model,
+
+ bool_type,
+ i8_type,
+ i16_type,
+ i32_type,
+ i64_type,
+ i128_type,
+ isize_type,
+ usize_type,
+ u8_type,
+ u16_type,
+ u32_type,
+ u64_type,
+ u128_type,
+ int_type,
+ uint_type,
+ long_type,
+ ulong_type,
+ ulonglong_type,
+ sizet_type,
+
+ float_type,
+ double_type,
+
+ linkage: Cell::new(FunctionType::Internal),
+ instances: Default::default(),
+ function_instances: Default::default(),
+ vtables: Default::default(),
+ const_globals: Default::default(),
+ const_cstr_cache: Default::default(),
+ globals: Default::default(),
+ scalar_types: Default::default(),
+ types: Default::default(),
+ tcx,
+ struct_types: Default::default(),
+ types_with_fields_to_set: Default::default(),
+ local_gen_sym_counter: Cell::new(0),
+ global_gen_sym_counter: Cell::new(0),
+ eh_personality: Cell::new(None),
+ pointee_infos: Default::default(),
+ structs_as_pointer: Default::default(),
+ }
+ }
+
+ pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
+ let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
+ debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+ "{:?} ({:?}) is not a function", value, value.get_type());
+ function
+ }
+
+ pub fn sess(&self) -> &Session {
+ &self.tcx.sess
+ }
+}
+
+impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
+ type Value = RValue<'gcc>;
+ type Function = RValue<'gcc>;
+
+ type BasicBlock = Block<'gcc>;
+ type Type = Type<'gcc>;
+ type Funclet = (); // TODO(antoyo)
+
+ type DIScope = (); // TODO(antoyo)
+ type DILocation = (); // TODO(antoyo)
+ type DIVariable = (); // TODO(antoyo)
+}
+
+impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
+ &self.vtables
+ }
+
+ fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+ let func = get_fn(self, instance);
+ *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func));
+ func
+ }
+
+ fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+ let func = get_fn(self, instance);
+ let func = self.rvalue_as_function(func);
+ let ptr = func.get_address(None);
+
+ // TODO(antoyo): don't do this twice: i.e. in declare_fn and here.
+ // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI).
+
+ self.normal_function_addresses.borrow_mut().insert(ptr);
+
+ ptr
+ }
+
+ fn eh_personality(&self) -> RValue<'gcc> {
+ // The exception handling personality function.
+ //
+ // If our compilation unit has the `eh_personality` lang item somewhere
+ // within it, then we just need to codegen that. Otherwise, we're
+ // building an rlib which will depend on some upstream implementation of
+ // this function, so we just codegen a generic reference to it. We don't
+ // specify any of the types for the function, we just make it a symbol
+ // that LLVM can later use.
+ //
+ // Note that MSVC is a little special here in that we don't use the
+ // `eh_personality` lang item at all. Currently LLVM has support for
+ // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
+ // *name of the personality function* to decide what kind of unwind side
+ // tables/landing pads to emit. It looks like Dwarf is used by default,
+ // injecting a dependency on the `_Unwind_Resume` symbol for resuming
+ // an "exception", but for MSVC we want to force SEH. This means that we
+ // can't actually have the personality function be our standard
+ // `rust_eh_personality` function, but rather we wired it up to the
+ // CRT's custom personality function, which forces LLVM to consider
+ // landing pads as "landing pads for SEH".
+ if let Some(llpersonality) = self.eh_personality.get() {
+ return llpersonality;
+ }
+ let tcx = self.tcx;
+ let llfn = match tcx.lang_items().eh_personality() {
+ Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr(
+ ty::Instance::resolve(
+ tcx,
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ tcx.intern_substs(&[]),
+ )
+ .unwrap().unwrap(),
+ ),
+ _ => {
+ let _name = if wants_msvc_seh(self.sess()) {
+ "__CxxFrameHandler3"
+ } else {
+ "rust_eh_personality"
+ };
+ //let func = self.declare_func(name, self.type_i32(), &[], true);
+ // FIXME(antoyo): this hack should not be needed. That will probably be removed when
+ // unwinding support is added.
+ self.context.new_rvalue_from_int(self.int_type, 0)
+ }
+ };
+ // TODO(antoyo): apply target cpu attributes.
+ self.eh_personality.set(Some(llfn));
+ llfn
+ }
+
+ fn sess(&self) -> &Session {
+ &self.tcx.sess
+ }
+
+ fn check_overflow(&self) -> bool {
+ self.check_overflow
+ }
+
+ fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
+ self.codegen_unit
+ }
+
+ fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
+ unimplemented!();
+ }
+
+ fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
+ // TODO(antoyo)
+ }
+
+ fn create_used_variable(&self) {
+ unimplemented!();
+ }
+
+ fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
+ if self.get_declared_value("main").is_none() {
+ Some(self.declare_cfn("main", fn_type))
+ }
+ else {
+ // If the symbol already exists, it is an error: for example, the user wrote
+ // #[no_mangle] extern "C" fn main(..) {..}
+ // instead of #[start]
+ None
+ }
+ }
+
+ fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
+ unimplemented!()
+ }
+
+ fn create_compiler_used_variable(&self) {
+ unimplemented!()
+ }
+}
+
+impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
+
+impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.tcx.data_layout
+ }
+}
+
+impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.tcx.sess.target
+ }
+}
+
+impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
+ type LayoutOfResult = TyAndLayout<'tcx>;
+
+ #[inline]
+ fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+ if let LayoutError::SizeOverflow(_) = err {
+ self.sess().span_fatal(span, &err.to_string())
+ } else {
+ span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
+ }
+ }
+}
+
+impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
+ type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+ #[inline]
+ fn handle_fn_abi_err(
+ &self,
+ err: FnAbiError<'tcx>,
+ span: Span,
+ fn_abi_request: FnAbiRequest<'tcx>,
+ ) -> ! {
+ if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+ self.sess().span_fatal(span, &err.to_string())
+ } else {
+ match fn_abi_request {
+ FnAbiRequest::OfFnPtr { sig, extra_args } => {
+ span_bug!(
+ span,
+ "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+ sig,
+ extra_args,
+ err
+ );
+ }
+ FnAbiRequest::OfInstance { instance, extra_args } => {
+ span_bug!(
+ span,
+ "`fn_abi_of_instance({}, {:?})` failed: {}",
+ instance,
+ extra_args,
+ err
+ );
+ }
+ }
+ }
+ }
+}
+
+impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn param_env(&self) -> ParamEnv<'tcx> {
+ ParamEnv::reveal_all()
+ }
+}
+
+impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
+ /// Generates a new symbol name with the given prefix. This symbol name must
+ /// only be used for definitions with `internal` or `private` linkage.
+ pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
+ let idx = self.local_gen_sym_counter.get();
+ self.local_gen_sym_counter.set(idx + 1);
+ // Include a '.' character, so there can be no accidental conflicts with
+ // user defined names
+ let mut name = String::with_capacity(prefix.len() + 6);
+ name.push_str(prefix);
+ name.push_str(".");
+ base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
+ name
+ }
+}
+
+pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String {
+ let name = &codegen_unit.name().to_string();
+ mangle_name(&name.replace('-', "_"))
+}
+
+fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
+ match tls_model {
+ TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
+ TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
+ TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
+ TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
+ }
+}
--- /dev/null
+use gccjit::RValue;
+use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::coverage::{
+ CodeRegion,
+ CounterValueReference,
+ ExpressionOperandId,
+ InjectedExpressionId,
+ Op,
+};
+use rustc_middle::ty::Instance;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+ fn set_function_source_hash(
+ &mut self,
+ _instance: Instance<'tcx>,
+ _function_source_hash: u64,
+ ) -> bool {
+ unimplemented!();
+ }
+
+ fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool {
+ // TODO(antoyo)
+ false
+ }
+
+ fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool {
+ // TODO(antoyo)
+ false
+ }
+
+ fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool {
+ // TODO(antoyo)
+ false
+ }
+}
+
+impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn coverageinfo_finalize(&self) {
+ // TODO(antoyo)
+ }
+
+ fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ /// Functions with MIR-based coverage are normally codegenned _only_ if
+ /// called. LLVM coverage tools typically expect every function to be
+ /// defined (even if unused), with at least one call to LLVM intrinsic
+ /// `instrprof.increment`.
+ ///
+ /// Codegen a small function that will never be called, with one counter
+ /// that will never be incremented.
+ ///
+ /// For used/called functions, the coverageinfo was already added to the
+ /// `function_coverage_map` (keyed by function `Instance`) during codegen.
+ /// But in this case, since the unused function was _not_ previously
+ /// codegenned, collect the coverage `CodeRegion`s from the MIR and add
+ /// them. The first `CodeRegion` is used to add a single counter, with the
+ /// same counter ID used in the injected `instrprof.increment` intrinsic
+ /// call. Since the function is never called, all other `CodeRegion`s can be
+ /// added as `unreachable_region`s.
+ fn define_unused_fn(&self, _def_id: DefId) {
+ unimplemented!();
+ }
+}
--- /dev/null
+use gccjit::RValue;
+use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
+use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
+use rustc_middle::mir;
+use rustc_middle::ty::{Instance, Ty};
+use rustc_span::{SourceFile, Span, Symbol};
+use rustc_target::abi::Size;
+use rustc_target::abi::call::FnAbi;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
+ // FIXME(eddyb) find a common convention for all of the debuginfo-related
+ // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
+ fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) {
+ unimplemented!();
+ }
+
+ fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
+ // TODO(antoyo): insert reference to gdb debug scripts section global.
+ }
+
+ fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {
+ unimplemented!();
+ }
+
+ fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) {
+ unimplemented!();
+ }
+}
+
+impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _vtable: Self::Value) {
+ // TODO(antoyo)
+ }
+
+ fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
+ // TODO(antoyo)
+ None
+ }
+
+ fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope {
+ unimplemented!();
+ }
+
+ fn debuginfo_finalize(&self) {
+ // TODO(antoyo)
+ }
+
+ fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable {
+ unimplemented!();
+ }
+
+ fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>) -> Self::DIScope {
+ unimplemented!();
+ }
+
+ fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, _span: Span) -> Self::DILocation {
+ unimplemented!();
+ }
+}
--- /dev/null
+use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
+use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_middle::ty::Ty;
+use rustc_span::Symbol;
+use rustc_target::abi::call::FnAbi;
+
+use crate::abi::FnAbiGccExt;
+use crate::context::{CodegenCx, unit_name};
+use crate::intrinsic::llvm;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+ if self.globals.borrow().contains_key(name) {
+ let typ = self.globals.borrow().get(name).expect("global").get_type();
+ let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
+ if is_tls {
+ global.set_tls_model(self.tls_model);
+ }
+ if let Some(link_section) = link_section {
+ global.set_link_section(&link_section.as_str());
+ }
+ global
+ }
+ else {
+ self.declare_global(name, ty, is_tls, link_section)
+ }
+ }
+
+ pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> {
+ let index = self.global_gen_sym_counter.get();
+ self.global_gen_sym_counter.set(index + 1);
+ let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit));
+ self.context.new_global(None, GlobalKind::Exported, ty, &name)
+ }
+
+ pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> {
+ let global = self.context.new_global(None, linkage, ty, name);
+ let global_address = global.get_address(None);
+ self.globals.borrow_mut().insert(name.to_string(), global_address);
+ global
+ }
+
+ /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> {
+ self.linkage.set(FunctionType::Exported);
+ let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic);
+ // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+ unsafe { std::mem::transmute(func) }
+ }*/
+
+ pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+ let global = self.context.new_global(None, GlobalKind::Exported, ty, name);
+ if is_tls {
+ global.set_tls_model(self.tls_model);
+ }
+ if let Some(link_section) = link_section {
+ global.set_link_section(&link_section.as_str());
+ }
+ let global_address = global.get_address(None);
+ self.globals.borrow_mut().insert(name.to_string(), global_address);
+ global
+ }
+
+ pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> {
+ let global = self.context.new_global(None, GlobalKind::Internal, ty, name);
+ let global_address = global.get_address(None);
+ self.globals.borrow_mut().insert(name.to_string(), global_address);
+ global
+ }
+
+ pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): use the fn_type parameter.
+ let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
+ let return_type = self.type_i32();
+ let variadic = false;
+ self.linkage.set(FunctionType::Exported);
+ let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
+ // NOTE: it is needed to set the current_func here as well, because get_fn() is not called
+ // for the main function.
+ *self.current_func.borrow_mut() = Some(func);
+ // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+ unsafe { std::mem::transmute(func) }
+ }
+
+ pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> {
+ let (return_type, params, variadic) = fn_abi.gcc_type(self);
+ let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, ¶ms, variadic);
+ // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+ unsafe { std::mem::transmute(func) }
+ }
+
+ pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+ self.get_or_insert_global(name, ty, is_tls, link_section)
+ }
+
+ pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
+ // TODO(antoyo): use a different field than globals, because this seems to return a function?
+ self.globals.borrow().get(name).cloned()
+ }
+}
+
+/// Declare a function.
+///
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing Value instead.
+fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
+ if name.starts_with("llvm.") {
+ return llvm::intrinsic(name, cx);
+ }
+ let func =
+ if cx.functions.borrow().contains_key(name) {
+ *cx.functions.borrow().get(name).expect("function")
+ }
+ else {
+ let params: Vec<_> = param_types.into_iter().enumerate()
+ .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
+ .collect();
+ let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, mangle_name(name), variadic);
+ cx.functions.borrow_mut().insert(name.to_string(), func);
+ func
+ };
+
+ // TODO(antoyo): set function calling convention.
+ // TODO(antoyo): set unnamed address.
+ // TODO(antoyo): set no red zone function attribute.
+ // TODO(antoyo): set attributes for optimisation.
+ // TODO(antoyo): set attributes for non lazy bind.
+
+ // FIXME(antoyo): invalid cast.
+ func
+}
+
+// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
+// Unsupported characters: `$` and `.`.
+pub fn mangle_name(name: &str) -> String {
+ name.replace(|char: char| {
+ if !char.is_alphanumeric() && char != '_' {
+ debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
+ true
+ }
+ else {
+ false
+ }
+ }, "_")
+}
--- /dev/null
+use gccjit::Function;
+
+use crate::context::CodegenCx;
+
+pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
+ let _gcc_name =
+ match name {
+ "llvm.x86.xgetbv" => {
+ let gcc_name = "__builtin_trap";
+ let func = cx.context.get_builtin_function(gcc_name);
+ cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
+ return func;
+ },
+ // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
+ "llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd",
+ "llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd",
+ "llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128",
+ _ => unimplemented!("unsupported LLVM intrinsic {}", name)
+ };
+
+ unimplemented!();
+}
--- /dev/null
+pub mod llvm;
+mod simd;
+
+use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
+use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::base::wants_msvc_seh;
+use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_span::{Span, Symbol, symbol::kw, sym};
+use rustc_target::abi::HasDataLayout;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::spec::PanicStrategy;
+
+use crate::abi::GccType;
+use crate::builder::Builder;
+use crate::common::{SignType, TypeReflection};
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+use crate::intrinsic::simd::generic_simd_intrinsic;
+
+fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option<Function<'gcc>> {
+ let gcc_name = match name {
+ sym::sqrtf32 => "sqrtf",
+ sym::sqrtf64 => "sqrt",
+ sym::powif32 => "__builtin_powif",
+ sym::powif64 => "__builtin_powi",
+ sym::sinf32 => "sinf",
+ sym::sinf64 => "sin",
+ sym::cosf32 => "cosf",
+ sym::cosf64 => "cos",
+ sym::powf32 => "powf",
+ sym::powf64 => "pow",
+ sym::expf32 => "expf",
+ sym::expf64 => "exp",
+ sym::exp2f32 => "exp2f",
+ sym::exp2f64 => "exp2",
+ sym::logf32 => "logf",
+ sym::logf64 => "log",
+ sym::log10f32 => "log10f",
+ sym::log10f64 => "log10",
+ sym::log2f32 => "log2f",
+ sym::log2f64 => "log2",
+ sym::fmaf32 => "fmaf",
+ sym::fmaf64 => "fma",
+ sym::fabsf32 => "fabsf",
+ sym::fabsf64 => "fabs",
+ sym::minnumf32 => "fminf",
+ sym::minnumf64 => "fmin",
+ sym::maxnumf32 => "fmaxf",
+ sym::maxnumf64 => "fmax",
+ sym::copysignf32 => "copysignf",
+ sym::copysignf64 => "copysign",
+ sym::floorf32 => "floorf",
+ sym::floorf64 => "floor",
+ sym::ceilf32 => "ceilf",
+ sym::ceilf64 => "ceil",
+ sym::truncf32 => "truncf",
+ sym::truncf64 => "trunc",
+ sym::rintf32 => "rintf",
+ sym::rintf64 => "rint",
+ sym::nearbyintf32 => "nearbyintf",
+ sym::nearbyintf64 => "nearbyint",
+ sym::roundf32 => "roundf",
+ sym::roundf64 => "round",
+ sym::abort => "abort",
+ _ => return None,
+ };
+ Some(cx.context.get_builtin_function(&gcc_name))
+}
+
+impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+ fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) {
+ let tcx = self.tcx;
+ let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+
+ let (def_id, substs) = match *callee_ty.kind() {
+ ty::FnDef(def_id, substs) => (def_id, substs),
+ _ => bug!("expected fn item type, found {}", callee_ty),
+ };
+
+ let sig = callee_ty.fn_sig(tcx);
+ let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+ let arg_tys = sig.inputs();
+ let ret_ty = sig.output();
+ let name = tcx.item_name(def_id);
+ let name_str = &*name.as_str();
+
+ let llret_ty = self.layout_of(ret_ty).gcc_type(self, true);
+ let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
+
+ let simple = get_simple_intrinsic(self, name);
+ let llval =
+ match name {
+ _ if simple.is_some() => {
+ // FIXME(antoyo): remove this cast when the API supports function.
+ let func = unsafe { std::mem::transmute(simple.expect("simple")) };
+ self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
+ },
+ sym::likely => {
+ self.expect(args[0].immediate(), true)
+ }
+ sym::unlikely => {
+ self.expect(args[0].immediate(), false)
+ }
+ kw::Try => {
+ try_intrinsic(
+ self,
+ args[0].immediate(),
+ args[1].immediate(),
+ args[2].immediate(),
+ llresult,
+ );
+ return;
+ }
+ sym::breakpoint => {
+ unimplemented!();
+ }
+ sym::va_copy => {
+ unimplemented!();
+ }
+ sym::va_arg => {
+ unimplemented!();
+ }
+
+ sym::volatile_load | sym::unaligned_volatile_load => {
+ let tp_ty = substs.type_at(0);
+ let mut ptr = args[0].immediate();
+ if let PassMode::Cast(ty) = fn_abi.ret.mode {
+ ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
+ }
+ let load = self.volatile_load(ptr.get_type(), ptr);
+ // TODO(antoyo): set alignment.
+ self.to_immediate(load, self.layout_of(tp_ty))
+ }
+ sym::volatile_store => {
+ let dst = args[0].deref(self.cx());
+ args[1].val.volatile_store(self, dst);
+ return;
+ }
+ sym::unaligned_volatile_store => {
+ let dst = args[0].deref(self.cx());
+ args[1].val.unaligned_volatile_store(self, dst);
+ return;
+ }
+ sym::prefetch_read_data
+ | sym::prefetch_write_data
+ | sym::prefetch_read_instruction
+ | sym::prefetch_write_instruction => {
+ unimplemented!();
+ }
+ sym::ctlz
+ | sym::ctlz_nonzero
+ | sym::cttz
+ | sym::cttz_nonzero
+ | sym::ctpop
+ | sym::bswap
+ | sym::bitreverse
+ | sym::rotate_left
+ | sym::rotate_right
+ | sym::saturating_add
+ | sym::saturating_sub => {
+ let ty = arg_tys[0];
+ match int_type_width_signed(ty, self) {
+ Some((width, signed)) => match name {
+ sym::ctlz | sym::cttz => {
+ let func = self.current_func.borrow().expect("func");
+ let then_block = func.new_block("then");
+ let else_block = func.new_block("else");
+ let after_block = func.new_block("after");
+
+ let arg = args[0].immediate();
+ let result = func.new_local(None, arg.get_type(), "zeros");
+ let zero = self.cx.context.new_rvalue_zero(arg.get_type());
+ let cond = self.cx.context.new_comparison(None, ComparisonOp::Equals, arg, zero);
+ self.llbb().end_with_conditional(None, cond, then_block, else_block);
+
+ let zero_result = self.cx.context.new_rvalue_from_long(arg.get_type(), width as i64);
+ then_block.add_assignment(None, result, zero_result);
+ then_block.end_with_jump(None, after_block);
+
+ // NOTE: since jumps were added in a place
+ // count_leading_zeroes() does not expect, the current blocks
+ // in the state need to be updated.
+ *self.current_block.borrow_mut() = Some(else_block);
+ self.block = Some(else_block);
+
+ let zeros =
+ match name {
+ sym::ctlz => self.count_leading_zeroes(width, arg),
+ sym::cttz => self.count_trailing_zeroes(width, arg),
+ _ => unreachable!(),
+ };
+ else_block.add_assignment(None, result, zeros);
+ else_block.end_with_jump(None, after_block);
+
+ // NOTE: since jumps were added in a place rustc does not
+ // expect, the current blocks in the state need to be updated.
+ *self.current_block.borrow_mut() = Some(after_block);
+ self.block = Some(after_block);
+
+ result.to_rvalue()
+ }
+ sym::ctlz_nonzero => {
+ self.count_leading_zeroes(width, args[0].immediate())
+ },
+ sym::cttz_nonzero => {
+ self.count_trailing_zeroes(width, args[0].immediate())
+ }
+ sym::ctpop => self.pop_count(args[0].immediate()),
+ sym::bswap => {
+ if width == 8 {
+ args[0].immediate() // byte swap a u8/i8 is just a no-op
+ }
+ else {
+ // TODO(antoyo): check if it's faster to use string literals and a
+ // match instead of format!.
+ let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width));
+ let mut arg = args[0].immediate();
+ // FIXME(antoyo): this cast should not be necessary. Remove
+ // when having proper sized integer types.
+ let param_type = bswap.get_param(0).to_rvalue().get_type();
+ if param_type != arg.get_type() {
+ arg = self.bitcast(arg, param_type);
+ }
+ self.cx.context.new_call(None, bswap, &[arg])
+ }
+ },
+ sym::bitreverse => self.bit_reverse(width, args[0].immediate()),
+ sym::rotate_left | sym::rotate_right => {
+ // TODO(antoyo): implement using algorithm from:
+ // https://blog.regehr.org/archives/1063
+ // for other platforms.
+ let is_left = name == sym::rotate_left;
+ let val = args[0].immediate();
+ let raw_shift = args[1].immediate();
+ if is_left {
+ self.rotate_left(val, raw_shift, width)
+ }
+ else {
+ self.rotate_right(val, raw_shift, width)
+ }
+ },
+ sym::saturating_add => {
+ self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width)
+ },
+ sym::saturating_sub => {
+ self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width)
+ },
+ _ => bug!(),
+ },
+ None => {
+ span_invalid_monomorphization_error(
+ tcx.sess,
+ span,
+ &format!(
+ "invalid monomorphization of `{}` intrinsic: \
+ expected basic integer type, found `{}`",
+ name, ty
+ ),
+ );
+ return;
+ }
+ }
+ }
+
+ sym::raw_eq => {
+ use rustc_target::abi::Abi::*;
+ let tp_ty = substs.type_at(0);
+ let layout = self.layout_of(tp_ty).layout;
+ let _use_integer_compare = match layout.abi {
+ Scalar(_) | ScalarPair(_, _) => true,
+ Uninhabited | Vector { .. } => false,
+ Aggregate { .. } => {
+ // For rusty ABIs, small aggregates are actually passed
+ // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
+ // so we re-use that same threshold here.
+ layout.size <= self.data_layout().pointer_size * 2
+ }
+ };
+
+ let a = args[0].immediate();
+ let b = args[1].immediate();
+ if layout.size.bytes() == 0 {
+ self.const_bool(true)
+ }
+ /*else if use_integer_compare {
+ let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits.
+ let ptr_ty = self.type_ptr_to(integer_ty);
+ let a_ptr = self.bitcast(a, ptr_ty);
+ let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+ let b_ptr = self.bitcast(b, ptr_ty);
+ let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+ self.icmp(IntPredicate::IntEQ, a_val, b_val)
+ }*/
+ else {
+ let void_ptr_type = self.context.new_type::<*const ()>();
+ let a_ptr = self.bitcast(a, void_ptr_type);
+ let b_ptr = self.bitcast(b, void_ptr_type);
+ let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+ let builtin = self.context.get_builtin_function("memcmp");
+ let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
+ self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
+ }
+ }
+
+ sym::black_box => {
+ args[0].val.store(self, result);
+
+ let block = self.llbb();
+ let extended_asm = block.add_extended_asm(None, "");
+ extended_asm.add_input_operand(None, "r", result.llval);
+ extended_asm.add_clobber("memory");
+ extended_asm.set_volatile_flag(true);
+
+ // We have copied the value to `result` already.
+ return;
+ }
+
+ _ if name_str.starts_with("simd_") => {
+ match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
+ Ok(llval) => llval,
+ Err(()) => return,
+ }
+ }
+
+ _ => bug!("unknown intrinsic '{}'", name),
+ };
+
+ if !fn_abi.ret.is_ignore() {
+ if let PassMode::Cast(ty) = fn_abi.ret.mode {
+ let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
+ let ptr = self.pointercast(result.llval, ptr_llty);
+ self.store(llval, ptr, result.align);
+ }
+ else {
+ OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
+ .val
+ .store(self, result);
+ }
+ }
+ }
+
+ fn abort(&mut self) {
+ let func = self.context.get_builtin_function("abort");
+ let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
+ self.call(self.type_void(), func, &[], None);
+ }
+
+ fn assume(&mut self, value: Self::Value) {
+ // TODO(antoyo): switch to asumme when it exists.
+ // Or use something like this:
+ // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
+ self.expect(value, true);
+ }
+
+ fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value {
+ // TODO(antoyo)
+ cond
+ }
+
+ fn sideeffect(&mut self) {
+ // TODO(antoyo)
+ }
+
+ fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+
+ fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
+ unimplemented!();
+ }
+}
+
+impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+ fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) {
+ arg_abi.store_fn_arg(self, idx, dst)
+ }
+
+ fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+ arg_abi.store(self, val, dst)
+ }
+
+ fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+ arg_abi.memory_ty(self)
+ }
+}
+
+pub trait ArgAbiExt<'gcc, 'tcx> {
+ fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+ fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>);
+ fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>);
+}
+
+impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
+ /// Gets the LLVM type for a place of the original Rust type of
+ /// this argument/return, i.e., the result of `type_of::type_of`.
+ fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+ self.layout.gcc_type(cx, true)
+ }
+
+ /// Stores a direct/indirect value described by this ArgAbi into a
+ /// place for the original Rust type of this argument/return.
+ /// Can be used for both storing formal arguments into Rust variables
+ /// or results of call/invoke instructions into their destinations.
+ fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+ if self.is_ignore() {
+ return;
+ }
+ if self.is_sized_indirect() {
+ OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
+ }
+ else if self.is_unsized_indirect() {
+ bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
+ }
+ else if let PassMode::Cast(cast) = self.mode {
+ // FIXME(eddyb): Figure out when the simpler Store is safe, clang
+ // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
+ let can_store_through_cast_ptr = false;
+ if can_store_through_cast_ptr {
+ let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx));
+ let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
+ bx.store(val, cast_dst, self.layout.align.abi);
+ }
+ else {
+ // The actual return type is a struct, but the ABI
+ // adaptation code has cast it into some scalar type. The
+ // code that follows is the only reliable way I have
+ // found to do a transform like i64 -> {i32,i32}.
+ // Basically we dump the data onto the stack then memcpy it.
+ //
+ // Other approaches I tried:
+ // - Casting rust ret pointer to the foreign type and using Store
+ // is (a) unsafe if size of foreign type > size of rust type and
+ // (b) runs afoul of strict aliasing rules, yielding invalid
+ // assembly under -O (specifically, the store gets removed).
+ // - Truncating foreign type to correct integral type and then
+ // bitcasting to the struct type yields invalid cast errors.
+
+ // We instead thus allocate some scratch space...
+ let scratch_size = cast.size(bx);
+ let scratch_align = cast.align(bx);
+ let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align);
+ bx.lifetime_start(llscratch, scratch_size);
+
+ // ... where we first store the value...
+ bx.store(val, llscratch, scratch_align);
+
+ // ... and then memcpy it to the intended destination.
+ bx.memcpy(
+ dst.llval,
+ self.layout.align.abi,
+ llscratch,
+ scratch_align,
+ bx.const_usize(self.layout.size.bytes()),
+ MemFlags::empty(),
+ );
+
+ bx.lifetime_end(llscratch, scratch_size);
+ }
+ }
+ else {
+ OperandValue::Immediate(val).store(bx, dst);
+ }
+ }
+
+ fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+ let mut next = || {
+ let val = bx.current_func().get_param(*idx as i32);
+ *idx += 1;
+ val.to_rvalue()
+ };
+ match self.mode {
+ PassMode::Ignore => {}
+ PassMode::Pair(..) => {
+ OperandValue::Pair(next(), next()).store(bx, dst);
+ }
+ PassMode::Indirect { extra_attrs: Some(_), .. } => {
+ OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
+ }
+ PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => {
+ let next_arg = next();
+ self.store(bx, next_arg.to_rvalue(), dst);
+ }
+ }
+ }
+}
+
+fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> {
+ match ty.kind() {
+ ty::Int(t) => Some((
+ match t {
+ rustc_middle::ty::IntTy::Isize => u64::from(cx.tcx.sess.target.pointer_width),
+ rustc_middle::ty::IntTy::I8 => 8,
+ rustc_middle::ty::IntTy::I16 => 16,
+ rustc_middle::ty::IntTy::I32 => 32,
+ rustc_middle::ty::IntTy::I64 => 64,
+ rustc_middle::ty::IntTy::I128 => 128,
+ },
+ true,
+ )),
+ ty::Uint(t) => Some((
+ match t {
+ rustc_middle::ty::UintTy::Usize => u64::from(cx.tcx.sess.target.pointer_width),
+ rustc_middle::ty::UintTy::U8 => 8,
+ rustc_middle::ty::UintTy::U16 => 16,
+ rustc_middle::ty::UintTy::U32 => 32,
+ rustc_middle::ty::UintTy::U64 => 64,
+ rustc_middle::ty::UintTy::U128 => 128,
+ },
+ false,
+ )),
+ _ => None,
+ }
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+ fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> {
+ let result_type = value.get_type();
+ let typ = result_type.to_unsigned(self.cx);
+
+ let value =
+ if result_type.is_signed(self.cx) {
+ self.context.new_bitcast(None, value, typ)
+ }
+ else {
+ value
+ };
+
+ let context = &self.cx.context;
+ let result =
+ match width {
+ 8 => {
+ // First step.
+ let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0));
+ let left = self.lshr(left, context.new_rvalue_from_int(typ, 4));
+ let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F));
+ let right = self.shl(right, context.new_rvalue_from_int(typ, 4));
+ let step1 = self.or(left, right);
+
+ // Second step.
+ let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC));
+ let left = self.lshr(left, context.new_rvalue_from_int(typ, 2));
+ let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33));
+ let right = self.shl(right, context.new_rvalue_from_int(typ, 2));
+ let step2 = self.or(left, right);
+
+ // Third step.
+ let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA));
+ let left = self.lshr(left, context.new_rvalue_from_int(typ, 1));
+ let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55));
+ let right = self.shl(right, context.new_rvalue_from_int(typ, 1));
+ let step3 = self.or(left, right);
+
+ step3
+ },
+ 16 => {
+ // First step.
+ let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555));
+ let left = self.shl(left, context.new_rvalue_from_int(typ, 1));
+ let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA));
+ let right = self.lshr(right, context.new_rvalue_from_int(typ, 1));
+ let step1 = self.or(left, right);
+
+ // Second step.
+ let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333));
+ let left = self.shl(left, context.new_rvalue_from_int(typ, 2));
+ let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC));
+ let right = self.lshr(right, context.new_rvalue_from_int(typ, 2));
+ let step2 = self.or(left, right);
+
+ // Third step.
+ let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F));
+ let left = self.shl(left, context.new_rvalue_from_int(typ, 4));
+ let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0));
+ let right = self.lshr(right, context.new_rvalue_from_int(typ, 4));
+ let step3 = self.or(left, right);
+
+ // Fourth step.
+ let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF));
+ let left = self.shl(left, context.new_rvalue_from_int(typ, 8));
+ let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00));
+ let right = self.lshr(right, context.new_rvalue_from_int(typ, 8));
+ let step4 = self.or(left, right);
+
+ step4
+ },
+ 32 => {
+ // TODO(antoyo): Refactor with other implementations.
+ // First step.
+ let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555));
+ let left = self.shl(left, context.new_rvalue_from_long(typ, 1));
+ let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA));
+ let right = self.lshr(right, context.new_rvalue_from_long(typ, 1));
+ let step1 = self.or(left, right);
+
+ // Second step.
+ let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333));
+ let left = self.shl(left, context.new_rvalue_from_long(typ, 2));
+ let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC));
+ let right = self.lshr(right, context.new_rvalue_from_long(typ, 2));
+ let step2 = self.or(left, right);
+
+ // Third step.
+ let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F));
+ let left = self.shl(left, context.new_rvalue_from_long(typ, 4));
+ let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0));
+ let right = self.lshr(right, context.new_rvalue_from_long(typ, 4));
+ let step3 = self.or(left, right);
+
+ // Fourth step.
+ let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF));
+ let left = self.shl(left, context.new_rvalue_from_long(typ, 8));
+ let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00));
+ let right = self.lshr(right, context.new_rvalue_from_long(typ, 8));
+ let step4 = self.or(left, right);
+
+ // Fifth step.
+ let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF));
+ let left = self.shl(left, context.new_rvalue_from_long(typ, 16));
+ let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000));
+ let right = self.lshr(right, context.new_rvalue_from_long(typ, 16));
+ let step5 = self.or(left, right);
+
+ step5
+ },
+ 64 => {
+ // First step.
+ let left = self.shl(value, context.new_rvalue_from_long(typ, 32));
+ let right = self.lshr(value, context.new_rvalue_from_long(typ, 32));
+ let step1 = self.or(left, right);
+
+ // Second step.
+ let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF));
+ let left = self.shl(left, context.new_rvalue_from_long(typ, 15));
+ let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead?
+ let right = self.lshr(right, context.new_rvalue_from_long(typ, 17));
+ let step2 = self.or(left, right);
+
+ // Third step.
+ let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10));
+ let left = self.xor(step2, left);
+ let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F));
+
+ let left = self.shl(temp, context.new_rvalue_from_long(typ, 10));
+ let left = self.or(temp, left);
+ let step3 = self.xor(left, step2);
+
+ // Fourth step.
+ let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4));
+ let left = self.xor(step3, left);
+ let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421));
+
+ let left = self.shl(temp, context.new_rvalue_from_long(typ, 4));
+ let left = self.or(temp, left);
+ let step4 = self.xor(left, step3);
+
+ // Fifth step.
+ let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2));
+ let left = self.xor(step4, left);
+ let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842));
+
+ let left = self.shl(temp, context.new_rvalue_from_long(typ, 2));
+ let left = self.or(temp, left);
+ let step5 = self.xor(left, step4);
+
+ step5
+ },
+ 128 => {
+ // TODO(antoyo): find a more efficient implementation?
+ let sixty_four = self.context.new_rvalue_from_long(typ, 64);
+ let high = self.context.new_cast(None, value >> sixty_four, self.u64_type);
+ let low = self.context.new_cast(None, value, self.u64_type);
+
+ let reversed_high = self.bit_reverse(64, high);
+ let reversed_low = self.bit_reverse(64, low);
+
+ let new_low = self.context.new_cast(None, reversed_high, typ);
+ let new_high = self.context.new_cast(None, reversed_low, typ) << sixty_four;
+
+ new_low | new_high
+ },
+ _ => {
+ panic!("cannot bit reverse with width = {}", width);
+ },
+ };
+
+ self.context.new_bitcast(None, result, result_type)
+ }
+
+ fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): use width?
+ let arg_type = arg.get_type();
+ let count_leading_zeroes =
+ if arg_type.is_uint(&self.cx) {
+ "__builtin_clz"
+ }
+ else if arg_type.is_ulong(&self.cx) {
+ "__builtin_clzl"
+ }
+ else if arg_type.is_ulonglong(&self.cx) {
+ "__builtin_clzll"
+ }
+ else if width == 128 {
+ // Algorithm from: https://stackoverflow.com/a/28433850/389119
+ let array_type = self.context.new_array_type(None, arg_type, 3);
+ let result = self.current_func()
+ .new_local(None, array_type, "count_loading_zeroes_results");
+
+ let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
+ let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
+ let low = self.context.new_cast(None, arg, self.u64_type);
+
+ let zero = self.context.new_rvalue_zero(self.usize_type);
+ let one = self.context.new_rvalue_one(self.usize_type);
+ let two = self.context.new_rvalue_from_long(self.usize_type, 2);
+
+ let clzll = self.context.get_builtin_function("__builtin_clzll");
+
+ let first_elem = self.context.new_array_access(None, result, zero);
+ let first_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[high]), arg_type);
+ self.llbb()
+ .add_assignment(None, first_elem, first_value);
+
+ let second_elem = self.context.new_array_access(None, result, one);
+ let second_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[low]), arg_type) + sixty_four;
+ self.llbb()
+ .add_assignment(None, second_elem, second_value);
+
+ let third_elem = self.context.new_array_access(None, result, two);
+ let third_value = self.context.new_rvalue_from_long(arg_type, 128);
+ self.llbb()
+ .add_assignment(None, third_elem, third_value);
+
+ let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
+ let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
+ let not_low_and_not_high = not_low & not_high;
+ let index = not_high + not_low_and_not_high;
+
+ let res = self.context.new_array_access(None, result, index);
+
+ return self.context.new_cast(None, res, arg_type);
+ }
+ else {
+ let count_leading_zeroes = self.context.get_builtin_function("__builtin_clz");
+ let arg = self.context.new_cast(None, arg, self.uint_type);
+ let diff = self.int_width(self.uint_type) - self.int_width(arg_type);
+ let diff = self.context.new_rvalue_from_long(self.int_type, diff);
+ let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff;
+ return self.context.new_cast(None, res, arg_type);
+ };
+ let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes);
+ let res = self.context.new_call(None, count_leading_zeroes, &[arg]);
+ self.context.new_cast(None, res, arg_type)
+ }
+
+ fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
+ let result_type = arg.get_type();
+ let arg =
+ if result_type.is_signed(self.cx) {
+ let new_type = result_type.to_unsigned(self.cx);
+ self.context.new_bitcast(None, arg, new_type)
+ }
+ else {
+ arg
+ };
+ let arg_type = arg.get_type();
+ let (count_trailing_zeroes, expected_type) =
+ if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) {
+ // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero.
+ ("__builtin_ctz", self.cx.uint_type)
+ }
+ else if arg_type.is_ulong(&self.cx) {
+ ("__builtin_ctzl", self.cx.ulong_type)
+ }
+ else if arg_type.is_ulonglong(&self.cx) {
+ ("__builtin_ctzll", self.cx.ulonglong_type)
+ }
+ else if arg_type.is_u128(&self.cx) {
+ // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119
+ let array_type = self.context.new_array_type(None, arg_type, 3);
+ let result = self.current_func()
+ .new_local(None, array_type, "count_loading_zeroes_results");
+
+ let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
+ let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
+ let low = self.context.new_cast(None, arg, self.u64_type);
+
+ let zero = self.context.new_rvalue_zero(self.usize_type);
+ let one = self.context.new_rvalue_one(self.usize_type);
+ let two = self.context.new_rvalue_from_long(self.usize_type, 2);
+
+ let ctzll = self.context.get_builtin_function("__builtin_ctzll");
+
+ let first_elem = self.context.new_array_access(None, result, zero);
+ let first_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[low]), arg_type);
+ self.llbb()
+ .add_assignment(None, first_elem, first_value);
+
+ let second_elem = self.context.new_array_access(None, result, one);
+ let second_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[high]), arg_type) + sixty_four;
+ self.llbb()
+ .add_assignment(None, second_elem, second_value);
+
+ let third_elem = self.context.new_array_access(None, result, two);
+ let third_value = self.context.new_rvalue_from_long(arg_type, 128);
+ self.llbb()
+ .add_assignment(None, third_elem, third_value);
+
+ let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
+ let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
+ let not_low_and_not_high = not_low & not_high;
+ let index = not_low + not_low_and_not_high;
+
+ let res = self.context.new_array_access(None, result, index);
+
+ return self.context.new_bitcast(None, res, result_type);
+ }
+ else {
+ unimplemented!("count_trailing_zeroes for {:?}", arg_type);
+ };
+ let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes);
+ let arg =
+ if arg_type != expected_type {
+ self.context.new_cast(None, arg, expected_type)
+ }
+ else {
+ arg
+ };
+ let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
+ self.context.new_bitcast(None, res, result_type)
+ }
+
+ fn int_width(&self, typ: Type<'gcc>) -> i64 {
+ self.cx.int_width(typ) as i64
+ }
+
+ fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> {
+ // TODO(antoyo): use the optimized version with fewer operations.
+ let result_type = value.get_type();
+ let value_type = result_type.to_unsigned(self.cx);
+
+ let value =
+ if result_type.is_signed(self.cx) {
+ self.context.new_bitcast(None, value, value_type)
+ }
+ else {
+ value
+ };
+
+ if value_type.is_u128(&self.cx) {
+ // TODO(antoyo): implement in the normal algorithm below to have a more efficient
+ // implementation (that does not require a call to __popcountdi2).
+ let popcount = self.context.get_builtin_function("__builtin_popcountll");
+ let sixty_four = self.context.new_rvalue_from_long(value_type, 64);
+ let high = self.context.new_cast(None, value >> sixty_four, self.cx.ulonglong_type);
+ let high = self.context.new_call(None, popcount, &[high]);
+ let low = self.context.new_cast(None, value, self.cx.ulonglong_type);
+ let low = self.context.new_call(None, popcount, &[low]);
+ let res = high + low;
+ return self.context.new_bitcast(None, res, result_type);
+ }
+
+ // First step.
+ let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555);
+ let left = value & mask;
+ let shifted = value >> self.context.new_rvalue_from_int(value_type, 1);
+ let right = shifted & mask;
+ let value = left + right;
+
+ // Second step.
+ let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333);
+ let left = value & mask;
+ let shifted = value >> self.context.new_rvalue_from_int(value_type, 2);
+ let right = shifted & mask;
+ let value = left + right;
+
+ // Third step.
+ let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F);
+ let left = value & mask;
+ let shifted = value >> self.context.new_rvalue_from_int(value_type, 4);
+ let right = shifted & mask;
+ let value = left + right;
+
+ if value_type.is_u8(&self.cx) {
+ return self.context.new_bitcast(None, value, result_type);
+ }
+
+ // Fourth step.
+ let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF);
+ let left = value & mask;
+ let shifted = value >> self.context.new_rvalue_from_int(value_type, 8);
+ let right = shifted & mask;
+ let value = left + right;
+
+ if value_type.is_u16(&self.cx) {
+ return self.context.new_bitcast(None, value, result_type);
+ }
+
+ // Fifth step.
+ let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF);
+ let left = value & mask;
+ let shifted = value >> self.context.new_rvalue_from_int(value_type, 16);
+ let right = shifted & mask;
+ let value = left + right;
+
+ if value_type.is_u32(&self.cx) {
+ return self.context.new_bitcast(None, value, result_type);
+ }
+
+ // Sixth step.
+ let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF);
+ let left = value & mask;
+ let shifted = value >> self.context.new_rvalue_from_int(value_type, 32);
+ let right = shifted & mask;
+ let value = left + right;
+
+ self.context.new_bitcast(None, value, result_type)
+ }
+
+ // Algorithm from: https://blog.regehr.org/archives/1063
+ fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
+ let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64);
+ let shift = shift % max;
+ let lhs = self.shl(value, shift);
+ let result_and =
+ self.and(
+ self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift),
+ self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1),
+ );
+ let rhs = self.lshr(value, result_and);
+ self.or(lhs, rhs)
+ }
+
+ // Algorithm from: https://blog.regehr.org/archives/1063
+ fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
+ let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64);
+ let shift = shift % max;
+ let lhs = self.lshr(value, shift);
+ let result_and =
+ self.and(
+ self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift),
+ self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1),
+ );
+ let rhs = self.shl(value, result_and);
+ self.or(lhs, rhs)
+ }
+
+ fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
+ let func = self.current_func.borrow().expect("func");
+
+ if signed {
+ // Algorithm from: https://stackoverflow.com/a/56531252/389119
+ let after_block = func.new_block("after");
+ let func_name =
+ match width {
+ 8 => "__builtin_add_overflow",
+ 16 => "__builtin_add_overflow",
+ 32 => "__builtin_sadd_overflow",
+ 64 => "__builtin_saddll_overflow",
+ 128 => "__builtin_add_overflow",
+ _ => unreachable!(),
+ };
+ let overflow_func = self.context.get_builtin_function(func_name);
+ let result_type = lhs.get_type();
+ let res = func.new_local(None, result_type, "saturating_sum");
+ let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
+
+ let then_block = func.new_block("then");
+
+ let unsigned_type = self.context.new_int_type(width as i32 / 8, false);
+ let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1);
+ let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type,
+ self.context.new_rvalue_from_int(unsigned_type, 0)
+ );
+ let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type);
+ then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type));
+ then_block.end_with_jump(None, after_block);
+
+ self.llbb().end_with_conditional(None, overflow, then_block, after_block);
+
+ // NOTE: since jumps were added in a place rustc does not
+ // expect, the current blocks in the state need to be updated.
+ *self.current_block.borrow_mut() = Some(after_block);
+ self.block = Some(after_block);
+
+ res.to_rvalue()
+ }
+ else {
+ // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/
+ let res = lhs + rhs;
+ let res_type = res.get_type();
+ let cond = self.context.new_comparison(None, ComparisonOp::LessThan, res, lhs);
+ let value = self.context.new_unary_op(None, UnaryOp::Minus, res_type, self.context.new_cast(None, cond, res_type));
+ res | value
+ }
+ }
+
+ // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/
+ fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
+ if signed {
+ // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119
+ let func_name =
+ match width {
+ 8 => "__builtin_sub_overflow",
+ 16 => "__builtin_sub_overflow",
+ 32 => "__builtin_ssub_overflow",
+ 64 => "__builtin_ssubll_overflow",
+ 128 => "__builtin_sub_overflow",
+ _ => unreachable!(),
+ };
+ let overflow_func = self.context.get_builtin_function(func_name);
+ let result_type = lhs.get_type();
+ let func = self.current_func.borrow().expect("func");
+ let res = func.new_local(None, result_type, "saturating_diff");
+ let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
+
+ let then_block = func.new_block("then");
+ let after_block = func.new_block("after");
+
+ let unsigned_type = self.context.new_int_type(width as i32 / 8, false);
+ let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1);
+ let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type,
+ self.context.new_rvalue_from_int(unsigned_type, 0)
+ );
+ let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type);
+ then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type));
+ then_block.end_with_jump(None, after_block);
+
+ self.llbb().end_with_conditional(None, overflow, then_block, after_block);
+
+ // NOTE: since jumps were added in a place rustc does not
+ // expect, the current blocks in the state need to be updated.
+ *self.current_block.borrow_mut() = Some(after_block);
+ self.block = Some(after_block);
+
+ res.to_rvalue()
+ }
+ else {
+ let res = lhs - rhs;
+ let comparison = self.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs);
+ let comparison = self.context.new_cast(None, comparison, lhs.get_type());
+ let unary_op = self.context.new_unary_op(None, UnaryOp::Minus, comparison.get_type(), comparison);
+ self.and(res, unary_op)
+ }
+ }
+}
+
+fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
+ if bx.sess().panic_strategy() == PanicStrategy::Abort {
+ bx.call(bx.type_void(), try_func, &[data], None);
+ // Return 0 unconditionally from the intrinsic call;
+ // we can never unwind.
+ let ret_align = bx.tcx.data_layout.i32_align.abi;
+ bx.store(bx.const_i32(0), dest, ret_align);
+ }
+ else if wants_msvc_seh(bx.sess()) {
+ unimplemented!();
+ }
+ else {
+ unimplemented!();
+ }
+}
--- /dev/null
+use gccjit::{RValue, Type};
+use rustc_codegen_ssa::base::compare_simd_types;
+use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::mir::operand::OperandRef;
+use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
+use rustc_hir as hir;
+use rustc_middle::span_bug;
+use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{Span, Symbol, sym};
+
+use crate::builder::Builder;
+
+pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
+ // macros for error handling:
+ macro_rules! emit_error {
+ ($msg: tt) => {
+ emit_error!($msg, )
+ };
+ ($msg: tt, $($fmt: tt)*) => {
+ span_invalid_monomorphization_error(
+ bx.sess(), span,
+ &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
+ name, $($fmt)*));
+ }
+ }
+
+ macro_rules! return_error {
+ ($($fmt: tt)*) => {
+ {
+ emit_error!($($fmt)*);
+ return Err(());
+ }
+ }
+ }
+
+ macro_rules! require {
+ ($cond: expr, $($fmt: tt)*) => {
+ if !$cond {
+ return_error!($($fmt)*);
+ }
+ };
+ }
+
+ macro_rules! require_simd {
+ ($ty: expr, $position: expr) => {
+ require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+ };
+ }
+
+ let tcx = bx.tcx();
+ let sig =
+ tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
+ let arg_tys = sig.inputs();
+ let name_str = &*name.as_str();
+
+ // every intrinsic below takes a SIMD vector as its first argument
+ require_simd!(arg_tys[0], "input");
+ let in_ty = arg_tys[0];
+
+ let comparison = match name {
+ sym::simd_eq => Some(hir::BinOpKind::Eq),
+ sym::simd_ne => Some(hir::BinOpKind::Ne),
+ sym::simd_lt => Some(hir::BinOpKind::Lt),
+ sym::simd_le => Some(hir::BinOpKind::Le),
+ sym::simd_gt => Some(hir::BinOpKind::Gt),
+ sym::simd_ge => Some(hir::BinOpKind::Ge),
+ _ => None,
+ };
+
+ let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
+ if let Some(cmp_op) = comparison {
+ require_simd!(ret_ty, "return");
+
+ let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+ require!(
+ in_len == out_len,
+ "expected return type with length {} (same as input type `{}`), \
+ found `{}` with length {}",
+ in_len,
+ in_ty,
+ ret_ty,
+ out_len
+ );
+ require!(
+ bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
+ "expected return type with integer elements, found `{}` with non-integer `{}`",
+ ret_ty,
+ out_ty
+ );
+
+ return Ok(compare_simd_types(
+ bx,
+ args[0].immediate(),
+ args[1].immediate(),
+ in_elem,
+ llret_ty,
+ cmp_op,
+ ));
+ }
+
+ if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
+ let n: u64 = stripped.parse().unwrap_or_else(|_| {
+ span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
+ });
+
+ require_simd!(ret_ty, "return");
+
+ let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+ require!(
+ out_len == n,
+ "expected return type of length {}, found `{}` with length {}",
+ n,
+ ret_ty,
+ out_len
+ );
+ require!(
+ in_elem == out_ty,
+ "expected return element type `{}` (element of input `{}`), \
+ found `{}` with element type `{}`",
+ in_elem,
+ in_ty,
+ ret_ty,
+ out_ty
+ );
+
+ let vector = args[2].immediate();
+
+ return Ok(bx.shuffle_vector(
+ args[0].immediate(),
+ args[1].immediate(),
+ vector,
+ ));
+ }
+
+ macro_rules! arith_binary {
+ ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
+ $(if name == sym::$name {
+ match in_elem.kind() {
+ $($(ty::$p(_))|* => {
+ return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
+ })*
+ _ => {},
+ }
+ require!(false,
+ "unsupported operation on `{}` with element `{}`",
+ in_ty,
+ in_elem)
+ })*
+ }
+ }
+
+ arith_binary! {
+ simd_add: Uint, Int => add, Float => fadd;
+ simd_sub: Uint, Int => sub, Float => fsub;
+ simd_mul: Uint, Int => mul, Float => fmul;
+ simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
+ simd_rem: Uint => urem, Int => srem, Float => frem;
+ simd_shl: Uint, Int => shl;
+ simd_shr: Uint => lshr, Int => ashr;
+ simd_and: Uint, Int => and;
+ simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors.
+ simd_xor: Uint, Int => xor;
+ }
+
+ unimplemented!("simd {}", name);
+}
--- /dev/null
+/*
+ * TODO(antoyo): support #[inline] attributes.
+ * TODO(antoyo): support LTO.
+ *
+ * TODO(antoyo): remove the patches.
+ */
+
+#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)]
+#![allow(broken_intra_doc_links)]
+#![recursion_limit="256"]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+
+extern crate rustc_ast;
+extern crate rustc_codegen_ssa;
+extern crate rustc_data_structures;
+extern crate rustc_errors;
+extern crate rustc_hir;
+extern crate rustc_metadata;
+extern crate rustc_middle;
+extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_symbol_mangling;
+extern crate rustc_target;
+extern crate snap;
+
+// This prevents duplicating functions and statics that are already part of the host rustc process.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
+mod abi;
+mod allocator;
+mod archive;
+mod asm;
+mod back;
+mod base;
+mod builder;
+mod callee;
+mod common;
+mod consts;
+mod context;
+mod coverageinfo;
+mod debuginfo;
+mod declare;
+mod intrinsic;
+mod mono_item;
+mod type_;
+mod type_of;
+
+use std::any::Any;
+use std::sync::Arc;
+
+use gccjit::{Context, OptimizationLevel};
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
+use rustc_codegen_ssa::base::codegen_crate;
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn};
+use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
+use rustc_codegen_ssa::target_features::supported_target_features;
+use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{ErrorReported, Handler};
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::config::{Lto, OptLevel, OutputFilenames};
+use rustc_session::Session;
+use rustc_span::Symbol;
+use rustc_span::fatal_error::FatalError;
+
+pub struct PrintOnPanic<F: Fn() -> String>(pub F);
+
+impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
+ fn drop(&mut self) {
+ if ::std::thread::panicking() {
+ println!("{}", (self.0)());
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct GccCodegenBackend;
+
+impl CodegenBackend for GccCodegenBackend {
+ fn init(&self, sess: &Session) {
+ if sess.lto() != Lto::No {
+ sess.warn("LTO is not supported. You may get a linker error.");
+ }
+ }
+
+ fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> {
+ let target_cpu = target_cpu(tcx.sess);
+ let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
+
+ rustc_symbol_mangling::test::report_symbol_names(tcx);
+
+ Box::new(res)
+ }
+
+ fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
+ let (codegen_results, work_products) = ongoing_codegen
+ .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
+ .expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
+ .join(sess);
+
+ Ok((codegen_results, work_products))
+ }
+
+ fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorReported> {
+ use rustc_codegen_ssa::back::link::link_binary;
+
+ link_binary::<crate::archive::ArArchiveBuilder<'_>>(
+ sess,
+ &codegen_results,
+ outputs,
+ )
+ }
+
+ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
+ target_features(sess)
+ }
+}
+
+impl ExtraBackendMethods for GccCodegenBackend {
+ fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module {
+ GccContext {
+ context: Context::default(),
+ }
+ }
+
+ fn write_compressed_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut Self::Module) {
+ base::write_compressed_metadata(tcx, metadata, gcc_module)
+ }
+
+ fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+ unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
+ }
+
+ fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
+ base::compile_codegen_unit(tcx, cgu_name)
+ }
+
+ fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel) -> TargetMachineFactoryFn<Self> {
+ // TODO(antoyo): set opt level.
+ Arc::new(|_| {
+ Ok(())
+ })
+ }
+
+ fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str {
+ unimplemented!();
+ }
+
+ fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> {
+ None
+ // TODO(antoyo)
+ }
+}
+
+pub struct ModuleBuffer;
+
+impl ModuleBufferMethods for ModuleBuffer {
+ fn data(&self) -> &[u8] {
+ unimplemented!();
+ }
+}
+
+pub struct ThinBuffer;
+
+impl ThinBufferMethods for ThinBuffer {
+ fn data(&self) -> &[u8] {
+ unimplemented!();
+ }
+}
+
+pub struct GccContext {
+ context: Context<'static>,
+}
+
+unsafe impl Send for GccContext {}
+// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here.
+unsafe impl Sync for GccContext {}
+
+impl WriteBackendMethods for GccCodegenBackend {
+ type Module = GccContext;
+ type TargetMachine = ();
+ type ModuleBuffer = ModuleBuffer;
+ type Context = ();
+ type ThinData = ();
+ type ThinBuffer = ThinBuffer;
+
+ fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
+ // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
+ // NOTE: implemented elsewhere.
+ // TODO: what is implemented elsewhere ^ ?
+ let module =
+ match modules.remove(0) {
+ FatLTOInput::InMemory(module) => module,
+ FatLTOInput::Serialized { .. } => {
+ unimplemented!();
+ }
+ };
+ Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] })
+ }
+
+ fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
+ unimplemented!();
+ }
+
+ fn print_pass_timings(&self) {
+ unimplemented!();
+ }
+
+ unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
+ module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
+ Ok(())
+ }
+
+ unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: &mut ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+ unimplemented!();
+ }
+
+ unsafe fn codegen(cgcx: &CodegenContext<Self>, diag_handler: &Handler, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+ back::write::codegen(cgcx, diag_handler, module, config)
+ }
+
+ fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
+ unimplemented!();
+ }
+
+ fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
+ unimplemented!();
+ }
+
+ fn run_lto_pass_manager(_cgcx: &CodegenContext<Self>, _module: &ModuleCodegen<Self::Module>, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> {
+ // TODO(antoyo)
+ Ok(())
+ }
+
+ fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+ back::write::link(cgcx, diag_handler, modules)
+ }
+}
+
+/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
+#[no_mangle]
+pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
+ Box::new(GccCodegenBackend)
+}
+
+fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
+ match optlevel {
+ None => OptimizationLevel::None,
+ Some(level) => {
+ match level {
+ OptLevel::No => OptimizationLevel::None,
+ OptLevel::Less => OptimizationLevel::Limited,
+ OptLevel::Default => OptimizationLevel::Standard,
+ OptLevel::Aggressive => OptimizationLevel::Aggressive,
+ OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
+ }
+ },
+ }
+}
+
+fn handle_native(name: &str) -> &str {
+ if name != "native" {
+ return name;
+ }
+
+ unimplemented!();
+}
+
+pub fn target_cpu(sess: &Session) -> &str {
+ let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
+ handle_native(name)
+}
+
+pub fn target_features(sess: &Session) -> Vec<Symbol> {
+ supported_target_features(sess)
+ .iter()
+ .filter_map(
+ |&(feature, gate)| {
+ if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
+ },
+ )
+ .filter(|_feature| {
+ // TODO(antoyo): implement a way to get enabled feature in libgccjit.
+ false
+ })
+ .map(|feature| Symbol::intern(feature))
+ .collect()
+}
--- /dev/null
+use rustc_codegen_ssa::traits::PreDefineMethods;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::mono::{Linkage, Visibility};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_span::def_id::DefId;
+
+use crate::base;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn predefine_static(&self, def_id: DefId, _linkage: Linkage, _visibility: Visibility, symbol_name: &str) {
+ let attrs = self.tcx.codegen_fn_attrs(def_id);
+ let instance = Instance::mono(self.tcx, def_id);
+ let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+ let gcc_type = self.layout_of(ty).gcc_type(self, true);
+
+ let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+ let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section);
+
+ // TODO(antoyo): set linkage and visibility.
+ self.instances.borrow_mut().insert(instance, global);
+ }
+
+ fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, _visibility: Visibility, symbol_name: &str) {
+ assert!(!instance.substs.needs_infer());
+
+ let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
+ self.linkage.set(base::linkage_to_gcc(linkage));
+ let _decl = self.declare_fn(symbol_name, &fn_abi);
+ //let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+
+ // TODO(antoyo): call set_link_section() to allow initializing argc/argv.
+ // TODO(antoyo): set unique comdat.
+ // TODO(antoyo): use inline attribute from there in linkage.set() above.
+ }
+}
--- /dev/null
+use std::convert::TryInto;
+
+use gccjit::{RValue, Struct, Type};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
+use rustc_codegen_ssa::common::TypeKind;
+use rustc_middle::bug;
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_target::abi::{AddressSpace, Align, Integer, Size};
+
+use crate::common::TypeReflection;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> {
+ // gcc only supports 1, 2, 4 or 8-byte integers.
+ // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa
+ // sometimes use 96-bit numbers and the following code will give an integer of a different
+ // size.
+ let bytes = (num_bits / 8).next_power_of_two() as i32;
+ match bytes {
+ 1 => self.i8_type,
+ 2 => self.i16_type,
+ 4 => self.i32_type,
+ 8 => self.i64_type,
+ 16 => self.i128_type,
+ _ => panic!("unexpected num_bits: {}", num_bits),
+ }
+ }
+
+ pub fn type_void(&self) -> Type<'gcc> {
+ self.context.new_type::<()>()
+ }
+
+ pub fn type_size_t(&self) -> Type<'gcc> {
+ self.context.new_type::<usize>()
+ }
+
+ pub fn type_u8(&self) -> Type<'gcc> {
+ self.u8_type
+ }
+
+ pub fn type_u16(&self) -> Type<'gcc> {
+ self.u16_type
+ }
+
+ pub fn type_u32(&self) -> Type<'gcc> {
+ self.u32_type
+ }
+
+ pub fn type_u64(&self) -> Type<'gcc> {
+ self.u64_type
+ }
+
+ pub fn type_u128(&self) -> Type<'gcc> {
+ self.u128_type
+ }
+
+ pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> {
+ // FIXME(eddyb) We could find a better approximation if ity.align < align.
+ let ity = Integer::approximate_align(self, align);
+ self.type_from_integer(ity)
+ }
+}
+
+impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn type_i1(&self) -> Type<'gcc> {
+ self.bool_type
+ }
+
+ fn type_i8(&self) -> Type<'gcc> {
+ self.i8_type
+ }
+
+ fn type_i16(&self) -> Type<'gcc> {
+ self.i16_type
+ }
+
+ fn type_i32(&self) -> Type<'gcc> {
+ self.i32_type
+ }
+
+ fn type_i64(&self) -> Type<'gcc> {
+ self.i64_type
+ }
+
+ fn type_i128(&self) -> Type<'gcc> {
+ self.i128_type
+ }
+
+ fn type_isize(&self) -> Type<'gcc> {
+ self.isize_type
+ }
+
+ fn type_f32(&self) -> Type<'gcc> {
+ self.context.new_type::<f32>()
+ }
+
+ fn type_f64(&self) -> Type<'gcc> {
+ self.context.new_type::<f64>()
+ }
+
+ fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> {
+ self.context.new_function_pointer_type(None, return_type, params, false)
+ }
+
+ fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> {
+ let types = fields.to_vec();
+ if let Some(typ) = self.struct_types.borrow().get(fields) {
+ return typ.clone();
+ }
+ let fields: Vec<_> = fields.iter().enumerate()
+ .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
+ .collect();
+ // TODO(antoyo): use packed.
+ let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
+ self.struct_types.borrow_mut().insert(types, typ);
+ typ
+ }
+
+ fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
+ if typ.is_integral() {
+ TypeKind::Integer
+ }
+ else if typ.is_vector().is_some() {
+ TypeKind::Vector
+ }
+ else {
+ // TODO(antoyo): support other types.
+ TypeKind::Void
+ }
+ }
+
+ fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
+ ty.make_pointer()
+ }
+
+ fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
+ // TODO(antoyo): use address_space
+ ty.make_pointer()
+ }
+
+ fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
+ if let Some(typ) = ty.is_array() {
+ typ
+ }
+ else if let Some(vector_type) = ty.is_vector() {
+ vector_type.get_element_type()
+ }
+ else if let Some(typ) = ty.get_pointee() {
+ typ
+ }
+ else {
+ unreachable!()
+ }
+ }
+
+ fn vector_length(&self, _ty: Type<'gcc>) -> usize {
+ unimplemented!();
+ }
+
+ fn float_width(&self, typ: Type<'gcc>) -> usize {
+ let f32 = self.context.new_type::<f32>();
+ let f64 = self.context.new_type::<f64>();
+ if typ == f32 {
+ 32
+ }
+ else if typ == f64 {
+ 64
+ }
+ else {
+ panic!("Cannot get width of float type {:?}", typ);
+ }
+ // TODO(antoyo): support other sizes.
+ }
+
+ fn int_width(&self, typ: Type<'gcc>) -> u64 {
+ if typ.is_i8(self) || typ.is_u8(self) {
+ 8
+ }
+ else if typ.is_i16(self) || typ.is_u16(self) {
+ 16
+ }
+ else if typ.is_i32(self) || typ.is_u32(self) {
+ 32
+ }
+ else if typ.is_i64(self) || typ.is_u64(self) {
+ 64
+ }
+ else if typ.is_i128(self) || typ.is_u128(self) {
+ 128
+ }
+ else {
+ panic!("Cannot get width of int type {:?}", typ);
+ }
+ }
+
+ fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
+ value.get_type()
+ }
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> {
+ let unit = Integer::approximate_align(self, align);
+ let size = size.bytes();
+ let unit_size = unit.size().bytes();
+ assert_eq!(size % unit_size, 0);
+ self.type_array(self.type_from_integer(unit), size / unit_size)
+ }
+
+ pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) {
+ // TODO(antoyo): use packed.
+ let fields: Vec<_> = fields.iter().enumerate()
+ .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
+ .collect();
+ typ.set_fields(None, &fields);
+ }
+
+ pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
+ self.context.new_opaque_struct_type(None, name)
+ }
+
+ pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
+ if let Some(struct_type) = ty.is_struct() {
+ if struct_type.get_field_count() == 0 {
+ // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
+ // size of usize::MAX in test_binary_search, we workaround this by setting the size to
+ // zero for ZSTs.
+ // FIXME(antoyo): fix gccjit API.
+ len = 0;
+ }
+ }
+
+ // NOTE: see note above. Some other test uses usize::MAX.
+ if len == u64::MAX {
+ len = 0;
+ }
+
+ let len: i32 = len.try_into().expect("array len");
+
+ self.context.new_array_type(None, ty, len)
+ }
+}
+
+pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
+ let field_count = layout.fields.count();
+
+ let mut packed = false;
+ let mut offset = Size::ZERO;
+ let mut prev_effective_align = layout.align.abi;
+ let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
+ for i in layout.fields.index_by_increasing_offset() {
+ let target_offset = layout.fields.offset(i as usize);
+ let field = layout.field(cx, i);
+ let effective_field_align =
+ layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset);
+ packed |= effective_field_align < field.align.abi;
+
+ assert!(target_offset >= offset);
+ let padding = target_offset - offset;
+ let padding_align = prev_effective_align.min(effective_field_align);
+ assert_eq!(offset.align_to(padding_align) + padding, target_offset);
+ result.push(cx.type_padding_filler(padding, padding_align));
+
+ result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box<Type>.
+ offset = target_offset + field.size;
+ prev_effective_align = effective_field_align;
+ }
+ if !layout.is_unsized() && field_count > 0 {
+ if offset > layout.size {
+ bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
+ }
+ let padding = layout.size - offset;
+ let padding_align = prev_effective_align;
+ assert_eq!(offset.align_to(padding_align) + padding, layout.size);
+ result.push(cx.type_padding_filler(padding, padding_align));
+ assert_eq!(result.len(), 1 + field_count * 2);
+ }
+
+ (result, packed)
+}
--- /dev/null
+use std::fmt::Write;
+
+use gccjit::{Struct, Type};
+use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
+use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
+
+use crate::abi::{FnAbiGccExt, GccType};
+use crate::context::CodegenCx;
+use crate::type_::struct_fields;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+ fn type_from_unsigned_integer(&self, i: Integer) -> Type<'gcc> {
+ use Integer::*;
+ match i {
+ I8 => self.type_u8(),
+ I16 => self.type_u16(),
+ I32 => self.type_u32(),
+ I64 => self.type_u64(),
+ I128 => self.type_u128(),
+ }
+ }
+}
+
+pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
+ match layout.abi {
+ Abi::Scalar(_) => bug!("handled elsewhere"),
+ Abi::Vector { ref element, count } => {
+ let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
+ return cx.context.new_vector_type(element, count);
+ },
+ Abi::ScalarPair(..) => {
+ return cx.type_struct(
+ &[
+ layout.scalar_pair_element_gcc_type(cx, 0, false),
+ layout.scalar_pair_element_gcc_type(cx, 1, false),
+ ],
+ false,
+ );
+ }
+ Abi::Uninhabited | Abi::Aggregate { .. } => {}
+ }
+
+ let name = match layout.ty.kind() {
+ // FIXME(eddyb) producing readable type names for trait objects can result
+ // in problematically distinct types due to HRTB and subtyping (see #47638).
+ // ty::Dynamic(..) |
+ ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str
+ if !cx.sess().fewer_names() =>
+ {
+ let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
+ if let (&ty::Adt(def, _), &Variants::Single { index }) =
+ (layout.ty.kind(), &layout.variants)
+ {
+ if def.is_enum() && !def.variants.is_empty() {
+ write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+ }
+ }
+ if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
+ (layout.ty.kind(), &layout.variants)
+ {
+ write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap();
+ }
+ Some(name)
+ }
+ ty::Adt(..) => {
+ // If `Some` is returned then a named struct is created in LLVM. Name collisions are
+ // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that
+ // can improve perf.
+ // FIXME(antoyo): I don't think that's true for libgccjit.
+ Some(String::new())
+ }
+ _ => None,
+ };
+
+ match layout.fields {
+ FieldsShape::Primitive | FieldsShape::Union(_) => {
+ let fill = cx.type_padding_filler(layout.size, layout.align.abi);
+ let packed = false;
+ match name {
+ None => cx.type_struct(&[fill], packed),
+ Some(ref name) => {
+ let gcc_type = cx.type_named_struct(name);
+ cx.set_struct_body(gcc_type, &[fill], packed);
+ gcc_type.as_type()
+ },
+ }
+ }
+ FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count),
+ FieldsShape::Arbitrary { .. } =>
+ match name {
+ None => {
+ let (gcc_fields, packed) = struct_fields(cx, layout);
+ cx.type_struct(&gcc_fields, packed)
+ },
+ Some(ref name) => {
+ let gcc_type = cx.type_named_struct(name);
+ *defer = Some((gcc_type, layout));
+ gcc_type.as_type()
+ },
+ },
+ }
+}
+
+pub trait LayoutGccExt<'tcx> {
+ fn is_gcc_immediate(&self) -> bool;
+ fn is_gcc_scalar_pair(&self) -> bool;
+ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>;
+ fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+ fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
+ fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>;
+ fn gcc_field_index(&self, index: usize) -> u64;
+ fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
+}
+
+impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
+ fn is_gcc_immediate(&self) -> bool {
+ match self.abi {
+ Abi::Scalar(_) | Abi::Vector { .. } => true,
+ Abi::ScalarPair(..) => false,
+ Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(),
+ }
+ }
+
+ fn is_gcc_scalar_pair(&self) -> bool {
+ match self.abi {
+ Abi::ScalarPair(..) => true,
+ Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false,
+ }
+ }
+
+ /// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`.
+ /// The pointee type of the pointer in `PlaceRef` is always this type.
+ /// For sized types, it is also the right LLVM type for an `alloca`
+ /// containing a value of that type, and most immediates (except `bool`).
+ /// Unsized types, however, are represented by a "minimal unit", e.g.
+ /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
+ /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
+ /// If the type is an unsized struct, the regular layout is generated,
+ /// with the inner-most trailing unsized field using the "minimal unit"
+ /// of that field's type - this is useful for taking the address of
+ /// that field and ensuring the struct has the right alignment.
+ //TODO(antoyo): do we still need the set_fields parameter?
+ fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> {
+ if let Abi::Scalar(ref scalar) = self.abi {
+ // Use a different cache for scalars because pointers to DSTs
+ // can be either fat or thin (data pointers of fat pointers).
+ if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
+ return ty;
+ }
+ let ty =
+ match *self.ty.kind() {
+ ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+ cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields))
+ }
+ ty::Adt(def, _) if def.is_box() => {
+ cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true))
+ }
+ ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())),
+ _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
+ };
+ cx.scalar_types.borrow_mut().insert(self.ty, ty);
+ return ty;
+ }
+
+ // Check the cache.
+ let variant_index =
+ match self.variants {
+ Variants::Single { index } => Some(index),
+ _ => None,
+ };
+ let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();
+ if let Some(ty) = cached_type {
+ let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty);
+ if let Some((struct_type, layout)) = type_to_set_fields {
+ // Since we might be trying to generate a type containing another type which is not
+ // completely generated yet, we deferred setting the fields until now.
+ let (fields, packed) = struct_fields(cx, layout);
+ cx.set_struct_body(struct_type, &fields, packed);
+ }
+ return ty;
+ }
+
+ assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
+
+ // Make sure lifetimes are erased, to avoid generating distinct LLVM
+ // types for Rust types that only differ in the choice of lifetimes.
+ let normal_ty = cx.tcx.erase_regions(self.ty);
+
+ let mut defer = None;
+ let ty =
+ if self.ty != normal_ty {
+ let mut layout = cx.layout_of(normal_ty);
+ if let Some(v) = variant_index {
+ layout = layout.for_variant(cx, v);
+ }
+ layout.gcc_type(cx, true)
+ }
+ else {
+ uncached_gcc_type(cx, *self, &mut defer)
+ };
+
+ cx.types.borrow_mut().insert((self.ty, variant_index), ty);
+
+ if let Some((ty, layout)) = defer {
+ let (fields, packed) = struct_fields(cx, layout);
+ cx.set_struct_body(ty, &fields, packed);
+ }
+
+ ty
+ }
+
+ fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+ if let Abi::Scalar(ref scalar) = self.abi {
+ if scalar.is_bool() {
+ return cx.type_i1();
+ }
+ }
+ self.gcc_type(cx, true)
+ }
+
+ fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> {
+ match scalar.value {
+ Int(i, true) => cx.type_from_integer(i),
+ Int(i, false) => cx.type_from_unsigned_integer(i),
+ F32 => cx.type_f32(),
+ F64 => cx.type_f64(),
+ Pointer => {
+ // If we know the alignment, pick something better than i8.
+ let pointee =
+ if let Some(pointee) = self.pointee_info_at(cx, offset) {
+ cx.type_pointee_for_align(pointee.align)
+ }
+ else {
+ cx.type_i8()
+ };
+ cx.type_ptr_to(pointee)
+ }
+ }
+ }
+
+ fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
+ // TODO(antoyo): remove llvm hack:
+ // HACK(eddyb) special-case fat pointers until LLVM removes
+ // pointee types, to avoid bitcasting every `OperandRef::deref`.
+ match self.ty.kind() {
+ ty::Ref(..) | ty::RawPtr(_) => {
+ return self.field(cx, index).gcc_type(cx, true);
+ }
+ ty::Adt(def, _) if def.is_box() => {
+ let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
+ return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate);
+ }
+ _ => {}
+ }
+
+ let (a, b) = match self.abi {
+ Abi::ScalarPair(ref a, ref b) => (a, b),
+ _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
+ };
+ let scalar = [a, b][index];
+
+ // Make sure to return the same type `immediate_gcc_type` would when
+ // dealing with an immediate pair. This means that `(bool, bool)` is
+ // effectively represented as `{i8, i8}` in memory and two `i1`s as an
+ // immediate, just like `bool` is typically `i8` in memory and only `i1`
+ // when immediate. We need to load/store `bool` as `i8` to avoid
+ // crippling LLVM optimizations or triggering other LLVM bugs with `i1`.
+ // TODO(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1.
+ if scalar.is_bool() {
+ return cx.type_i1();
+ }
+
+ let offset =
+ if index == 0 {
+ Size::ZERO
+ }
+ else {
+ a.value.size(cx).align_to(b.value.align(cx).abi)
+ };
+ self.scalar_gcc_type_at(cx, scalar, offset)
+ }
+
+ fn gcc_field_index(&self, index: usize) -> u64 {
+ match self.abi {
+ Abi::Scalar(_) | Abi::ScalarPair(..) => {
+ bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
+ }
+ _ => {}
+ }
+ match self.fields {
+ FieldsShape::Primitive | FieldsShape::Union(_) => {
+ bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
+ }
+
+ FieldsShape::Array { .. } => index as u64,
+
+ FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
+ }
+ }
+
+ fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> {
+ if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
+ return pointee;
+ }
+
+ let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
+
+ cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
+ result
+ }
+}
+
+impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+ fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
+ layout.gcc_type(self, true)
+ }
+
+ fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
+ layout.immediate_gcc_type(self)
+ }
+
+ fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool {
+ layout.is_gcc_immediate()
+ }
+
+ fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
+ layout.is_gcc_scalar_pair()
+ }
+
+ fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
+ layout.gcc_field_index(index)
+ }
+
+ fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
+ layout.scalar_pair_element_gcc_type(self, index, immediate)
+ }
+
+ fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> {
+ ty.gcc_type(self)
+ }
+
+ fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+ fn_abi.ptr_to_gcc_type(self)
+ }
+
+ fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> {
+ unimplemented!();
+ }
+
+ fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+ // FIXME(antoyo): return correct type.
+ self.type_void()
+ }
+}
--- /dev/null
+#!/bin/bash
+
+# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed?
+
+set -e
+
+if [ -f ./gcc_path ]; then
+ export GCC_PATH=$(cat gcc_path)
+else
+ echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
+ exit 1
+fi
+
+export LD_LIBRARY_PATH="$GCC_PATH"
+export LIBRARY_PATH="$GCC_PATH"
+
+if [[ "$1" == "--release" ]]; then
+ export CHANNEL='release'
+ CARGO_INCREMENTAL=1 cargo rustc --release
+ shift
+else
+ echo $LD_LIBRARY_PATH
+ export CHANNEL='debug'
+ cargo rustc
+fi
+
+source config.sh
+
+function clean() {
+ rm -r target/out || true
+ mkdir -p target/out/gccjit
+}
+
+function mini_tests() {
+ echo "[BUILD] mini_core"
+ $RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE
+
+ echo "[BUILD] example"
+ $RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE
+
+ echo "[AOT] mini_core_hello_world"
+ $RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
+}
+
+function build_sysroot() {
+ echo "[BUILD] sysroot"
+ time ./build_sysroot/build_sysroot.sh
+}
+
+function std_tests() {
+ echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
+ $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
+
+ echo "[AOT] alloc_system"
+ $RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
+
+ echo "[AOT] alloc_example"
+ $RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/alloc_example
+
+ echo "[AOT] dst_field_align"
+ # FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed.
+ $RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
+
+ echo "[AOT] std_example"
+ $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE
+
+ echo "[AOT] subslice-patterns-const-eval"
+ $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
+
+ echo "[AOT] track-caller-attribute"
+ $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE
+ $RUN_WRAPPER ./target/out/track-caller-attribute
+
+ echo "[BUILD] mod_bench"
+ $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE
+}
+
+# FIXME(antoyo): linker gives multiple definitions error on Linux
+#echo "[BUILD] sysroot in release mode"
+#./build_sysroot/build_sysroot.sh --release
+
+# TODO(antoyo): uncomment when it works.
+#pushd simple-raytracer
+#if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
+ #echo "[BENCH COMPILE] ebobby/simple-raytracer"
+ #hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \
+ #"RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \
+ #"../cargo.sh build"
+
+ #echo "[BENCH RUN] ebobby/simple-raytracer"
+ #cp ./target/*/debug/main ./raytracer_cg_gccjit
+ #hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_gccjit
+#else
+ #echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
+ #echo "[COMPILE] ebobby/simple-raytracer"
+ #../cargo.sh build
+ #echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
+#fi
+#popd
+
+function test_libcore() {
+ pushd build_sysroot/sysroot_src/library/core/tests
+ echo "[TEST] libcore"
+ rm -r ./target || true
+ ../../../../../cargo.sh test
+ popd
+}
+
+# TODO(antoyo): uncomment when it works.
+#pushd regex
+#echo "[TEST] rust-lang/regex example shootout-regex-dna"
+#../cargo.sh clean
+## Make sure `[codegen mono items] start` doesn't poison the diff
+#../cargo.sh build --example shootout-regex-dna
+#cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt
+#diff -u res.txt examples/regexdna-output.txt
+
+#echo "[TEST] rust-lang/regex tests"
+#../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options
+#popd
+
+#echo
+#echo "[BENCH COMPILE] mod_bench"
+
+#COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
+#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort"
+
+## Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
+#hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
+
+#echo
+#echo "[BENCH RUN] mod_bench"
+#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_*
+
+function test_rustc() {
+ echo
+ echo "[TEST] rust-lang/rust"
+
+ rust_toolchain=$(cat rust-toolchain)
+
+ git clone https://github.com/rust-lang/rust.git || true
+ cd rust
+ git fetch
+ git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(')
+ export RUSTFLAGS=
+
+ rm config.toml || true
+
+ cat > config.toml <<EOF
+[rust]
+codegen-backends = []
+deny-warnings = false
+
+[build]
+cargo = "$(which cargo)"
+local-rebuild = true
+rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc"
+EOF
+
+ rustc -V | cut -d' ' -f3 | tr -d '('
+ git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') src/test
+
+ for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" src/test/ui); do
+ rm $test
+ done
+
+ git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
+
+ rm -r src/test/ui/{abi*,extern/,llvm-asm/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,simd*,borrowck/,test*,*lto*.rs} || true
+ for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" src/test/ui); do
+ rm $test
+ done
+ git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs
+ git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs
+ rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro.
+
+ RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
+
+ echo "[TEST] rustc test suite"
+ COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS"
+}
+
+function clean_ui_tests() {
+ find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -exec rm -rf {} \;
+}
+
+case $1 in
+ "--test-rustc")
+ test_rustc
+ ;;
+
+ "--test-libcore")
+ test_libcore
+ ;;
+
+ "--clean-ui-tests")
+ clean_ui_tests
+ ;;
+
+ *)
+ clean
+ mini_tests
+ build_sysroot
+ std_tests
+ test_libcore
+ test_rustc
+ ;;
+esac
--- /dev/null
+use std::{
+ env::{self, current_dir},
+ path::PathBuf,
+ process::Command,
+};
+
+use lang_tester::LangTester;
+use tempfile::TempDir;
+
+fn main() {
+ let tempdir = TempDir::new().expect("temp dir");
+ let current_dir = current_dir().expect("current dir");
+ let current_dir = current_dir.to_str().expect("current dir").to_string();
+ let gcc_path = include_str!("../gcc_path");
+ let gcc_path = gcc_path.trim();
+ env::set_var("LD_LIBRARY_PATH", gcc_path);
+ LangTester::new()
+ .test_dir("tests/run")
+ .test_file_filter(|path| path.extension().expect("extension").to_str().expect("to_str") == "rs")
+ .test_extract(|source| {
+ let lines =
+ source.lines()
+ .skip_while(|l| !l.starts_with("//"))
+ .take_while(|l| l.starts_with("//"))
+ .map(|l| &l[2..])
+ .collect::<Vec<_>>()
+ .join("\n");
+ Some(lines)
+ })
+ .test_cmds(move |path| {
+ // Test command 1: Compile `x.rs` into `tempdir/x`.
+ let mut exe = PathBuf::new();
+ exe.push(&tempdir);
+ exe.push(path.file_stem().expect("file_stem"));
+ let mut compiler = Command::new("rustc");
+ compiler.args(&[
+ &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir),
+ "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir),
+ "-Zno-parallel-llvm",
+ "-C", "panic=abort",
+ "-C", "link-arg=-lc",
+ "-o", exe.to_str().expect("to_str"),
+ path.to_str().expect("to_str"),
+ ]);
+ // Test command 2: run `tempdir/x`.
+ let runtime = Command::new(exe);
+ vec![("Compiler", compiler), ("Run-time", runtime)]
+ })
+ .run();
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: signal
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+ use super::Sized;
+
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+/*
+ * Code
+ */
+
+fn test_fail() -> ! {
+ unsafe { intrinsics::abort() };
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ test_fail();
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: signal
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+ use super::Sized;
+
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+/*
+ * Code
+ */
+
+fn fail() -> i32 {
+ unsafe { intrinsics::abort() };
+ 0
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ fail();
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 42
+// 7
+// 5
+// 10
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ pub fn puts(s: *const u8) -> i32;
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+ type Output;
+
+ fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for isize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for u8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i16 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+
+/*
+ * Code
+ */
+
+static mut ONE: usize = 1;
+
+fn make_array() -> [u8; 3] {
+ [42, 10, 5]
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+ let array = [42, 7, 5];
+ let array2 = make_array();
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE - 1]);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE]);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE + 1]);
+
+ libc::printf(b"%d\n\0" as *const u8 as *const i8, array2[argc as usize] as u32);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+
+#![feature(asm, global_asm)]
+
+global_asm!("
+ .global add_asm
+add_asm:
+ mov rax, rdi
+ add rax, rsi
+ ret"
+);
+
+extern "C" {
+ fn add_asm(a: i64, b: i64) -> i64;
+}
+
+fn main() {
+ unsafe {
+ asm!("nop");
+ }
+
+ let x: u64;
+ unsafe {
+ asm!("mov $5, {}",
+ out(reg) x,
+ options(att_syntax)
+ );
+ }
+ assert_eq!(x, 5);
+
+ let x: u64;
+ let input: u64 = 42;
+ unsafe {
+ asm!("mov {input}, {output}",
+ "add $1, {output}",
+ input = in(reg) input,
+ output = out(reg) x,
+ options(att_syntax)
+ );
+ }
+ assert_eq!(x, 43);
+
+ let x: u64;
+ unsafe {
+ asm!("mov {}, 6",
+ out(reg) x,
+ );
+ }
+ assert_eq!(x, 6);
+
+ let x: u64;
+ let input: u64 = 42;
+ unsafe {
+ asm!("mov {output}, {input}",
+ "add {output}, 1",
+ input = in(reg) input,
+ output = out(reg) x,
+ );
+ }
+ assert_eq!(x, 43);
+
+ // check inout(reg_class) x
+ let mut x: u64 = 42;
+ unsafe {
+ asm!("add {0}, {0}",
+ inout(reg) x
+ );
+ }
+ assert_eq!(x, 84);
+
+ // check inout("reg") x
+ let mut x: u64 = 42;
+ unsafe {
+ asm!("add r11, r11",
+ inout("r11") x
+ );
+ }
+ assert_eq!(x, 84);
+
+ // check a mix of
+ // in("reg")
+ // inout(class) x => y
+ // inout (class) x
+ let x: u64 = 702;
+ let y: u64 = 100;
+ let res: u64;
+ let mut rem: u64 = 0;
+ unsafe {
+ asm!("div r11",
+ in("r11") y,
+ inout("eax") x => res,
+ inout("edx") rem,
+ );
+ }
+ assert_eq!(res, 7);
+ assert_eq!(rem, 2);
+
+ // check const
+ let mut x: u64 = 42;
+ unsafe {
+ asm!("add {}, {}",
+ inout(reg) x,
+ const 1
+ );
+ }
+ assert_eq!(x, 43);
+
+ // check const (ATT syntax)
+ let mut x: u64 = 42;
+ unsafe {
+ asm!("add {}, {}",
+ const 1,
+ inout(reg) x,
+ options(att_syntax)
+ );
+ }
+ assert_eq!(x, 43);
+
+ // check sym fn
+ extern "C" fn foo() -> u64 { 42 }
+ let x: u64;
+ unsafe {
+ asm!("call {}", sym foo, lateout("rax") x);
+ }
+ assert_eq!(x, 42);
+
+ // check sym fn (ATT syntax)
+ let x: u64;
+ unsafe {
+ asm!("call {}", sym foo, lateout("rax") x, options(att_syntax));
+ }
+ assert_eq!(x, 42);
+
+ // check sym static
+ static FOO: u64 = 42;
+ let x: u64;
+ unsafe {
+ asm!("mov {1}, qword ptr [rip + {0}]", sym FOO, lateout(reg) x);
+ }
+ assert_eq!(x, 42);
+
+ // check sym static (ATT syntax)
+ let x: u64;
+ unsafe {
+ asm!("movq {0}(%rip), {1}", sym FOO, lateout(reg) x, options(att_syntax));
+ }
+ assert_eq!(x, 42);
+
+ assert_eq!(unsafe { add_asm(40, 2) }, 42);
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// stdout: 2
+// 7 8
+// 10
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn puts(s: *const u8) -> i32;
+ pub fn fflush(stream: *mut i32) -> i32;
+ pub fn printf(format: *const i8, ...) -> i32;
+
+ pub static STDOUT: *mut i32;
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ libc::fflush(libc::STDOUT);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+/*
+ * Code
+ */
+
+fn inc_ref(num: &mut isize) -> isize {
+ *num = *num + 5;
+ *num + 1
+}
+
+fn inc(num: isize) -> isize {
+ num + 1
+}
+
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ argc = inc(argc);
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+ }
+
+ let b = inc_ref(&mut argc);
+ unsafe {
+ libc::printf(b"%ld %ld\n\0" as *const u8 as *const i8, argc, b);
+ }
+
+ argc = 10;
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: Arg: 1
+// Argument: 1
+// String arg: 1
+// Int argument: 2
+// Both args: 11
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics,
+ unboxed_closures)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn puts(s: *const u8) -> i32;
+ pub fn printf(format: *const i8, ...) -> i32;
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+pub trait FnOnce<Args> {
+ #[lang = "fn_once_output"]
+ type Output;
+
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+pub trait FnMut<Args>: FnOnce<Args> {
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ intrinsics::abort();
+ }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ let string = "Arg: %d\n\0";
+ let mut closure = || {
+ unsafe {
+ libc::printf(string as *const str as *const i8, argc);
+ }
+ };
+ closure();
+
+ let mut closure = || {
+ unsafe {
+ libc::printf("Argument: %d\n\0" as *const str as *const i8, argc);
+ }
+ };
+ closure();
+
+ let mut closure = |string| {
+ unsafe {
+ libc::printf(string as *const str as *const i8, argc);
+ }
+ };
+ closure("String arg: %d\n\0");
+
+ let mut closure = |arg: isize| {
+ unsafe {
+ libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg);
+ }
+ };
+ closure(argc + 1);
+
+ let mut closure = |string, arg: isize| {
+ unsafe {
+ libc::printf(string as *const str as *const i8, arg);
+ }
+ };
+ closure("Both args: %d\n\0", argc + 10);
+
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: true
+// 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for u64 {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+impl Copy for bool {}
+impl Copy for u16 {}
+impl Copy for i16 {}
+impl Copy for char {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ pub fn puts(s: *const u8) -> i32;
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+ type Output;
+
+ fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for isize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for u8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i16 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+ fn eq(&self, other: &Rhs) -> bool;
+ fn ne(&self, other: &Rhs) -> bool;
+}
+
+impl PartialEq for u8 {
+ fn eq(&self, other: &u8) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u8) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for u16 {
+ fn eq(&self, other: &u16) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u16) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for u32 {
+ fn eq(&self, other: &u32) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u32) -> bool {
+ (*self) != (*other)
+ }
+}
+
+
+impl PartialEq for u64 {
+ fn eq(&self, other: &u64) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &u64) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for usize {
+ fn eq(&self, other: &usize) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &usize) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for i8 {
+ fn eq(&self, other: &i8) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &i8) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for i32 {
+ fn eq(&self, other: &i32) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &i32) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for isize {
+ fn eq(&self, other: &isize) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &isize) -> bool {
+ (*self) != (*other)
+ }
+}
+
+impl PartialEq for char {
+ fn eq(&self, other: &char) -> bool {
+ (*self) == (*other)
+ }
+ fn ne(&self, other: &char) -> bool {
+ (*self) != (*other)
+ }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+ unsafe {
+ if argc == 1 {
+ libc::printf(b"true\n\0" as *const u8 as *const i8);
+ }
+
+ let string =
+ match argc {
+ 1 => b"1\n\0",
+ 2 => b"2\n\0",
+ 3 => b"3\n\0",
+ 4 => b"4\n\0",
+ 5 => b"5\n\0",
+ _ => b"_\n\0",
+ };
+ libc::printf(string as *const u8 as *const i8);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+
+#![feature(auto_traits, lang_items, no_core, start)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 2
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn exit(status: i32);
+ }
+}
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ unsafe {
+ libc::exit(2);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 1
+
+#![feature(auto_traits, lang_items, no_core, start)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ 1
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ pub fn puts(s: *const u8) -> i32;
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+ type Output;
+
+ fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for isize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for u8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i16 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+
+/*
+ * Code
+ */
+
+fn i16_as_i8(a: i16) -> i8 {
+ a as i8
+}
+
+fn call_func(func: fn(i16) -> i8, param: i16) -> i8 {
+ func(param)
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+ unsafe {
+ let result = call_func(i16_as_i8, argc as i16) as isize;
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, result);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// stdout: Panicking
+// status: signal
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn puts(s: *const u8) -> i32;
+ pub fn fflush(stream: *mut i32) -> i32;
+
+ pub static STDOUT: *mut i32;
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ libc::fflush(libc::STDOUT);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ let int = 9223372036854775807isize;
+ let int = int + argc;
+ int
+}
--- /dev/null
+
+// Compiler:
+//
+// Run-time:
+// stdout: 2
+// 7
+// 6
+// 11
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn puts(s: *const u8) -> i32;
+ pub fn fflush(stream: *mut i32) -> i32;
+ pub fn printf(format: *const i8, ...) -> i32;
+
+ pub static STDOUT: *mut i32;
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ libc::fflush(libc::STDOUT);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+ field: isize,
+}
+
+fn test(num: isize) -> Test {
+ Test {
+ field: num + 1,
+ }
+}
+
+fn update_num(num: &mut isize) {
+ *num = *num + 5;
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ let mut test = test(argc);
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+ }
+ update_num(&mut test.field);
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+ }
+
+ update_num(&mut argc);
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+ }
+
+ let refe = &mut argc;
+ *refe = *refe + 5;
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+ }
+
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// stdout: 41
+// 39
+// 10
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+
+#[lang = "deref"]
+pub trait Deref {
+ type Target: ?Sized;
+
+ fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ pub fn puts(s: *const u8) -> i32;
+ pub fn fflush(stream: *mut i32) -> i32;
+
+ pub static STDOUT: *mut i32;
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ libc::fflush(libc::STDOUT);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+ type Output;
+
+ fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for isize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for u8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i16 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+#[lang = "mul"]
+pub trait Mul<RHS = Self> {
+ type Output;
+
+ #[must_use]
+ fn mul(self, rhs: RHS) -> Self::Output;
+}
+
+impl Mul for u8 {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
+impl Mul for usize {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
+impl Mul for isize {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, 10 * argc);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ pub fn puts(s: *const u8) -> i32;
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+ unsafe {
+ libc::puts("Panicking\0" as *const str as *const u8);
+ intrinsics::abort();
+ }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i8 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for usize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+impl Add for isize {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+ type Output;
+
+ fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for isize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for u8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i8 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+impl Sub for i16 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
+
+/*
+ * Code
+ */
+
+static mut ONE: usize = 1;
+
+fn make_array() -> [u8; 3] {
+ [42, 10, 5]
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+ unsafe {
+ let ptr = ONE as *mut usize;
+ let value = ptr as usize;
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, value);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 10
+// 10
+// 42
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+#[lang = "copy"]
+pub unsafe trait Copy {}
+
+unsafe impl Copy for bool {}
+unsafe impl Copy for u8 {}
+unsafe impl Copy for u16 {}
+unsafe impl Copy for u32 {}
+unsafe impl Copy for u64 {}
+unsafe impl Copy for usize {}
+unsafe impl Copy for i8 {}
+unsafe impl Copy for i16 {}
+unsafe impl Copy for i32 {}
+unsafe impl Copy for isize {}
+unsafe impl Copy for f32 {}
+unsafe impl Copy for char {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ }
+}
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+ (
+ a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+ b as u32,
+ )
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+ let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
+ unsafe {
+ libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, d);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, j);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 5
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+ type Output: ?Sized;
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+impl<T> Index<usize> for [T] {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self[index]
+ }
+}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+ file: &'static str,
+ line: u32,
+ column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+ unsafe {
+ libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ intrinsics::abort();
+ }
+}
+
+mod intrinsics {
+ use super::Sized;
+
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+/*
+ * Code
+ */
+
+static mut TWO: usize = 2;
+
+fn index_slice(s: &[u32]) -> u32 {
+ unsafe {
+ s[TWO]
+ }
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ let array = [42, 7, 5];
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array));
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 10
+// 14
+// 1
+// 12
+// 12
+// 1
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+ use super::Sized;
+
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ }
+}
+
+#[lang = "structural_peq"]
+pub trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+pub trait StructuralEq {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ // Code here does not matter - this is replaced by the
+ // real drop glue by the compiler.
+ drop_in_place(to_drop);
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+ field: isize,
+}
+
+struct WithRef {
+ refe: &'static Test,
+}
+
+static mut CONSTANT: isize = 10;
+
+static mut TEST: Test = Test {
+ field: 12,
+};
+
+static mut TEST2: Test = Test {
+ field: 14,
+};
+
+static mut WITH_REF: WithRef = WithRef {
+ refe: unsafe { &TEST },
+};
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
+ TEST2.field = argc;
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field);
+ WITH_REF.refe = &TEST2;
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST.field);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 1
+// 2
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ }
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+ field: isize,
+}
+
+struct Two {
+ two: isize,
+}
+
+fn one() -> isize {
+ 1
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ let test = Test {
+ field: one(),
+ };
+ let two = Two {
+ two: 2,
+ };
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, two.two);
+ }
+ 0
+}
--- /dev/null
+// Compiler:
+//
+// Run-time:
+// status: 0
+// stdout: 3
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+ #[link(name = "c")]
+ extern "C" {
+ pub fn printf(format: *const i8, ...) -> i32;
+ }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+ let test: (isize, isize, isize) = (3, 1, 4);
+ unsafe {
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0);
+ }
+ 0
+}
}
pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
- // The new pass manager is disabled by default.
- config.new_llvm_pass_manager.unwrap_or(false)
+ // The new pass manager is enabled by default for LLVM >= 13.
+ // This matches Clang, which also enables it since Clang 13.
+ config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0))
}
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
let arg_tys = sig.inputs();
let ret_ty = sig.output();
let name = tcx.item_name(def_id);
- let name_str = &*name.as_str();
let llret_ty = self.layout_of(ret_ty).llvm_type(self);
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
&[args[0].immediate(), y],
)
}
- sym::ctlz_nonzero | sym::cttz_nonzero => {
+ sym::ctlz_nonzero => {
let y = self.const_bool(true);
- let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
+ let llvm_name = &format!("llvm.ctlz.i{}", width);
+ self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
+ }
+ sym::cttz_nonzero => {
+ let y = self.const_bool(true);
+ let llvm_name = &format!("llvm.cttz.i{}", width);
self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
}
sym::ctpop => self.call_intrinsic(
return;
}
- _ if name_str.starts_with("simd_") => {
+ _ if name.as_str().starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
Err(()) => return,
let sig =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
let arg_tys = sig.inputs();
- let name_str = &*name.as_str();
if name == sym::simd_select_bitmask {
let in_ty = arg_tys[0];
));
}
- if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
+ if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
// If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
// If there is no suffix, use the index array length.
let n: u64 = if stripped.is_empty() {
OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty)));
(bx, operand)
}
+ mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
+ let operand = self.codegen_operand(&mut bx, operand);
+ let lloperand = operand.immediate();
+
+ let content_ty = self.monomorphize(content_ty);
+ let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
+ let llty_ptr = bx.cx().backend_type(box_layout);
+
+ let val = bx.pointercast(lloperand, llty_ptr);
+ let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
+ (bx, operand)
+ }
}
}
mir::Rvalue::AddressOf(..) |
mir::Rvalue::Len(..) |
mir::Rvalue::Cast(..) | // (*)
+ mir::Rvalue::ShallowInitBox(..) | // (*)
mir::Rvalue::BinaryOp(..) |
mir::Rvalue::CheckedBinaryOp(..) |
mir::Rvalue::UnaryOp(..) |
self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
}
+ ShallowInitBox(ref operand, _) => {
+ let src = self.eval_operand(operand, None)?;
+ let v = self.read_immediate(&src)?;
+ self.write_immediate(*v, &dest)?;
+ }
+
Cast(cast_kind, ref operand, cast_ty) => {
let src = self.eval_operand(operand, None)?;
let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
+ Rvalue::ShallowInitBox(_, _) => {}
Rvalue::UnaryOp(_, ref operand) => {
let ty = operand.ty(self.body, self.tcx);
return;
}
+ if Some(callee) == tcx.lang_items().exchange_malloc_fn() {
+ self.check_op(ops::HeapAllocation);
+ return;
+ }
+
// `async` blocks get lowered to `std::future::from_generator(/* a closure */)`.
let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn();
if is_async_block {
Rvalue::Use(operand)
| Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_, operand)
- | Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand),
+ | Rvalue::Cast(_, operand, _)
+ | Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
NullOp::AlignOf => {}
},
+ Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
+
Rvalue::UnaryOp(op, operand) => {
match op {
// These operations can never fail.
//! Also computes as the resulting DAG if each SCC is replaced with a
//! node in the graph. This uses [Tarjan's algorithm](
//! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
-//! that completes in *O(n)* time.
+//! that completes in *O*(*n*) time.
use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
pub use index_map::SortedIndexMultiMap;
/// `SortedMap` is a data structure with similar characteristics as BTreeMap but
-/// slightly different trade-offs: lookup, insertion, and removal are O(log(N))
+/// slightly different trade-offs: lookup, insertion, and removal are *O*(log(*n*))
/// and elements can be iterated in order cheaply.
///
/// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it
#[track_caller]
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
- ReadGuard::map(self.value.borrow(), |opt| match *opt {
- None => panic!("attempted to read from stolen value"),
- Some(ref v) => v,
- })
+ let borrow = self.value.borrow();
+ if let None = &*borrow {
+ panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
+ }
+ ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
}
#[track_caller]
use rustc_ast::{token, Attribute, Inline, Item};
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_parse::new_parser_from_file;
+use rustc_parse::validate_attr;
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident};
dir_path: &Path,
) -> Option<PathBuf> {
// Extract path string from first `#[path = "path_string"]` attribute.
- let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str();
+ let first_path = attrs.iter().find(|at| at.has_name(sym::path))?;
+ let path_string = match first_path.value_str() {
+ Some(s) => s.as_str(),
+ None => {
+ // This check is here mainly to catch attempting to use a macro,
+ // such as #[path = concat!(...)]. This isn't currently supported
+ // because otherwise the InvocationCollector would need to defer
+ // loading a module until the #[path] attribute was expanded, and
+ // it doesn't support that (and would likely add a bit of
+ // complexity). Usually bad forms are checked in AstValidator (via
+ // `check_builtin_attribute`), but by the time that runs the macro
+ // is expanded, and it doesn't give an error.
+ validate_attr::emit_fatal_malformed_builtin_attribute(
+ &sess.parse_sess,
+ first_path,
+ sym::path,
+ );
+ }
+ };
// On windows, the base path might have the form
// `\\?\foo\bar` in which case it does not tolerate
}
// Synthesize a new symbol that includes the minus sign.
- let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]);
+ let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
lit = token::Lit::new(lit.kind, symbol, lit.suffix);
}
(accepted, const_fn_union, "1.56.0", Some(51909), None),
/// Allows explicit discriminants on non-unit enum variants.
(accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None),
+ /// Allows macro attributes to observe output of `#[derive]`.
+ (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Lessens the requirements for structs to implement `Unsize`.
(active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
- /// Allows macro attributes to observe output of `#[derive]`.
- (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None),
-
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
self.obligations.push(Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
- predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
- .to_predicate(self.infcx.tcx),
+ predicate: ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+ sup, sub,
+ )))
+ .to_predicate(self.infcx.tcx),
recursion_depth: 0,
});
}
self.obligations.push(Obligation::new(
self.trace.cause.clone(),
self.param_env,
- ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into()))
+ .to_predicate(self.infcx.tcx),
));
}
self.obligations.push(Obligation::new(
self.trace.cause.clone(),
self.param_env,
- predicate.to_predicate(self.tcx()),
+ ty::Binder::dummy(predicate).to_predicate(self.tcx()),
));
}
}
err: &mut DiagnosticBuilder<'tcx>,
cause: &ObligationCause<'tcx>,
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
+ terr: &TypeError<'tcx>,
) {
match cause.code {
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
err.help("...or use `match` instead of `let...else`");
}
- _ => (),
+ _ => {
+ if let ObligationCauseCode::BindingObligation(_, binding_span) =
+ cause.code.peel_derives()
+ {
+ if matches!(terr, TypeError::RegionsPlaceholderMismatch) {
+ err.span_note(*binding_span, "the lifetime requirement is introduced here");
+ }
+ }
+ }
}
}
// It reads better to have the error origin as the final
// thing.
- self.note_error_origin(diag, cause, exp_found);
+ self.note_error_origin(diag, cause, exp_found, terr);
}
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
self.fields.obligations.push(Obligation::new(
self.fields.trace.cause.clone(),
self.fields.param_env,
- ty::PredicateKind::Subtype(ty::SubtypePredicate {
+ ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: self.a_is_expected,
a,
b,
- })
+ }))
.to_predicate(self.tcx()),
));
cause,
recursion_depth: 0,
param_env,
- predicate: trait_ref.without_const().to_predicate(infcx.tcx),
+ predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx),
},
);
}
None
}
})
+ .map(ty::Binder::dummy)
.map(|predicate_kind| predicate_kind.to_predicate(tcx))
.filter(|&predicate| visited.insert(predicate))
.map(|predicate| {
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(internal_output_capture)]
+#![feature(thread_spawn_unchecked)]
#![feature(nll)]
#![feature(once_cell)]
#![recursion_limit = "256"]
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build;
-use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
+use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test};
use rustc_plugin_impl as plugin;
use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
-use rustc_session::Session;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_session::{Limit, Session};
+use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::FileName;
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
sess: &Session,
lint_store: &LintStore,
krate: &ast::Crate,
+ crate_attrs: &[ast::Attribute],
crate_name: &str,
) {
sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
sess,
lint_store,
&krate,
+ crate_attrs,
true,
None,
rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
resolver: &mut Resolver<'_>,
) -> Result<ast::Crate> {
tracing::trace!("configure_and_expand");
- pre_expansion_lint(sess, lint_store, &krate, crate_name);
+ pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name);
rustc_builtin_macros::register_builtin_macros(resolver);
krate = sess.time("crate_injection", || {
// Create the config for macro expansion
let features = sess.features_untracked();
- let recursion_limit =
- rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess);
+ let recursion_limit = get_recursion_limit(&krate.attrs, &sess);
let cfg = rustc_expand::expand::ExpansionConfig {
features: Some(&features),
recursion_limit,
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
};
+ let crate_attrs = krate.attrs.clone();
let extern_mod_loaded = |ident: Ident, attrs, items, span| {
let krate = ast::Crate { attrs, items, span };
- pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str());
+ pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str());
(krate.attrs, krate.items)
};
let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded));
sess,
lint_store,
&krate,
+ &krate.attrs,
false,
Some(std::mem::take(resolver.lint_buffer())),
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
codegen
}
+
+fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
+ if let Some(attr) = krate_attrs
+ .iter()
+ .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none())
+ {
+ // This is here mainly to check for using a macro, such as
+ // #![recursion_limit = foo!()]. That is not supported since that
+ // would require expanding this while in the middle of expansion,
+ // which needs to know the limit before expanding. Otherwise,
+ // validation would normally be caught in AstValidator (via
+ // `check_builtin_attribute`), but by the time that runs the macro
+ // is expanded, and it doesn't give an error.
+ validate_attr::emit_fatal_malformed_builtin_attribute(
+ &sess.parse_sess,
+ attr,
+ sym::recursion_limit,
+ );
+ }
+ rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
+}
use rustc_metadata::dynamic_lib::DynamicLibrary;
#[cfg(parallel_compiler)]
use rustc_middle::ty::tls;
+use rustc_parse::validate_attr;
#[cfg(parallel_compiler)]
use rustc_query_impl::QueryCtxt;
use rustc_resolve::{self, Resolver};
/// for `'static` bounds.
#[cfg(not(parallel_compiler))]
pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
- struct Ptr(*mut ());
- unsafe impl Send for Ptr {}
- unsafe impl Sync for Ptr {}
-
- let mut f = Some(f);
- let run = Ptr(&mut f as *mut _ as *mut ());
- let mut result = None;
- let result_ptr = Ptr(&mut result as *mut _ as *mut ());
-
- let thread = cfg.spawn(move || {
- let _ = (&run, &result_ptr);
- let run = unsafe { (*(run.0 as *mut Option<F>)).take().unwrap() };
- let result = unsafe { &mut *(result_ptr.0 as *mut Option<R>) };
- *result = Some(run());
- });
-
- match thread.unwrap().join() {
- Ok(()) => result.unwrap(),
- Err(p) => panic::resume_unwind(p),
+ // SAFETY: join() is called immediately, so any closure captures are still
+ // alive.
+ match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
+ Ok(v) => v,
+ Err(e) => panic::resume_unwind(e),
}
}
}
pub(crate) fn check_attr_crate_type(
- _sess: &Session,
+ sess: &Session,
attrs: &[ast::Attribute],
lint_buffer: &mut LintBuffer,
) {
);
}
}
+ } else {
+ // This is here mainly to check for using a macro, such as
+ // #![crate_type = foo!()]. That is not supported since the
+ // crate type needs to be known very early in compilation long
+ // before expansion. Otherwise, validation would normally be
+ // caught in AstValidator (via `check_builtin_attribute`), but
+ // by the time that runs the macro is expanded, and it doesn't
+ // give an error.
+ validate_attr::emit_fatal_malformed_builtin_attribute(
+ &sess.parse_sess,
+ a,
+ sym::crate_type,
+ );
}
}
}
sess: &'a Session,
lint_store: &'a LintStore,
krate: &'a ast::Crate,
+ crate_attrs: &'a [ast::Attribute],
buffered: LintBuffer,
warn_about_weird_lints: bool,
) -> EarlyContext<'a> {
sess,
krate,
lint_store,
- builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs),
+ builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs),
buffered,
}
}
sess: &Session,
lint_store: &LintStore,
krate: &ast::Crate,
+ crate_attrs: &[ast::Attribute],
pass: T,
buffered: LintBuffer,
warn_about_weird_lints: bool,
) -> LintBuffer {
let mut cx = EarlyContextAndPass {
- context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints),
+ context: EarlyContext::new(
+ sess,
+ lint_store,
+ krate,
+ crate_attrs,
+ buffered,
+ warn_about_weird_lints,
+ ),
pass,
};
sess: &Session,
lint_store: &LintStore,
krate: &ast::Crate,
+ crate_attrs: &[ast::Attribute],
pre_expansion: bool,
lint_buffer: Option<LintBuffer>,
builtin_lints: T,
let mut buffered = lint_buffer.unwrap_or_default();
if !sess.opts.debugging_opts.no_interleave_lints {
- buffered =
- early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, pre_expansion);
+ buffered = early_lint_crate(
+ sess,
+ lint_store,
+ krate,
+ crate_attrs,
+ builtin_lints,
+ buffered,
+ pre_expansion,
+ );
if !passes.is_empty() {
buffered = early_lint_crate(
sess,
lint_store,
krate,
+ crate_attrs,
EarlyLintPassObjects { lints: &mut passes[..] },
buffered,
false,
sess,
lint_store,
krate,
+ crate_attrs,
EarlyLintPassObjects { lints: slice::from_mut(pass) },
buffered,
pre_expansion && i == 0,
#endif
bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
if (!NoPrepopulatePasses) {
- if (OptLevel == OptimizationLevel::O0) {
+ // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead.
+ // At the same time, the LTO pipelines do support O0 and using them is required.
+ bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
+ if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
/// that `Foo` has a destructor. These rvalues can be optimized
/// away after type-checking and before lowering.
Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
+
+ /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
+ ///
+ /// This is different a normal transmute because dataflow analysis will treat the box
+ /// as initialized but its content as uninitialized.
+ ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
}),
}
}
+
+ ShallowInitBox(ref place, ref ty) => {
+ write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty)
+ }
}
}
}
pub category: ConstraintCategory,
}
+// Make sure this enum doesn't unintentionally grow
+rustc_data_structures::static_assert_size!(ConstraintCategory, 12);
+
/// Outlives-constraints can be categorized to determine whether and why they
/// are interesting (for error reporting). Order of variants indicates sort
/// order of the category, thereby influencing diagnostic output.
OpaqueType,
ClosureUpvar(hir::HirId),
+ /// A constraint from a user-written predicate
+ /// with the provided span, written on the item
+ /// with the given `DefId`
+ Predicate(Span),
+
/// A "boring" constraint (caused by the given location) is one that
/// the user probably doesn't want to see described in diagnostics,
/// because it is kind of an artifact of the type system setup.
tcx.mk_generator(did, substs, movability)
}
},
+ Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
}
}
/// whether its only shallowly initialized (`Rvalue::Box`).
pub fn initialization_state(&self) -> RvalueInitializationState {
match *self {
- Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
+ Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => {
+ RvalueInitializationState::Shallow
+ }
_ => RvalueInitializationState::Deep,
}
}
});
Aggregate(kind, fields.fold_with(folder))
}
+ ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
}
}
}
fields.visit_with(visitor)
}
+ ShallowInitBox(ref op, ty) => {
+ op.visit_with(visitor)?;
+ ty.visit_with(visitor)
+ }
}
}
}
self.visit_operand(operand, location);
}
}
+
+ Rvalue::ShallowInitBox(operand, ty) => {
+ self.visit_operand(operand, location);
+ self.visit_ty(ty, TyContext::Location(location));
+ }
}
}
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
}
-impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> {
- fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
- ty::Binder::dummy(*self)
- }
-}
-
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
}
}
-impl ToPredicate<'tcx> for PredicateKind<'tcx> {
- #[inline(always)]
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- tcx.mk_predicate(Binder::dummy(self))
- }
-}
-
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- PredicateKind::Trait(ty::TraitPredicate {
- trait_ref: self.value,
- constness: self.constness,
- })
- .to_predicate(tcx)
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.value
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
/// are the parameters defined on trait.
- pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> {
- TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) }
+ pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
+ ty::Binder::dummy(TraitRef {
+ def_id,
+ substs: InternalSubsts::identity_for_item(tcx, def_id),
+ })
}
#[inline]
use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use rustc_hir::lang_items::LangItem;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
}
ExprKind::Box { value } => {
let value = &this.thir[value];
+ let tcx = this.tcx;
+
+ // `exchange_malloc` is unsafe but box is safe, so need a new scope.
+ let synth_scope = this.new_source_scope(
+ expr_span,
+ LintLevel::Inherited,
+ Some(Safety::BuiltinUnsafe),
+ );
+ let synth_info = SourceInfo { span: expr_span, scope: synth_scope };
+
+ let size = this.temp(tcx.types.usize, expr_span);
+ this.cfg.push_assign(
+ block,
+ synth_info,
+ size,
+ Rvalue::NullaryOp(NullOp::SizeOf, value.ty),
+ );
+
+ let align = this.temp(tcx.types.usize, expr_span);
+ this.cfg.push_assign(
+ block,
+ synth_info,
+ align,
+ Rvalue::NullaryOp(NullOp::AlignOf, value.ty),
+ );
+
+ // malloc some memory of suitable size and align:
+ let exchange_malloc = Operand::function_handle(
+ tcx,
+ tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
+ ty::List::empty(),
+ expr_span,
+ );
+ let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
+ let success = this.cfg.start_new_block();
+ this.cfg.terminate(
+ block,
+ synth_info,
+ TerminatorKind::Call {
+ func: exchange_malloc,
+ args: vec![Operand::Move(size), Operand::Move(align)],
+ destination: Some((Place::from(storage), success)),
+ cleanup: None,
+ from_hir_call: false,
+ fn_span: expr_span,
+ },
+ );
+ this.diverge_from(block);
+ block = success;
+
// The `Box<T>` temporary created here is not a part of the HIR,
// and therefore is not considered during generator auto-trait
// determination. See the comment about `box` at `yield_in_scope`.
this.schedule_drop_storage_and_value(expr_span, scope, result);
}
- // malloc some memory of suitable type (thus far, uninitialized):
- let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
+ // Transmute `*mut u8` to the box (thus far, uninitialized):
+ let box_ = Rvalue::ShallowInitBox(Operand::Move(Place::from(storage)), value.ty);
this.cfg.push_assign(block, source_info, Place::from(result), box_);
// initialize the box contents:
}
mir::Rvalue::Cast(..)
+ | mir::Rvalue::ShallowInitBox(..)
| mir::Rvalue::Use(..)
| mir::Rvalue::ThreadLocalRef(..)
| mir::Rvalue::Repeat(..)
Rvalue::Use(ref operand)
| Rvalue::Repeat(ref operand, _)
| Rvalue::Cast(_, ref operand, _)
+ | Rvalue::ShallowInitBox(ref operand, _)
| Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs))
| Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
| Rvalue::Repeat(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
+ | Rvalue::ShallowInitBox(..)
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(..) => {}
}
}
Rvalue::Cast(..)
+ | Rvalue::ShallowInitBox(..)
| Rvalue::Use(..)
| Rvalue::Repeat(..)
| Rvalue::Len(..)
| Rvalue::AddressOf(_, _)
| Rvalue::Cast(_, Operand::Constant(_), _)
| Rvalue::NullaryOp(_, _)
+ | Rvalue::ShallowInitBox(_, _)
| Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
// These rvalues make things ambiguous
| Rvalue::ThreadLocalRef(_)
| Rvalue::AddressOf(_, _)
| Rvalue::NullaryOp(_, _)
+ | Rvalue::ShallowInitBox(_, _)
| Rvalue::UnaryOp(_, Operand::Constant(_))
| Rvalue::Cast(_, Operand::Constant(_), _)
=> return None,
self.expect(&token::Not)?; // `!`
let ident = self.parse_ident()?;
+
+ if self.eat(&token::Not) {
+ // Handle macro_rules! foo!
+ let span = self.prev_token.span;
+ self.struct_span_err(span, "macro names aren't followed by a `!`")
+ .span_suggestion(
+ span,
+ "remove the `!`",
+ "".to_owned(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+
let body = self.parse_mac_args()?;
self.eat_semi_for_macro_if_needed(&body);
self.complain_if_pub_macro(vis, true);
use rustc_ast::tokenstream::{DelimSpan, TokenTree};
use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::ParseSess;
// Some special attributes like `cfg` must be checked
// before the generic check, so we skip them here.
let should_skip = |name| name == sym::cfg;
- // Some of previously accepted forms were used in practice,
- // report them as warnings for now.
- let should_warn = |name| {
- name == sym::doc
- || name == sym::ignore
- || name == sym::inline
- || name == sym::link
- || name == sym::test
- || name == sym::bench
- };
match parse_meta(sess, attr) {
Ok(meta) => {
if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
- let error_msg = format!("malformed `{}` attribute input", name);
- let mut msg = "attribute must be of the form ".to_owned();
- let mut suggestions = vec![];
- let mut first = true;
- if template.word {
- first = false;
- let code = format!("#[{}]", name);
- msg.push_str(&format!("`{}`", &code));
- suggestions.push(code);
- }
- if let Some(descr) = template.list {
- if !first {
- msg.push_str(" or ");
- }
- first = false;
- let code = format!("#[{}({})]", name, descr);
- msg.push_str(&format!("`{}`", &code));
- suggestions.push(code);
- }
- if let Some(descr) = template.name_value_str {
- if !first {
- msg.push_str(" or ");
- }
- let code = format!("#[{} = \"{}\"]", name, descr);
- msg.push_str(&format!("`{}`", &code));
- suggestions.push(code);
- }
- if should_warn(name) {
- sess.buffer_lint(
- &ILL_FORMED_ATTRIBUTE_INPUT,
- meta.span,
- ast::CRATE_NODE_ID,
- &msg,
- );
- } else {
- sess.span_diagnostic
- .struct_span_err(meta.span, &error_msg)
- .span_suggestions(
- meta.span,
- if suggestions.len() == 1 {
- "must be of the form"
- } else {
- "the following are the possible correct uses"
- },
- suggestions.into_iter(),
- Applicability::HasPlaceholders,
- )
- .emit();
- }
+ emit_malformed_attribute(sess, attr, name, template);
}
}
Err(mut err) => {
}
}
}
+
+fn emit_malformed_attribute(
+ sess: &ParseSess,
+ attr: &Attribute,
+ name: Symbol,
+ template: AttributeTemplate,
+) {
+ // Some of previously accepted forms were used in practice,
+ // report them as warnings for now.
+ let should_warn = |name| {
+ matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench)
+ };
+
+ let error_msg = format!("malformed `{}` attribute input", name);
+ let mut msg = "attribute must be of the form ".to_owned();
+ let mut suggestions = vec![];
+ let mut first = true;
+ let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" };
+ if template.word {
+ first = false;
+ let code = format!("#{}[{}]", inner, name);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
+ }
+ if let Some(descr) = template.list {
+ if !first {
+ msg.push_str(" or ");
+ }
+ first = false;
+ let code = format!("#{}[{}({})]", inner, name, descr);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
+ }
+ if let Some(descr) = template.name_value_str {
+ if !first {
+ msg.push_str(" or ");
+ }
+ let code = format!("#{}[{} = \"{}\"]", inner, name, descr);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
+ }
+ if should_warn(name) {
+ sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg);
+ } else {
+ sess.span_diagnostic
+ .struct_span_err(attr.span, &error_msg)
+ .span_suggestions(
+ attr.span,
+ if suggestions.len() == 1 {
+ "must be of the form"
+ } else {
+ "the following are the possible correct uses"
+ },
+ suggestions.into_iter(),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+ }
+}
+
+pub fn emit_fatal_malformed_builtin_attribute(
+ sess: &ParseSess,
+ attr: &Attribute,
+ name: Symbol,
+) -> ! {
+ let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2;
+ emit_malformed_attribute(sess, attr, name, template);
+ // This is fatal, otherwise it will likely cause a cascade of other errors
+ // (and an error here is expected to be very rare).
+ FatalError.raise()
+}
candidates.iter().map(|c| path_names_to_string(&c.path)).collect();
path_strings.sort();
+ let core_path_strings =
+ path_strings.drain_filter(|p| p.starts_with("core::")).collect::<Vec<String>>();
+ path_strings.extend(core_path_strings);
path_strings.dedup();
let (determiner, kind) = if candidates.len() == 1 {
self.suggest_using_enum_variant(err, source, def_id, span);
}
- (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
+ (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
let (ctor_def, ctor_vis, fields) =
if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
+ if let PathSource::Expr(Some(parent)) = source {
+ if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
+ bad_struct_syntax_suggestion(def_id);
+ return true;
+ }
+ }
struct_ctor
} else {
bad_struct_syntax_suggestion(def_id);
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(box_patterns)]
+#![feature(drain_filter)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
self.create_stable_hashing_context(),
);
- if let Res::Def(_, _) = res {
- // Gate macro attributes in `#[derive]` output.
- if !self.session.features_untracked().macro_attributes_in_derive_output
- && kind == MacroKind::Attr
- && ext.builtin_name != Some(sym::derive)
- {
- let mut expn_id = parent_scope.expansion;
- loop {
- // Helper attr table is a quick way to determine whether the attr is `derive`.
- if self.helper_attrs.contains_key(&expn_id) {
- feature_err(
- &self.session.parse_sess,
- sym::macro_attributes_in_derive_output,
- path.span,
- "macro attributes in `#[derive]` output are unstable",
- )
- .emit();
- break;
- } else {
- let expn_data = expn_id.expn_data();
- match expn_data.kind {
- ExpnKind::Root
- | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
- break;
- }
- _ => expn_id = expn_data.parent.expect_local(),
- }
- }
- }
- }
- }
-
Ok(ext)
}
pub struct Symbol(SymbolIndex);
rustc_index::newtype_index! {
- pub struct SymbolIndex { .. }
+ struct SymbolIndex { .. }
}
impl Symbol {
self.0.as_u32()
}
- pub fn len(self) -> usize {
- with_session_globals(|session_globals| session_globals.symbol_interner.get(self).len())
- }
-
pub fn is_empty(self) -> bool {
self == kw::Empty
}
--- /dev/null
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ let base = super::solid_base::opts("asp3");
+ Target {
+ llvm_target: "aarch64-unknown-none".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: TargetOptions {
+ linker: Some("aarch64-kmc-elf-gcc".to_owned()),
+ features: "+neon,+fp-armv8".to_string(),
+ relocation_model: RelocModel::Static,
+ disable_redzone: true,
+ max_atomic_width: Some(128),
+ ..base
+ },
+ }
+}
--- /dev/null
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ let base = super::solid_base::opts("asp3");
+ Target {
+ llvm_target: "armv7a-none-eabi".to_string(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+ arch: "arm".to_string(),
+ options: TargetOptions {
+ linker: Some("arm-kmc-eabi-gcc".to_owned()),
+ features: "+v7,+soft-float,+thumb2,-neon".to_string(),
+ relocation_model: RelocModel::Static,
+ disable_redzone: true,
+ max_atomic_width: Some(64),
+ ..base
+ },
+ }
+}
--- /dev/null
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ let base = super::solid_base::opts("asp3");
+ Target {
+ llvm_target: "armv7a-none-eabihf".to_string(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+ arch: "arm".to_string(),
+ options: TargetOptions {
+ linker: Some("arm-kmc-eabi-gcc".to_owned()),
+ features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
+ relocation_model: RelocModel::Static,
+ disable_redzone: true,
+ max_atomic_width: Some(64),
+ ..base
+ },
+ }
+}
mod openbsd_base;
mod redox_base;
mod solaris_base;
+mod solid_base;
mod thumb_base;
mod uefi_msvc_base;
mod vxworks_base;
("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
+ ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3),
+ ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi),
+ ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
+
("mipsel-sony-psp", mipsel_sony_psp),
("mipsel-unknown-none", mipsel_unknown_none),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
--- /dev/null
+use super::FramePointer;
+use crate::spec::TargetOptions;
+
+pub fn opts(kernel: &str) -> TargetOptions {
+ TargetOptions {
+ os: format!("solid_{}", kernel),
+ vendor: "kmc".to_string(),
+ frame_pointer: FramePointer::NonLeaf,
+ has_elf_tls: true,
+ ..Default::default()
+ }
+}
let obligation = traits::Obligation::new(
cause.clone(),
self.param_env,
- trait_ref.without_const().to_predicate(tcx),
+ ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
);
if !self.infcx.predicate_may_hold(&obligation) {
debug!("overloaded_deref_ty: cannot match obligation");
cause: traits::ObligationCause::dummy(),
param_env,
recursion_depth: 0,
- predicate: trait_ref.without_const().to_predicate(self.tcx),
+ predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
};
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
}
let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
// Try to apply the original trait binding obligation by borrowing.
- let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>,
+ let mut try_borrowing = |new_imm_trait_ref: ty::TraitRef<'tcx>,
+ new_mut_trait_ref: ty::TraitRef<'tcx>,
expected_trait_ref: ty::TraitRef<'tcx>,
- mtbl: bool,
blacklist: &[DefId]|
-> bool {
if blacklist.contains(&expected_trait_ref.def_id) {
return false;
}
- let new_obligation = Obligation::new(
+ let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
ObligationCause::dummy(),
param_env,
- new_trait_ref.without_const().to_predicate(self.tcx),
- );
+ ty::Binder::dummy(new_imm_trait_ref).without_const().to_predicate(self.tcx),
+ ));
- if self.predicate_must_hold_modulo_regions(&new_obligation) {
+ let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ ty::Binder::dummy(new_mut_trait_ref).without_const().to_predicate(self.tcx),
+ ));
+
+ if imm_result || mut_result {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
// We have a very specific type of error, where just borrowing this argument
// might solve the problem. In cases like this, the important part is the
// }
// ```
- err.span_suggestion(
- span,
- &format!(
- "consider{} borrowing here",
- if mtbl { " mutably" } else { "" }
- ),
- format!("&{}{}", if mtbl { "mut " } else { "" }, snippet),
- Applicability::MaybeIncorrect,
- );
+ if imm_result && mut_result {
+ err.span_suggestions(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ ["&".to_string(), "&mut ".to_string()].into_iter(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "consider{} borrowing here",
+ if mut_result { " mutably" } else { "" }
+ ),
+ format!("&{}", if mut_result { "mut " } else { "" }),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
return true;
}
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
let new_mut_trait_ref =
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
- if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) {
- return true;
- } else {
- return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
- }
+ return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
} else if let ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ItemObligation(_) = &*code
{
- if try_borrowing(
+ return try_borrowing(
ty::TraitRef::new(trait_ref.def_id, imm_substs),
+ ty::TraitRef::new(trait_ref.def_id, mut_substs),
trait_ref,
- false,
&never_suggest_borrow[..],
- ) {
- return true;
- } else {
- return try_borrowing(
- ty::TraitRef::new(trait_ref.def_id, mut_substs),
- trait_ref,
- true,
- &never_suggest_borrow[..],
- );
- }
+ );
} else {
false
}
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
- let pred = infcx.replace_bound_vars_with_placeholders(binder);
+ let pred =
+ ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
ProcessResult::Changed(mk_pending(vec![
obligation.with(pred.to_predicate(self.selcx.tcx())),
]))
infcx.tcx.def_path_str(def_id)
);
- let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
+ let trait_ref =
+ ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) });
let obligation = Obligation {
param_env,
cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
trait_def_id: DefId,
supertraits_only: bool,
) -> SmallVec<[Span; 1]> {
- let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
+ let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
let predicates = if supertraits_only {
tcx.super_predicates_of(trait_def_id)
} else {
let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
- let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
- ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
- ));
+ let trait_predicate = trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
+ });
- let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref))
+ let mut associated_types = traits::supertraits(tcx, trait_ref)
.flat_map(|super_trait_ref| {
tcx.associated_items(super_trait_ref.def_id())
.in_definition_order()
let param_env = tcx.param_env(method.def_id);
// Self: Unsize<U>
- let unsize_predicate = ty::TraitRef {
+ let unsize_predicate = ty::Binder::dummy(ty::TraitRef {
def_id: unsize_did,
substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
- }
+ })
.without_const()
.to_predicate(tcx);
}
});
- ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx)
+ ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
+ .without_const()
+ .to_predicate(tcx)
};
let caller_bounds: Vec<Predicate<'tcx>> = param_env
// Receiver: DispatchFromDyn<Receiver[Self => U]>
let obligation = {
- let predicate = ty::TraitRef {
+ let predicate = ty::Binder::dummy(ty::TraitRef {
def_id: dispatch_from_dyn_did,
substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
- }
+ })
.without_const()
.to_predicate(tcx);
// Compute supertraits of current trait lazily.
if self.supertraits.is_none() {
- let trait_ref =
- ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
+ let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id);
self.supertraits = Some(
traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
);
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_span::symbol::sym;
use std::collections::BTreeMap;
// to make sure we don't forget to fold the substs regardless.
match *ty.kind() {
- ty::Opaque(def_id, substs) => {
+ // This is really important. While we *can* handle this, this has
+ // severe performance implications for large opaque types with
+ // late-bound regions. See `issue-88862` benchmark.
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),
Reveal::All => {
- // N.b. there is an assumption here all this code can handle
- // escaping bound vars.
-
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
let obligation = Obligation::with_depth(
cause: ObligationCause<'tcx>,
depth: usize,
) -> NormalizedTy<'tcx> {
- let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref();
+ let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx()));
let trait_obligation = Obligation {
cause,
recursion_depth: depth,
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
- let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
+ let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
let _ = selcx.infcx().commit_if_ok(|_| {
let impl_source = match selcx.select(&trait_obligation) {
// Wrap this in a closure so we don't accidentally return from the outer function
let res = (|| match *ty.kind() {
- ty::Opaque(def_id, substs) => {
+ // This is really important. While we *can* handle this, this has
+ // severe performance implications for large opaque types with
+ // late-bound regions. See `issue-88862` benchmark.
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),
Reveal::All => {
- // N.b. there is an assumption here all this code can handle
- // escaping bound vars.
-
let substs = substs.super_fold_with(self);
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
let placeholder_trait_predicate =
self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+ let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
ty::Projection(proj) => (proj.item_def_id, proj.substs),
ty::Opaque(def_id, substs) => (def_id, substs),
obligations.extend(self.infcx.commit_if_ok(|_| {
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value)
+ .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);
obligations.push(Obligation::new(
obligation.cause.clone(),
obligation.param_env,
- ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)
+ ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind))
.to_predicate(self.tcx()),
));
}
);
// We can only make objects from sized types.
- let tr = ty::TraitRef::new(
+ let tr = ty::Binder::dummy(ty::TraitRef::new(
tcx.require_lang_item(LangItem::Sized, None),
tcx.mk_substs_trait(source, &[]),
- );
+ ));
nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
// If the type is `Foo + 'a`, ensure that the type
cause,
param_env,
recursion_depth,
- predicate: trait_ref.without_const().to_predicate(tcx),
+ predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
}
}
new_cause,
depth,
param_env,
- ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
)
}),
);
cause.clone(),
depth,
param_env,
- ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
)
}),
);
cause,
self.recursion_depth,
self.param_env,
- trait_ref.without_const().to_predicate(self.infcx.tcx),
+ ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx),
));
}
}
let obligations = self.nominal_obligations(uv.def.did, substs);
self.out.extend(obligations);
- let predicate = ty::PredicateKind::ConstEvaluatable(
+ let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
ty::Unevaluated::new(uv.def, substs),
- )
+ ))
.to_predicate(self.tcx());
let cause = self.cause(traits::MiscObligation);
self.out.push(traits::Obligation::with_depth(
cause,
self.recursion_depth,
self.param_env,
- ty::PredicateKind::WellFormed(resolved_constant.into())
- .to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(
+ resolved_constant.into(),
+ ))
+ .to_predicate(self.tcx()),
));
}
}
cause,
depth,
param_env,
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r))
- .to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(rty, r),
+ ))
+ .to_predicate(self.tcx()),
));
}
}
cause.clone(),
depth,
param_env,
- ty::PredicateKind::ObjectSafe(did).to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did))
+ .to_predicate(tcx),
)
}));
}
cause,
self.recursion_depth,
param_env,
- ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))
+ .to_predicate(self.tcx()),
));
} else {
// Yes, resolved, proceed with the result.
mod normalize_projection_ty;
mod type_op;
-pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
use rustc_middle::ty::query::Providers;
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
self.prove_predicate(
- ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
+ .to_predicate(self.tcx()),
span,
);
}
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
self.prove_predicate(
- ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
span,
);
Ok(())
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
- type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None);
+ type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy());
Ok(())
})
}
/// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
/// this query can be re-run to better track the span of the obligation cause, and improve the error
/// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>(
+pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>(
infcx: &'a InferCtxt<'a, 'tcx>,
fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
- span: Option<Span>,
+ cause: ObligationCause<'tcx>,
) {
- let cause = if let Some(span) = span {
- ObligationCause::dummy_with_span(span)
- } else {
- ObligationCause::dummy()
- };
let (param_env, ProvePredicate { predicate }) = key.into_parts();
fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
}
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::Limit;
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
let adt_components =
- move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+ move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
// If we don't know a type doesn't need drop, for example if it's a type
// parameter without a `Copy` bound, then we conservatively return that it
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
- let significant_drop_fields =
- move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter());
+ let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
+ tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
+ };
let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
.next()
.is_some();
impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
where
- F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+ F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
I: Iterator<Item = Ty<'tcx>>,
{
type Item = NeedsDropResult<Ty<'tcx>>;
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
// impl then check whether the field types need `Drop`.
ty::Adt(adt_def, substs) => {
- let tys = match (self.adt_components)(adt_def) {
+ let tys = match (self.adt_components)(adt_def, substs) {
Err(e) => return Some(Err(e)),
Ok(tys) => tys,
};
}
}
+enum DtorType {
+ /// Type has a `Drop` but it is considered insignificant.
+ /// Check the query `adt_significant_drop_tys` for understanding
+ /// "significant" / "insignificant".
+ Insignificant,
+
+ /// Type has a `Drop` implentation.
+ Significant,
+}
+
// This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
// ADT has a destructor or if the ADT only has a significant destructor. For
// understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper(
- tcx: TyCtxt<'_>,
+fn adt_drop_tys_helper<'tcx>(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
- adt_has_dtor: impl Fn(&ty::AdtDef) -> bool,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_components = move |adt_def: &ty::AdtDef| {
+ adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+ let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
return Ok(Vec::new().into_iter());
- } else if adt_has_dtor(adt_def) {
- debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
- return Err(AlwaysRequiresDrop);
+ } else if let Some(dtor_info) = adt_has_dtor(adt_def) {
+ match dtor_info {
+ DtorType::Significant => {
+ debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+ return Err(AlwaysRequiresDrop);
+ }
+ DtorType::Insignificant => {
+ debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+
+ // Since the destructor is insignificant, we just want to make sure all of
+ // the passed in type parameters are also insignificant.
+ // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
+ return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
+ }
+ }
} else if adt_def.is_union() {
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
}
fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some();
+ // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
+ // significant.
+ let adt_has_dtor =
+ |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}
def_id: DefId,
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
let adt_has_dtor = |adt_def: &ty::AdtDef| {
- adt_def
- .destructor(tcx)
- .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor))
- .unwrap_or(false)
+ let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
+ if is_marked_insig {
+ // In some cases like `std::collections::HashMap` where the struct is a wrapper around
+ // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
+ // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
+ // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
+ Some(DtorType::Insignificant)
+ } else if adt_def.destructor(tcx).is_some() {
+ // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
+ // significant.
+ Some(DtorType::Significant)
+ } else {
+ // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
+ // treat this as the simple case of Drop impl for type.
+ None
+ }
};
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}
for o in obligations {
match o.predicate.kind().skip_binder() {
ty::PredicateKind::Trait(t) => {
- let pred = ty::PredicateKind::Trait(ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: t.def_id(),
- substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
- },
- constness: t.constness,
- });
+ let pred =
+ ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: t.def_id(),
+ substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
+ },
+ constness: t.constness,
+ }));
let obl = Obligation::new(
o.cause.clone(),
self.param_env,
if borrow {
// Check for &self vs &mut self in the method signature. Since this is either
// the Fn or FnMut trait, it should be one of those.
- let (region, mutbl) =
- if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() {
- (r, mutbl)
- } else {
- span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
- };
+ let (region, mutbl) = if let ty::Ref(r, _, mutbl) =
+ method.sig.inputs()[0].kind()
+ {
+ (r, mutbl)
+ } else {
+ // The `fn`/`fn_mut` lang item is ill-formed, which should have
+ // caused an error elsewhere.
+ self.tcx
+ .sess
+ .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?");
+ return None;
+ };
let mutbl = match mutbl {
hir::Mutability::Not => AutoBorrowMutability::Not,
obligations.push(Obligation::new(
self.cause.clone(),
self.param_env,
- ty::PredicateKind::Coerce(ty::CoercePredicate {
+ ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate {
a: source_ty,
b: target_ty,
- })
+ }))
.to_predicate(self.tcx()),
));
}
self.register_predicate(traits::Obligation::new(
cause,
self.param_env,
- ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx),
));
}
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_trait_selection::traits;
let trait_ref = ty::TraitRef::new(trait_def_id, substs);
// Construct an obligation
- let poly_trait_ref = trait_ref.to_poly_trait_ref();
+ let poly_trait_ref = ty::Binder::dummy(trait_ref);
let obligation = traits::Obligation::misc(
span,
self.body_id,
obligations.push(traits::Obligation::new(
cause,
self.param_env,
- ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
));
let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
use rustc_middle::middle::stability;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{
- self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, assume all super-traits are relevant.
- let bounds = iter::once(trait_ref.to_poly_trait_ref());
+ let bounds = iter::once(ty::Binder::dummy(trait_ref));
self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
trait_ref: ty::TraitRef<'tcx>,
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
let cause = traits::ObligationCause::misc(self.span, self.body_id);
- let predicate = trait_ref.to_poly_trait_ref().to_poly_trait_predicate();
+ let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate();
let obligation = traits::Obligation::new(cause, self.param_env, predicate);
traits::SelectionContext::new(self).select(&obligation)
}
}
}
}
- let predicate = trait_ref.without_const().to_predicate(self.tcx);
+ let predicate =
+ ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
let obligation = traits::Obligation::new(cause, self.param_env, predicate);
if !self.predicate_may_hold(&obligation) {
result = ProbeResult::NoMatch;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::fast_reject::simplify_type;
use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{
- self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, Span};
.into()],
);
let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
- let poly_trait_ref = trait_ref.to_poly_trait_ref();
+ let poly_trait_ref = ty::Binder::dummy(trait_ref);
let obligation = Obligation::misc(
span,
self.body_id,
}
}
- debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
+ debug!(
+ "For closure={:?}, min_captures before sorting={:?}",
+ closure_def_id, root_var_min_capture_list
+ );
+
+ // Now that we have the minimized list of captures, sort the captures by field id.
+ // This causes the closure to capture the upvars in the same order as the fields are
+ // declared which is also the drop order. Thus, in situations where we capture all the
+ // fields of some type, the obserable drop order will remain the same as it previously
+ // was even though we're dropping each capture individually.
+ // See https://github.com/rust-lang/project-rfc-2229/issues/42 and
+ // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`.
+ for (_, captures) in &mut root_var_min_capture_list {
+ captures.sort_by(|capture1, capture2| {
+ for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) {
+ // We do not need to look at the `Projection.ty` fields here because at each
+ // step of the iteration, the projections will either be the same and therefore
+ // the types must be as well or the current projection will be different and
+ // we will return the result of comparing the field indexes.
+ match (p1.kind, p2.kind) {
+ // Paths are the same, continue to next loop.
+ (ProjectionKind::Deref, ProjectionKind::Deref) => {}
+ (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
+ if i1 == i2 => {}
+
+ // Fields are different, compare them.
+ (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => {
+ return i1.cmp(&i2);
+ }
+
+ // We should have either a pair of `Deref`s or a pair of `Field`s.
+ // Anything else is a bug.
+ (
+ l @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
+ r @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
+ ) => bug!(
+ "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})",
+ l,
+ r
+ ),
+ (
+ l
+ @
+ (ProjectionKind::Index
+ | ProjectionKind::Subslice
+ | ProjectionKind::Deref
+ | ProjectionKind::Field(..)),
+ r
+ @
+ (ProjectionKind::Index
+ | ProjectionKind::Subslice
+ | ProjectionKind::Deref
+ | ProjectionKind::Field(..)),
+ ) => bug!(
+ "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
+ l,
+ r
+ ),
+ }
+ }
+
+ unreachable!(
+ "we captured two identical projections: capture1 = {:?}, capture2 = {:?}",
+ capture1, capture2
+ );
+ });
+ }
+
+ debug!(
+ "For closure={:?}, min_captures after sorting={:#?}",
+ closure_def_id, root_var_min_capture_list
+ );
typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
}
};
check_object_unsafe_self_trait_by_name(tcx, &trait_item);
check_associated_item(tcx, trait_item.hir_id(), span, method_sig);
+
+ let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
+ let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+ let encl_trait_def_id = encl_trait.def_id.to_def_id();
+ let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
+ Some("fn")
+ } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
+ Some("fn_mut")
+ } else {
+ None
+ };
+
+ if let (Some(fn_lang_item_name), "call") =
+ (fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str())
+ {
+ // We are looking at the `call` function of the `fn` or `fn_mut` lang item.
+ // Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
+ if let Some(hir::FnSig { decl, span, .. }) = method_sig {
+ if let &[self_ty, _] = &decl.inputs {
+ if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+ tcx.sess
+ .struct_span_err(
+ self_ty.span,
+ &format!(
+ "first argument of `call` in `{}` lang item must be a reference",
+ fn_lang_item_name
+ ),
+ )
+ .emit();
+ }
+ } else {
+ tcx.sess
+ .struct_span_err(
+ *span,
+ &format!(
+ "`call` function in `{}` lang item takes exactly two arguments",
+ fn_lang_item_name
+ ),
+ )
+ .emit();
+ }
+ } else {
+ tcx.sess
+ .struct_span_err(
+ trait_item.span,
+ &format!(
+ "`call` trait item in `{}` lang item must be a function",
+ fn_lang_item_name
+ ),
+ )
+ .emit();
+ }
+ }
}
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
fcx.register_predicate(traits::Obligation::new(
cause,
fcx.param_env,
- ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
discr_substs,
- ))
+ )))
.to_predicate(tcx),
));
}
cause: ObligationCause<'tcx>,
receiver_ty: Ty<'tcx>,
) -> bool {
- let trait_ref = ty::TraitRef {
+ let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: receiver_trait_def_id,
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
- };
+ });
let obligation = traits::Obligation::new(
cause,
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
use rustc_session::lint;
use rustc_session::parse::feature_err;
match item.kind {
ItemKind::Impl(ref impl_) => {
if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id);
+ is_default_impl_trait = tcx
+ .impl_trait_ref(def_id)
+ .map(|trait_ref| ty::Binder::dummy(trait_ref));
}
&impl_.generics
}
// (see below). Recall that a default impl is not itself an impl, but rather a
// set of defaults that can be incorporated into another impl.
if let Some(trait_ref) = is_default_impl_trait {
- predicates.insert((
- trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx),
- tcx.def_span(def_id),
- ));
+ predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
}
// Collect the region predicates that were declared inline as
}
_ => bug!(),
};
- let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
- .to_predicate(icx.tcx);
+ let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+ ty::OutlivesPredicate(r1, r2),
+ ))
+ .to_predicate(icx.tcx);
(pred, span)
}))
assert_eq!(uv.promoted, None);
let span = self.tcx.hir().span(c.hir_id);
self.preds.insert((
- ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx),
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
+ .to_predicate(self.tcx),
span,
));
}
traits::Obligation::new(
cause,
self.param_env,
- ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
+ .to_predicate(self.tcx),
),
);
|(ty::OutlivesPredicate(kind1, region2), &span)| {
match kind1.unpack() {
GenericArgKind::Type(ty1) => Some((
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
- .to_predicate(tcx),
+ ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(ty1, region2),
+ ))
+ .to_predicate(tcx),
span,
)),
GenericArgKind::Lifetime(region1) => Some((
- ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
- region1, region2,
+ ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+ ty::OutlivesPredicate(region1, region2),
))
.to_predicate(tcx),
span,
/// Builds the `type defined here` message.
fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) {
let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
- def_span.into()
+ if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
+ def_span.into()
+ } else {
+ return;
+ }
} else {
return;
};
}
/// The allocator for unique pointers.
-// This function must not unwind. If it does, MIR codegen will fail.
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[lang = "exchange_malloc"]
#[inline]
//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
//! Checking the largest element is *O*(1). Converting a vector to a binary heap
//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
-//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*))
+//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*))
//! in-place heapsort.
//!
//! # Examples
/// This will be a max-heap.
///
/// It is a logic error for an item to be modified in such a way that the
-/// item's ordering relative to any other item, as determined by the `Ord`
+/// item's ordering relative to any other item, as determined by the [`Ord`]
/// trait, changes while it is in the heap. This is normally only possible
-/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The
+/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
/// behavior resulting from such a logic error is not specified, but will
/// not result in undefined behavior. This could include panics, incorrect
/// results, aborts, memory leaks, and non-termination.
///
/// ## Min-heap
///
-/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to
+/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to
/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest
/// value instead of the greatest one.
///
///
/// # Time complexity
///
-/// | [push] | [pop] | [peek]/[peek\_mut] |
-/// |--------|-----------|--------------------|
-/// | O(1)~ | *O*(log(*n*)) | *O*(1) |
+/// | [push] | [pop] | [peek]/[peek\_mut] |
+/// |---------|---------------|--------------------|
+/// | *O*(1)~ | *O*(log(*n*)) | *O*(1) |
///
/// The value for `push` is an expected cost; the method documentation gives a
/// more detailed analysis.
///
+/// [`core::cmp::Reverse`]: core::cmp::Reverse
+/// [`Ord`]: core::cmp::Ord
+/// [`Cell`]: core::cell::Cell
+/// [`RefCell`]: core::cell::RefCell
/// [push]: BinaryHeap::push
/// [pop]: BinaryHeap::pop
/// [peek]: BinaryHeap::peek
/// An owning iterator over the elements of a `BinaryHeap`.
///
/// This `struct` is created by [`BinaryHeap::into_iter()`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: BinaryHeap::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct IntoIter<T> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")]
+#[rustc_insignificant_dtor]
pub struct BTreeMap<K, V> {
root: Option<Root<K, V>>,
length: usize,
/// An owning iterator over the entries of a `BTreeMap`.
///
/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: IntoIterator::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct IntoIter<K, V> {
range: LazyLeafRange<marker::Dying, K, V>,
length: usize,
/// An owning iterator over the items of a `BTreeSet`.
///
/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: BTreeSet#method.into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct IntoIter<T> {
/// let list = LinkedList::from([1, 2, 3]);
/// ```
///
-/// NOTE: It is almost always better to use `Vec` or `VecDeque` because
+/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because
/// array-based containers are generally faster,
/// more memory efficient, and make better use of CPU cache.
+///
+/// [`Vec`]: crate::vec::Vec
+/// [`VecDeque`]: super::vec_deque::VecDeque
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")]
+#[rustc_insignificant_dtor]
pub struct LinkedList<T> {
head: Option<NonNull<Node<T>>>,
tail: Option<NonNull<Node<T>>>,
/// An owning iterator over the elements of a `LinkedList`.
///
/// This `struct` is created by the [`into_iter`] method on [`LinkedList`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: LinkedList::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
/// Returns `true` if the `LinkedList` contains an element equal to the
/// given value.
///
+ /// This operation should compute in *O*(*n*) time.
+ ///
/// # Examples
///
/// ```
/// Provides a reference to the front element, or `None` if the list is
/// empty.
///
+ /// This operation should compute in *O*(1) time.
+ ///
/// # Examples
///
/// ```
/// Provides a mutable reference to the front element, or `None` if the list
/// is empty.
///
+ /// This operation should compute in *O*(1) time.
+ ///
/// # Examples
///
/// ```
/// Provides a reference to the back element, or `None` if the list is
/// empty.
///
+ /// This operation should compute in *O*(1) time.
+ ///
/// # Examples
///
/// ```
/// Provides a mutable reference to the back element, or `None` if the list
/// is empty.
///
+ /// This operation should compute in *O*(1) time.
+ ///
/// # Examples
///
/// ```
/// An owning iterator over the elements of a `VecDeque`.
///
/// This `struct` is created by the [`into_iter`] method on [`VecDeque`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: VecDeque::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<
/// [`make_contiguous`]: VecDeque::make_contiguous
#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct VecDeque<
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
//! provides some helper methods.
//!
//! Additionally, the return value of this function is [`fmt::Result`] which is a
-//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
+//! type alias of <code>[Result]<(), [std::fmt::Error]></code>. Formatting implementations
//! should ensure that they propagate errors from the [`Formatter`] (e.g., when
//! calling [`write!`]). However, they should never return errors spuriously. That
//! is, a formatting implementation must and may only return an error if the
//! it would internally pass around this structure until it has been determined
//! where output should go to.
//!
-//! [`fmt::Result`]: Result
-//! [`Result`]: core::result::Result
-//! [`std::fmt::Error`]: Error
-//! [`write!`]: core::write
-//! [`write`]: core::write
-//! [`format!`]: crate::format
-//! [`to_string`]: crate::string::ToString
-//! [`writeln!`]: core::writeln
+//! [`fmt::Result`]: Result "fmt::Result"
+//! [Result]: core::result::Result "std::result::Result"
+//! [std::fmt::Error]: Error "fmt::Error"
+//! [`write`]: write() "fmt::write"
+//! [`to_string`]: crate::string::ToString::to_string "ToString::to_string"
//! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt
//! [`std::io::Write`]: ../../std/io/trait.Write.html
-//! [`print!`]: ../../std/macro.print.html
-//! [`println!`]: ../../std/macro.println.html
-//! [`eprint!`]: ../../std/macro.eprint.html
-//! [`eprintln!`]: ../../std/macro.eprintln.html
-//! [`format_args!`]: core::format_args
-//! [`fmt::Arguments`]: Arguments
-//! [`format`]: crate::format
+//! [`print!`]: ../../std/macro.print.html "print!"
+//! [`println!`]: ../../std/macro.println.html "println!"
+//! [`eprint!`]: ../../std/macro.eprint.html "eprint!"
+//! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!"
+//! [`fmt::Arguments`]: Arguments "fmt::Arguments"
+//! [`format`]: format() "fmt::format"
#![stable(feature = "rust1", since = "1.0.0")]
/// [get_mut]: Rc::get_mut
#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct Rc<T: ?Sized> {
ptr: NonNull<RcBox<T>>,
phantom: PhantomData<RcBox<T>>,
/// Consumes the `Rc`, returning the wrapped pointer.
///
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
- /// [`Rc::from_raw`][from_raw].
- ///
- /// [from_raw]: Rc::from_raw
+ /// [`Rc::from_raw`].
///
/// # Examples
///
/// and alignment as `T`. This is trivially true if `U` is `T`.
/// Note that if `U` is not `T` but has the same size and alignment, this is
/// basically like transmuting references of different types. See
- /// [`mem::transmute`][transmute] for more information on what
+ /// [`mem::transmute`] for more information on what
/// restrictions apply in this case.
///
/// The user of `from_raw` has to make sure a specific value of `T` is only
/// even if the returned `Rc<T>` is never accessed.
///
/// [into_raw]: Rc::into_raw
- /// [transmute]: core::mem::transmute
///
/// # Examples
///
/// assert!(Rc::ptr_eq(&five, &same_five));
/// assert!(!Rc::ptr_eq(&five, &other_five));
/// ```
- ///
- /// [`ptr::eq`]: core::ptr::eq
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.ptr.as_ptr() == other.ptr.as_ptr()
}
/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the
/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
-/// pointer, which returns an [`Option`]`<`[`Rc`]`<T>>`.
+/// pointer, which returns an <code>[Option]<[Rc]\<T>></code>.
///
/// Since a `Weak` reference does not count towards ownership, it will not
/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no
/// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
/// ```
///
- /// [`null`]: core::ptr::null
+ /// [`null`]: ptr::null
#[stable(feature = "rc_as_ptr", since = "1.45.0")]
pub fn as_ptr(&self) -> *const T {
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
/// let third = Rc::downgrade(&third_rc);
/// assert!(!first.ptr_eq(&third));
/// ```
- ///
- /// [`ptr::eq`]: core::ptr::eq
#[inline]
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
pub fn ptr_eq(&self, other: &Self) -> bool {
/// Constructs a new `Weak<T>`, without allocating any memory.
/// Calling [`upgrade`] on the return value always gives [`None`].
///
- /// [`None`]: Option
/// [`upgrade`]: Weak::upgrade
///
/// # Examples
///
/// # Examples
///
-/// You can create a `String` from [a literal string][`str`] with [`String::from`]:
+/// You can create a `String` from [a literal string][`&str`] with [`String::from`]:
///
/// [`String::from`]: From::from
///
/// println!("The first letter of s is {}", s[0]); // ERROR!!!
/// ```
///
-/// [`OsString`]: ../../std/ffi/struct.OsString.html
+/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString"
///
/// Indexing is intended to be a constant-time operation, but UTF-8 encoding
/// does not allow us to do this. Furthermore, it's not clear what sort of
///
/// # Deref
///
-/// `String`s implement [`Deref`]`<Target=str>`, and so inherit all of [`str`]'s
+/// `String` implements <code>[Deref]<Target = [str]></code>, and so inherits all of [`str`]'s
/// methods. In addition, this means that you can pass a `String` to a
/// function which takes a [`&str`] by using an ampersand (`&`):
///
/// to explicitly extract the string slice containing the string. The second
/// way changes `example_func(&example_string);` to
/// `example_func(&*example_string);`. In this case we are dereferencing a
-/// `String` to a [`str`][`&str`], then referencing the [`str`][`&str`] back to
+/// `String` to a [`str`], then referencing the [`str`] back to
/// [`&str`]. The second way is more idiomatic, however both work to do the
/// conversion explicitly rather than relying on the implicit conversion.
///
///
/// Here, there's no need to allocate more memory inside the loop.
///
-/// [`str`]: prim@str
-/// [`&str`]: prim@str
-/// [`Deref`]: core::ops::Deref
+/// [str]: prim@str "str"
+/// [`str`]: prim@str "str"
+/// [`&str`]: prim@str "&str"
+/// [Deref]: core::ops::Deref "ops::Deref"
+/// [`Deref`]: core::ops::Deref "ops::Deref"
/// [`as_str()`]: String::as_str
#[derive(PartialOrd, Eq, Ord)]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_type")]
/// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error`
/// through the [`utf8_error`] method.
///
-/// [`Utf8Error`]: core::str::Utf8Error
-/// [`std::str`]: core::str
-/// [`&str`]: prim@str
-/// [`utf8_error`]: Self::utf8_error
+/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error"
+/// [`std::str`]: core::str "std::str"
+/// [`&str`]: prim@str "&str"
+/// [`utf8_error`]: FromUtf8Error::utf8_error
///
/// # Examples
///
/// with this error.
///
/// [`from_utf8_unchecked`]: String::from_utf8_unchecked
- /// [`Vec<u8>`]: crate::vec::Vec
- /// [`&str`]: prim@str
+ /// [`Vec<u8>`]: crate::vec::Vec "Vec"
+ /// [`&str`]: prim@str "&str"
/// [`into_bytes`]: String::into_bytes
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// it's already valid UTF-8, we don't need a new allocation. This return
/// type allows us to handle both cases.
///
- /// [`Cow<'a, str>`]: crate::borrow::Cow
+ /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow"
///
/// # Examples
///
/// conversion requires a memory allocation.
///
/// [`from_utf8_lossy`]: String::from_utf8_lossy
- /// [`Cow<'a, str>`]: crate::borrow::Cow
+ /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow"
/// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
///
/// # Examples
unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes());
}
- /// Converts this `String` into a [`Box`]`<`[`str`]`>`.
+ /// Converts this `String` into a <code>[Box]<[str]></code>.
///
/// This will drop any excess capacity.
///
- /// [`str`]: prim@str
+ /// [str]: prim@str "str"
///
/// # Examples
///
/// an analogue to `FromUtf8Error`. See its documentation for more details
/// on using it.
///
- /// [`std::str`]: core::str
- /// [`&str`]: prim@str
+ /// [`std::str`]: core::str "std::str"
+ /// [`&str`]: prim@str "&str"
///
/// # Examples
///
///
/// This alias exists for backwards compatibility, and may be eventually deprecated.
///
-/// [`Infallible`]: core::convert::Infallible
+/// [`Infallible`]: core::convert::Infallible "convert::Infallible"
#[stable(feature = "str_parse_error", since = "1.5.0")]
pub type ParseError = core::convert::Infallible;
/// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant"));
/// ```
///
- /// [`Borrowed`]: crate::borrow::Cow::Borrowed
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed"
#[inline]
fn from(s: &'a str) -> Cow<'a, str> {
Cow::Borrowed(s)
/// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2));
/// ```
///
- /// [`Owned`]: crate::borrow::Cow::Owned
+ /// [`Owned`]: crate::borrow::Cow::Owned "borrow::Cow::Owned"
#[inline]
fn from(s: String) -> Cow<'a, str> {
Cow::Owned(s)
/// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant"));
/// ```
///
- /// [`Borrowed`]: crate::borrow::Cow::Borrowed
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed"
#[inline]
fn from(s: &'a String) -> Cow<'a, str> {
Cow::Borrowed(s.as_str())
/// first: after all, isn't the point of `Arc<T>` thread safety? The key is
/// this: `Arc<T>` makes it thread safe to have multiple ownership of the same
/// data, but it doesn't add thread safety to its data. Consider
-/// `Arc<`[`RefCell<T>`]`>`. [`RefCell<T>`] isn't [`Sync`], and if `Arc<T>` was always
-/// [`Send`], `Arc<`[`RefCell<T>`]`>` would be as well. But then we'd have a problem:
+/// <code>Arc<[RefCell\<T>]></code>. [`RefCell<T>`] isn't [`Sync`], and if `Arc<T>` was always
+/// [`Send`], <code>Arc<[RefCell\<T>]></code> would be as well. But then we'd have a problem:
/// [`RefCell<T>`] is not thread safe; it keeps track of the borrowing count using
/// non-atomic operations.
///
/// [deref]: core::ops::Deref
/// [downgrade]: Arc::downgrade
/// [upgrade]: Weak::upgrade
+/// [RefCell\<T>]: core::cell::RefCell
/// [`RefCell<T>`]: core::cell::RefCell
/// [`std::sync`]: ../../std/sync/index.html
/// [`Arc::clone(&from)`]: Arc::clone
///
/// Sharing a mutable [`AtomicUsize`]:
///
-/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize
+/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize"
///
/// ```no_run
/// use std::sync::Arc;
/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the
/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
-/// pointer, which returns an [`Option`]`<`[`Arc`]`<T>>`.
+/// pointer, which returns an <code>[Option]<[Arc]\<T>></code>.
///
/// Since a `Weak` reference does not count towards ownership, it will not
/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no
/// assert_eq!(*zero, 0)
/// ```
///
- /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+ /// [zeroed]: mem::MaybeUninit::zeroed
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> {
/// assert_eq!(*values, [0, 0, 0])
/// ```
///
- /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+ /// [zeroed]: mem::MaybeUninit::zeroed
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
- /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
+ /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init
///
/// # Examples
///
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
- /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
+ /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init
///
/// # Examples
///
/// assert!(!Arc::ptr_eq(&five, &other_five));
/// ```
///
- /// [`ptr::eq`]: core::ptr::eq
+ /// [`ptr::eq`]: core::ptr::eq "ptr::eq"
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.ptr.as_ptr() == other.ptr.as_ptr()
}
/// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
/// ```
///
- /// [`null`]: core::ptr::null
+ /// [`null`]: core::ptr::null "ptr::null"
#[stable(feature = "weak_into_raw", since = "1.45.0")]
pub fn as_ptr(&self) -> *const T {
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
/// [`new`]: Weak::new
/// [`into_raw`]: Weak::into_raw
/// [`upgrade`]: Weak::upgrade
- /// [`forget`]: std::mem::forget
#[stable(feature = "weak_into_raw", since = "1.45.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
// See Weak::as_ptr for context on how the input pointer is derived.
/// assert!(!first.ptr_eq(&third));
/// ```
///
- /// [`ptr::eq`]: core::ptr::eq
+ /// [`ptr::eq`]: core::ptr::eq "ptr::eq"
#[inline]
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
pub fn ptr_eq(&self, other: &Self) -> bool {
/// let iter: std::vec::IntoIter<_> = v.into_iter();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct IntoIter<
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
//! A contiguous growable array type with heap-allocated contents, written
//! `Vec<T>`.
//!
-//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
-//! `O(1)` pop (from the end).
+//! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and
+//! *O*(1) pop (from the end).
//!
//! Vectors ensure they never allocate more than `isize::MAX` bytes.
//!
/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
/// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only
-/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
-/// details are very subtle — if you intend to allocate memory using a `Vec`
+/// if <code>[mem::size_of::\<T>]\() * [capacity]\() > 0</code>. In general, `Vec`'s allocation
+/// details are very subtle --- if you intend to allocate memory using a `Vec`
/// and use it for something else (either to pass to unsafe code, or to build your
/// own memory-backed collection), be sure to deallocate this memory by using
/// `from_raw_parts` to recover the `Vec` and then dropping it.
/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
/// (as defined by the allocator Rust is configured to use by default), and its
/// pointer points to [`len`] initialized, contiguous elements in order (what
-/// you would see if you coerced it to a slice), followed by [`capacity`]` -
-/// `[`len`] logically uninitialized, contiguous elements.
+/// you would see if you coerced it to a slice), followed by <code>[capacity] - [len]</code>
+/// logically uninitialized, contiguous elements.
///
/// A vector containing the elements `'a'` and `'b'` with capacity 4 can be
/// visualized as below. The top part is the `Vec` struct, it contains a
///
/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
-/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely
+/// <code>[len] == [capacity]</code>. That is, the reported capacity is completely
/// accurate, and can be relied on. It can even be used to manually free the memory
/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
/// when not necessary.
///
/// `vec![x; n]`, `vec![a, b, c, d]`, and
/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
-/// with exactly the requested capacity. If [`len`]` == `[`capacity`],
+/// with exactly the requested capacity. If <code>[len] == [capacity]</code>,
/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
///
/// [`&str`]: type@str
/// [`shrink_to_fit`]: Vec::shrink_to_fit
/// [`shrink_to`]: Vec::shrink_to
+/// [capacity]: Vec::capacity
/// [`capacity`]: Vec::capacity
-/// [`mem::size_of::<T>`]: core::mem::size_of
+/// [mem::size_of::\<T>]: core::mem::size_of
+/// [len]: Vec::len
/// [`len`]: Vec::len
/// [`push`]: Vec::push
/// [`insert`]: Vec::insert
/// [owned slice]: Box
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
+#[rustc_insignificant_dtor]
pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
buf: RawVec<T, A>,
len: usize,
///
/// The removed element is replaced by the last element of the vector.
///
- /// This does not preserve ordering, but is O(1).
+ /// This does not preserve ordering, but is *O*(1).
///
/// # Panics
///
/// A by-value [array] iterator.
#[stable(feature = "array_value_iter", since = "1.51.0")]
+#[rustc_insignificant_dtor]
pub struct IntoIter<T, const N: usize> {
/// This is the array we are iterating over.
///
//! ```
//!
//! An iterator has a method, [`next`], which when called, returns an
-//! [`Option`]`<Item>`. [`next`] will return [`Some(Item)`] as long as there
+//! <code>[Option]\<Item></code>. Calling [`next`] will return [`Some(Item)`] as long as there
//! are elements, and once they've all been exhausted, will return `None` to
//! indicate that iteration is finished. Individual iterators may choose to
//! resume iteration, and so calling [`next`] again may or may not eventually
/// Specifically, `size_hint()` returns a tuple where the first element
/// is the lower bound, and the second element is the upper bound.
///
- /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`.
+ /// The second half of the tuple that is returned is an <code>[Option]<[usize]></code>.
/// A [`None`] here means that either there is no known upper bound, or the
/// upper bound is larger than [`usize`].
///
/// That said, the implementation should provide a correct estimation,
/// because otherwise it would be a violation of the trait's protocol.
///
- /// The default implementation returns `(0, `[`None`]`)` which is correct for any
+ /// The default implementation returns <code>(0, [None])</code> which is correct for any
/// iterator.
///
- /// [`usize`]: type@usize
- ///
/// # Examples
///
/// Basic usage:
/// The returned iterator might panic if the to-be-returned index would
/// overflow a [`usize`].
///
- /// [`usize`]: type@usize
/// [`zip`]: Iterator::zip
///
/// # Examples
/// The relative order of partitioned items is not maintained.
///
/// # Current implementation
+ ///
/// Current algorithms tries finding the first element for which the predicate evaluates
/// to false, and the last element for which it evaluates to true and repeatedly swaps them.
///
- /// Time Complexity: *O*(*N*)
+ /// Time complexity: *O*(*n*)
///
/// See also [`is_partitioned()`] and [`partition()`].
///
//!
//! Rust's pointer types must always point to a valid location; there are
//! no "null" references. Instead, Rust has *optional* pointers, like
-//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
+//! the optional owned box, <code>[Option]<[Box\<T>]></code>.
//!
-//! [`Box<T>`]: ../../std/boxed/struct.Box.html
+//! [Box\<T>]: ../../std/boxed/struct.Box.html
//!
//! The following example uses [`Option`] to create an optional box of
//! [`i32`]. Notice that in order to use the inner [`i32`] value, the
//!
//! ## Adapters for working with references
//!
-//! * [`as_ref`] converts from `&Option<T>` to `Option<&T>`
-//! * [`as_mut`] converts from `&mut Option<T>` to `Option<&mut T>`
-//! * [`as_deref`] converts from `&Option<T>` to `Option<&T::Target>`
-//! * [`as_deref_mut`] converts from `&mut Option<T>` to
-//! `Option<&mut T::Target>`
-//! * [`as_pin_ref`] converts from [`Pin`]`<&Option<T>>` to
-//! `Option<`[`Pin`]`<&T>>`
-//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option<T>>` to
-//! `Option<`[`Pin`]`<&mut T>>`
-//!
+//! * [`as_ref`] converts from <code>[&][][Option]\<T></code> to <code>[Option]<[&]T></code>
+//! * [`as_mut`] converts from <code>[&mut] [Option]\<T></code> to <code>[Option]<[&mut] T></code>
+//! * [`as_deref`] converts from <code>[&][][Option]\<T></code> to
+//! <code>[Option]<[&]T::[Target]></code>
+//! * [`as_deref_mut`] converts from <code>[&mut] [Option]\<T></code> to
+//! <code>[Option]<[&mut] T::[Target]></code>
+//! * [`as_pin_ref`] converts from <code>[Pin]<[&][][Option]\<T>></code> to
+//! <code>[Option]<[Pin]<[&]T>></code>
+//! * [`as_pin_mut`] converts from <code>[Pin]<[&mut] [Option]\<T>></code> to
+//! <code>[Option]<[Pin]<[&mut] T>></code>
+//!
+//! [&]: reference "shared reference"
+//! [&mut]: reference "mutable reference"
+//! [Target]: Deref::Target "ops::Deref::Target"
//! [`as_deref`]: Option::as_deref
//! [`as_deref_mut`]: Option::as_deref_mut
//! [`as_mut`]: Option::as_mut
///
/// # Examples
///
- /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
- /// The [`map`] method takes the `self` argument by value, consuming the original,
+ /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, preserving
+ /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
/// so this technique uses `as_ref` to first take an `Option` to a reference
/// to the value inside the original.
///
/// [`map`]: Option::map
- /// [`String`]: ../../std/string/struct.String.html
+ /// [String]: ../../std/string/struct.String.html "String"
///
/// ```
/// let text: Option<String> = Some("Hello, world!".to_string());
}
}
- /// Converts from [`Pin`]`<&Option<T>>` to `Option<`[`Pin`]`<&T>>`.
+ /// Converts from <code>[Pin]<[&]Option\<T>></code> to <code>Option<[Pin]<[&]T>></code>.
+ ///
+ /// [&]: reference "shared reference"
#[inline]
#[stable(feature = "pin", since = "1.33.0")]
pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
}
- /// Converts from [`Pin`]`<&mut Option<T>>` to `Option<`[`Pin`]`<&mut T>>`.
+ /// Converts from <code>[Pin]<[&mut] Option\<T>></code> to <code>Option<[Pin]<[&mut] T>></code>.
+ ///
+ /// [&mut]: reference "mutable reference"
#[inline]
#[stable(feature = "pin", since = "1.33.0")]
pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
///
/// # Examples
///
- /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original:
+ /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, consuming
+ /// the original:
///
- /// [`String`]: ../../std/string/struct.String.html
+ /// [String]: ../../std/string/struct.String.html "String"
/// ```
/// let maybe_some_string = Some(String::from("Hello, World!"));
/// // `Option::map` takes self *by value*, consuming `maybe_some_string`
impl<T, E> Option<Result<T, E>> {
/// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`.
///
- /// [`None`] will be mapped to [`Ok`]`(`[`None`]`)`.
- /// [`Some`]`(`[`Ok`]`(_))` and [`Some`]`(`[`Err`]`(_))` will be mapped to
- /// [`Ok`]`(`[`Some`]`(_))` and [`Err`]`(_)`.
+ /// [`None`] will be mapped to <code>[Ok]\([None])</code>.
+ /// <code>[Some]\([Ok]\(\_))</code> and <code>[Some]\([Err]\(\_))</code> will be mapped to
+ /// <code>[Ok]\([Some]\(\_))</code> and <code>[Err]\(\_)</code>.
///
/// # Examples
///
///
/// # Examples
///
- /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
- /// The [`map`] method takes the `self` argument by value, consuming the original,
- /// so this technique uses `from` to first take an `Option` to a reference
+ /// Converts an <code>[Option]<[String]></code> into an <code>[Option]<[usize]></code>, preserving
+ /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
+ /// so this technique uses `from` to first take an [`Option`] to a reference
/// to the value inside the original.
///
/// [`map`]: Option::map
- /// [`String`]: ../../std/string/struct.String.html
+ /// [String]: ../../std/string/struct.String.html "String"
///
/// ```
/// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push"
//! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc"
//! [RefCell]: crate::cell::RefCell "cell::RefCell"
-//! [`drop`]: Drop::drop "Drop::drop"
+//! [`drop`]: Drop::drop
//! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque"
//! [`ptr::write`]: crate::ptr::write "ptr::write"
//! [`Future`]: crate::future::Future "future::Future"
//! [drop-impl]: #drop-implementation
//! [drop-guarantee]: #drop-guarantee
//! [`poll`]: crate::future::Future::poll "future::Future::poll"
-//! [&]: ../../std/primitive.reference.html "shared reference"
-//! [&mut]: ../../std/primitive.reference.html "mutable reference"
+//! [&]: reference "shared reference"
+//! [&mut]: reference "mutable reference"
//! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
#![stable(feature = "pin", since = "1.33.0")]
//! ```
//!
//! *Note: The actual definition of [`Write`] uses [`io::Result`], which
-//! is just a synonym for [`Result`]`<T, `[`io::Error`]`>`.*
+//! is just a synonym for <code>[Result]<T, [io::Error]></code>.*
//!
//! This method doesn't produce a value, but the write may
//! fail. It's crucial to handle the error case, and *not* write
//! early return of [`Err`] that it provides.
//!
//! [`expect`]: Result::expect
-//! [`Write`]: ../../std/io/trait.Write.html
-//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all
-//! [`io::Result`]: ../../std/io/type.Result.html
+//! [`Write`]: ../../std/io/trait.Write.html "io::Write"
+//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all "io::Write::write_all"
+//! [`io::Result`]: ../../std/io/type.Result.html "io::Result"
//! [`?`]: crate::ops::Try
//! [`Ok(T)`]: Ok
//! [`Err(E)`]: Err
-//! [`io::Error`]: ../../std/io/struct.Error.html
+//! [io::Error]: ../../std/io/struct.Error.html "io::Error"
//!
//! # Method overview
//!
/// Specifically, `size_hint()` returns a tuple where the first element
/// is the lower bound, and the second element is the upper bound.
///
- /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`.
+ /// The second half of the tuple that is returned is an <code>[Option]<[usize]></code>.
/// A [`None`] here means that either there is no known upper bound, or the
/// upper bound is larger than [`usize`].
///
/// That said, the implementation should provide a correct estimation,
/// because otherwise it would be a violation of the trait's protocol.
///
- /// The default implementation returns `(0, `[`None`]`)` which is correct for any
+ /// The default implementation returns <code>(0, [None])</code> which is correct for any
/// stream.
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
///
/// # Examples
///
- /// Converts a `Poll<`[`String`]`>` into an `Poll<`[`usize`]`>`, consuming the original:
+ /// Converts a <code>Poll<[String]></code> into a <code>Poll<[usize]></code>, consuming
+ /// the original:
///
- /// [`String`]: ../../std/string/struct.String.html
+ /// [String]: ../../std/string/struct.String.html "String"
/// ```
/// # use core::task::Poll;
/// let poll_some_string = Poll::Ready(String::from("Hello, World!"));
libc::abort();
}
} else if #[cfg(any(target_os = "hermit",
+ target_os = "solid_asp3",
all(target_vendor = "fortanix", target_env = "sgx")
))] {
unsafe fn abort() -> ! {
} else if #[cfg(any(
all(target_family = "windows", target_env = "gnu"),
target_os = "psp",
+ target_os = "solid_asp3",
all(target_family = "unix", not(target_os = "espidf")),
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
std_detect_file_io = ["std_detect/std_detect_file_io"]
std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"]
+std_detect_env_override = ["std_detect/std_detect_env_override"]
[package.metadata.fortanix-sgx]
# Maximum possible number of threads when testing
|| target.contains("wasm32")
|| target.contains("asmjs")
|| target.contains("espidf")
+ || target.contains("solid")
{
// These platforms don't have any special requirements.
} else {
#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct HashMap<K, V, S = RandomState> {
base: base::HashMap<K, V, S>,
}
/// An owning iterator over the entries of a `HashMap`.
///
/// This `struct` is created by the [`into_iter`] method on [`HashMap`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: IntoIterator::into_iter
+/// [`IntoIterator`]: crate::iter::IntoIterator
///
/// # Example
///
/// An owning iterator over the items of a `HashSet`.
///
/// This `struct` is created by the [`into_iter`] method on [`HashSet`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: IntoIterator::into_iter
+/// [`IntoIterator`]: crate::iter::IntoIterator
///
/// # Examples
///
//!
//! ## Sequences
//!
-//! | | get(i) | insert(i) | remove(i) | append | split_off(i) |
-//! |----------------|----------------|-----------------|----------------|--------|----------------|
-//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) |
-//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) |
-//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) |
+//! | | get(i) | insert(i) | remove(i) | append | split_off(i) |
+//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------|
+//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) |
+//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) |
+//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) |
//!
//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and
//! [`VecDeque`] is generally going to be faster than [`LinkedList`].
//!
//! For Sets, all operations have the cost of the equivalent Map operation.
//!
-//! | | get | insert | remove | range | append |
-//! |--------------|-----------|-----------|-----------|-----------|--------|
-//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A |
-//! | [`BTreeMap`] | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) | O(n+m) |
+//! | | get | insert | remove | range | append |
+//! |--------------|---------------|---------------|---------------|---------------|--------------|
+//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A |
+//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) |
//!
//! # Correct and Efficient Usage of Collections
//!
//! contents by-value. This is great when the collection itself is no longer
//! needed, and the values are needed elsewhere. Using `extend` with `into_iter`
//! is the main way that contents of one collection are moved into another.
-//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`].
+//! `extend` automatically calls `into_iter`, and takes any <code>T: [IntoIterator]</code>.
//! Calling `collect` on an iterator itself is also a great way to convert one
//! collection into another. Both of these methods should internally use the
//! capacity management tools discussed in the previous section to do this as
//! assert_eq!(map.keys().next().unwrap().b, "baz");
//! ```
//!
-//! [`IntoIterator`]: crate::iter::IntoIterator
+//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator"
#![stable(feature = "rust1", since = "1.0.0")]
/// type is a static guarantee that the underlying bytes contain no interior 0
/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
///
-/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former
+/// `CString` is to <code>&[CStr]</code> as [`String`] is to <code>&[str]</code>: the former
/// in each pair are owned strings; the latter are borrowed
/// references.
///
/// # Creating a `CString`
///
/// A `CString` is created from either a byte slice or a byte vector,
-/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// or anything that implements <code>[Into]<[Vec]<[u8]>></code> (for
/// example, you can build a `CString` straight out of a [`String`] or
-/// a [`&str`], since both implement that trait).
+/// a <code>&[str]</code>, since both implement that trait).
///
-/// The [`CString::new`] method will actually check that the provided `&[u8]`
+/// The [`CString::new`] method will actually check that the provided <code>&[[u8]]</code>
/// does not have 0 bytes in the middle, and return an error if it
/// finds one.
///
///
/// # Extracting a slice of the whole C string
///
-/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// Alternatively, you can obtain a <code>&[[u8]]</code> slice from a
/// `CString` with the [`CString::as_bytes`] method. Slices produced in this
/// way do *not* contain the trailing nul terminator. This is useful
/// when you will be calling an extern function that takes a `*const
/// You can of course get the slice's length with its
/// [`len`][slice::len] method.
///
-/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// If you need a <code>&[[u8]]</code> slice *with* the nul terminator, you
/// can use [`CString::as_bytes_with_nul`] instead.
///
/// Once you have the kind of slice you need (with or without a nul
/// extern functions. See the documentation for that function for a
/// discussion on ensuring the lifetime of the raw pointer.
///
-/// [`&str`]: prim@str
+/// [str]: prim@str "str"
/// [`Deref`]: ops::Deref
-/// [`&CStr`]: CStr
///
/// # Examples
///
/// Representation of a borrowed C string.
///
/// This type represents a borrowed reference to a nul-terminated
-/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
/// slice, or unsafely from a raw `*const c_char`. It can then be
-/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
/// into an owned [`CString`].
///
-/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
/// in each pair are borrowed references; the latter are owned
/// strings.
///
/// println!("string: {}", my_string_safe());
/// ```
///
-/// [`&str`]: prim@str
+/// [str]: prim@str "str"
#[derive(Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
#[stable(feature = "rust1", since = "1.0.0")]
unsafe { ptr::read(&this.inner) }
}
- /// Converts a [`Vec`]`<u8>` to a [`CString`] without checking the
+ /// Converts a <code>[Vec]<[u8]></code> to a [`CString`] without checking the
/// invariants on the given [`Vec`].
///
/// # Safety
Self { inner: v.into_boxed_slice() }
}
- /// Attempts to converts a [`Vec`]`<u8>` to a [`CString`].
+ /// Attempts to converts a <code>[Vec]<[u8]></code> to a [`CString`].
///
/// Runtime checks are present to ensure there is only one nul byte in the
/// [`Vec`], its last element.
#[stable(feature = "cstring_into", since = "1.7.0")]
impl From<CString> for Vec<u8> {
- /// Converts a [`CString`] into a [`Vec`]`<u8>`.
+ /// Converts a [`CString`] into a <code>[Vec]<[u8]></code>.
///
/// The conversion consumes the [`CString`], and removes the terminating NUL byte.
#[inline]
#[stable(feature = "c_string_from_box", since = "1.18.0")]
impl From<Box<CStr>> for CString {
- /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+ /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
#[inline]
fn from(s: Box<CStr>) -> CString {
s.into_c_string()
#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")]
impl From<Vec<NonZeroU8>> for CString {
- /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without
+ /// Converts a <code>[Vec]<[NonZeroU8]></code> into a [`CString`] without
/// copying nor checking for inner null bytes.
#[inline]
fn from(v: Vec<NonZeroU8>) -> CString {
#[stable(feature = "box_from_c_string", since = "1.20.0")]
impl From<CString> for Box<CStr> {
- /// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating.
+ /// Converts a [`CString`] into a <code>[Box]<[CStr]></code> without copying or allocating.
#[inline]
fn from(s: CString) -> Box<CStr> {
s.into_boxed_c_str()
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Arc<CStr> {
- /// Converts a [`CString`] into an [`Arc`]`<CStr>` without copying or allocating.
+ /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> without copying or allocating.
#[inline]
fn from(s: CString) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner());
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Rc<CStr> {
- /// Converts a [`CString`] into an [`Rc`]`<CStr>` without copying or allocating.
+ /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> without copying or allocating.
#[inline]
fn from(s: CString) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner());
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
}
- /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
+ /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
///
/// If the contents of the `CStr` are valid UTF-8 data, this
- /// function will return the corresponding [`&str`] slice. Otherwise,
+ /// function will return the corresponding <code>&[str]</code> slice. Otherwise,
/// it will return an error with details of where UTF-8 validation failed.
///
- /// [`&str`]: prim@str
+ /// [str]: prim@str "str"
///
/// # Examples
///
str::from_utf8(self.to_bytes())
}
- /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
+ /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
///
/// If the contents of the `CStr` are valid UTF-8 data, this
- /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
- /// with the corresponding [`&str`] slice. Otherwise, it will
+ /// function will return a <code>[Cow]::[Borrowed]\(&[str])</code>
+ /// with the corresponding <code>&[str]</code> slice. Otherwise, it will
/// replace any invalid UTF-8 sequences with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
- /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
+ /// <code>[Cow]::[Owned]\(&[str])</code> with the result.
///
- /// [`str`]: primitive@str
- /// [`&str`]: primitive@str
- /// [`Borrowed`]: Cow::Borrowed
- /// [`Owned`]: Cow::Owned
- /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
+ /// [str]: prim@str "str"
+ /// [Borrowed]: Cow::Borrowed
+ /// [Owned]: Cow::Owned
+ /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
///
/// # Examples
///
String::from_utf8_lossy(self.to_bytes())
}
- /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+ /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
///
/// # Examples
///
//! terminator, so the buffer length is really `len+1` characters.
//! Rust strings don't have a nul terminator; their length is always
//! stored and does not need to be calculated. While in Rust
-//! accessing a string's length is a `O(1)` operation (because the
-//! length is stored); in C it is an `O(length)` operation because the
+//! accessing a string's length is an *O*(1) operation (because the
+//! length is stored); in C it is an *O*(*n*) operation because the
//! length needs to be computed by scanning the string for the nul
//! terminator.
//!
//! string: it is nul-terminated, and has no internal nul characters.
//! Rust code can create a [`CString`] out of a normal string (provided
//! that the string doesn't have nul characters in the middle), and
-//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can
+//! then use a variety of methods to obtain a raw <code>\*mut [u8]</code> that can
//! then be passed as an argument to functions which use the C
//! conventions for strings.
//!
//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
-//! is what you would use to wrap a raw `*const `[`u8`] that you got from
+//! is what you would use to wrap a raw <code>\*const [u8]</code> that you got from
//! a C function. A [`CStr`] is guaranteed to be a nul-terminated array
//! of bytes. Once you have a [`CStr`], you can convert it to a Rust
-//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding
+//! <code>&[str]</code> if it's valid UTF-8, or lossily convert it by adding
//! replacement characters.
//!
//! [`OsString`] and [`OsStr`] are useful when you need to transfer
//! library, various APIs that transfer strings to/from the operating
//! system use [`OsString`] instead of plain strings. For example,
//! [`env::var_os()`] is used to query environment variables; it
-//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable
-//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to
-//! convert to a Rust string. This yields a [`Result`], so that
+//! returns an <code>[Option]<[OsString]></code>. If the environment variable
+//! exists you will get a <code>[Some]\(os_string)</code>, which you can
+//! *then* try to convert to a Rust string. This yields a [`Result`], so that
//! your code can detect errors in case the environment variable did
//! not in fact contain valid Unicode data.
//!
//! ## On Unix
//!
//! On Unix, [`OsStr`] implements the
-//! `std::os::unix::ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
+//! <code>std::os::unix::ffi::[OsStrExt][unix.OsStrExt]</code> trait, which
//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
//! These do inexpensive conversions from and to UTF-8 byte slices.
//!
//! Additionally, on Unix [`OsString`] implements the
-//! `std::os::unix::ffi::`[`OsStringExt`][unix.OsStringExt] trait,
+//! <code>std::os::unix::ffi::[OsStringExt][unix.OsStringExt]</code> trait,
//! which provides [`from_vec`] and [`into_vec`] methods that consume
//! their arguments, and take or produce vectors of [`u8`].
//!
//! ## On Windows
//!
//! On Windows, [`OsStr`] implements the
-//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
+//! <code>std::os::windows::ffi::[OsStrExt][windows.OsStrExt]</code> trait,
//! which provides an [`encode_wide`] method. This provides an
//! iterator that can be [`collect`]ed into a vector of [`u16`].
//!
//! Additionally, on Windows [`OsString`] implements the
-//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
+//! <code>std::os::windows:ffi::[OsStringExt][windows.OsStringExt]</code>
//! trait, which provides a [`from_wide`] method. The result of this
//! method is an [`OsString`] which can be round-tripped to a Windows
//! string losslessly.
//!
//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
-//! [`env::set_var()`]: crate::env::set_var
-//! [`env::var_os()`]: crate::env::var_os
-//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt
-//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec
-//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec
-//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt
-//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes
-//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes
-//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt
-//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt
-//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide
-//! [`collect`]: crate::iter::Iterator::collect
-//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt
-//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide
+//! [`env::set_var()`]: crate::env::set_var "env::set_var"
+//! [`env::var_os()`]: crate::env::var_os "env::var_os"
+//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt "os::unix::ffi::OsStringExt"
+//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec "os::unix::ffi::OsStringExt::from_vec"
+//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec "os::unix::ffi::OsStringExt::into_vec"
+//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt"
+//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes "os::unix::ffi::OsStrExt::from_bytes"
+//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes "os::unix::ffi::OsStrExt::as_bytes"
+//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt"
+//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt "os::windows::ffi::OsStrExt"
+//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide "os::windows::ffi::OsStrExt::encode_wide"
+//! [`collect`]: crate::iter::Iterator::collect "iter::Iterator::collect"
+//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt"
+//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide"
#![stable(feature = "rust1", since = "1.0.0")]
/// of this is that `OsString` instances are *not* `NUL` terminated; in order
/// to pass to e.g., Unix system call, you should create a [`CStr`].
///
-/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former
+/// `OsString` is to <code>&[OsStr]</code> as [`String`] is to <code>&[str]</code>: the former
/// in each pair are owned strings; the latter are borrowed
/// references.
///
/// # Creating an `OsString`
///
/// **From a Rust string**: `OsString` implements
-/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to
+/// <code>[From]<[String]></code>, so you can use <code>my_string.[into]\()</code> to
/// create an `OsString` from a normal Rust string.
///
/// **From slices:** Just like you can start with an empty Rust
-/// [`String`] and then [`String::push_str`] `&str`
+/// [`String`] and then [`String::push_str`] some <code>&[str]</code>
/// sub-string slices into it, you can create an empty `OsString` with
/// the [`OsString::new`] method and then push string slices into it with the
/// [`OsString::push`] method.
///
/// # Extracting a borrowed reference to the whole OS string
///
-/// You can use the [`OsString::as_os_str`] method to get an `&`[`OsStr`] from
+/// You can use the [`OsString::as_os_str`] method to get an <code>&[OsStr]</code> from
/// an `OsString`; this is effectively a borrowed reference to the
/// whole string.
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
/// the traits which `OsString` implements for [conversions] from/to native representations.
///
-/// [`&OsStr`]: OsStr
-/// [`&str`]: str
/// [`CStr`]: crate::ffi::CStr
/// [conversions]: super#conversions
+/// [into]: Into::into
#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsString {
/// This type represents a borrowed reference to a string in the operating system's preferred
/// representation.
///
-/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed
-/// references; the latter are owned strings.
+/// `&OsStr` is to [`OsString`] as <code>&[str]</code> is to [`String`]: the
+/// former in each pair are borrowed references; the latter are owned strings.
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
/// the traits which `OsStr` implements for [conversions] from/to native representations.
///
-/// [`&str`]: str
/// [conversions]: super#conversions
#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
#[stable(feature = "rust1", since = "1.0.0")]
self.inner.into_string().map_err(|buf| OsString { inner: buf })
}
- /// Extends the string with the given [`&OsStr`] slice.
- ///
- /// [`&OsStr`]: OsStr
+ /// Extends the string with the given <code>&[OsStr]</code> slice.
///
/// # Examples
///
unsafe { &mut *(inner as *mut Slice as *mut OsStr) }
}
- /// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
+ /// Yields a <code>&[str]</code> slice if the `OsStr` is valid Unicode.
///
/// This conversion may entail doing a check for UTF-8 validity.
///
- /// [`&str`]: str
- ///
/// # Examples
///
/// ```
self.inner.to_str()
}
- /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`.
+ /// Converts an `OsStr` to a <code>[Cow]<[str]></code>.
///
/// Any non-Unicode sequences are replaced with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
self.inner.inner.len()
}
- /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating.
+ /// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
#[stable(feature = "into_boxed_os_str", since = "1.20.0")]
pub fn into_os_string(self: Box<OsStr>) -> OsString {
let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
#[stable(feature = "os_string_from_box", since = "1.18.0")]
impl From<Box<OsStr>> for OsString {
- /// Converts a [`Box`]`<`[`OsStr`]`>` into an [`OsString`] without copying or
+ /// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or
/// allocating.
#[inline]
fn from(boxed: Box<OsStr>) -> OsString {
#[stable(feature = "box_from_os_string", since = "1.20.0")]
impl From<OsString> for Box<OsStr> {
- /// Converts an [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating.
+ /// Converts an [`OsString`] into a <code>[Box]<[OsStr]></code> without copying or allocating.
#[inline]
fn from(s: OsString) -> Box<OsStr> {
s.into_boxed_os_str()
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Arc<OsStr> {
- /// Converts an [`OsString`] into an [`Arc`]`<OsStr>` without copying or allocating.
+ /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> without copying or allocating.
#[inline]
fn from(s: OsString) -> Arc<OsStr> {
let arc = s.inner.into_arc();
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Rc<OsStr> {
- /// Converts an [`OsString`] into an [`Rc`]`<OsStr>` without copying or allocating.
+ /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> without copying or allocating.
#[inline]
fn from(s: OsString) -> Rc<OsStr> {
let rc = s.inner.into_rc();
/// Iterator over the entries in a directory.
///
/// This iterator is returned from the [`read_dir`] function of this module and
-/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`]
+/// will yield instances of <code>[io::Result]<[DirEntry]></code>. Through a [`DirEntry`]
/// information like the entry's path and possibly other metadata can be
/// learned.
///
/// If a file is opened with both read and append access, beware that after
/// opening, and after every write, the position for reading may be set at the
/// end of the file. So, before writing, save the current position (using
- /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
+ /// <code>[seek]\([SeekFrom]::[Current]\(0))</code>), and restore it before the next read.
///
/// ## Note
///
/// This function doesn't create the file if it doesn't exist. Use the
/// [`OpenOptions::create`] method to do so.
///
- /// [`write()`]: Write::write
- /// [`flush()`]: Write::flush
- /// [`seek`]: Seek::seek
- /// [`Current`]: SeekFrom::Current
+ /// [`write()`]: Write::write "io::Write::write"
+ /// [`flush()`]: Write::flush "io::Write::flush"
+ /// [seek]: Seek::seek "io::Seek::seek"
+ /// [Current]: SeekFrom::Current "io::SeekFrom::Current"
///
/// # Examples
///
/// Returns an iterator over the entries within a directory.
///
-/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`.
+/// The iterator will yield instances of <code>[io::Result]<[DirEntry]></code>.
/// New errors may be encountered after an iterator is initially constructed.
/// Entries for the current and parent directories (typically `.` and `..`) are
/// skipped.
/// *repeated* read calls to the same file or network socket. It does not
/// help when reading very large amounts at once, or reading just one or a few
/// times. It also provides no advantage when reading from a source that is
-/// already in memory, like a [`Vec`]`<u8>`.
+/// already in memory, like a <code>[Vec]\<u8></code>.
///
/// When the `BufReader<R>` is dropped, the contents of its buffer will be
/// discarded. Creating multiple instances of a `BufReader<R>` on the same
impl<R: Seek> Seek for BufReader<R> {
/// Seek to an offset, in bytes, in the underlying reader.
///
- /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
+ /// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
/// position the underlying reader would be at if the `BufReader<R>` had no
/// internal buffer.
///
///
/// See [`std::io::Seek`] for more details.
///
- /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
+ /// Note: In the edge case where you're seeking with <code>[SeekFrom::Current]\(n)</code>
/// where `n` minus the internal buffer length overflows an `i64`, two
/// seeks will be performed instead of one. If the second seek returns
/// [`Err`], the underlying reader will be left at the same position it would
- /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
+ /// have if you called `seek` with <code>[SeekFrom::Current]\(0)</code>.
///
/// [`std::io::Seek`]: Seek
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
/// *repeated* write calls to the same file or network socket. It does not
/// help when writing very large amounts at once, or writing just one or a few
/// times. It also provides no advantage when writing to a destination that is
-/// in memory, like a [`Vec`]`<u8>`.
+/// in memory, like a <code>[Vec]\<u8></code>.
///
/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
/// dropping will attempt to flush the contents of the buffer, any errors
/// [`Seek`] implementation.
///
/// `Cursor`s are used with in-memory buffers, anything implementing
-/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
+/// <code>[AsRef]<\[u8]></code>, to allow them to implement [`Read`] and/or [`Write`],
/// allowing these buffers to be used anywhere you might use a reader or writer
/// that does actual I/O.
///
/// The standard library implements some I/O traits on various types which
-/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
-/// `Cursor<`[`&[u8]`][bytes]`>`.
+/// are commonly used as a buffer, like <code>Cursor<[Vec]\<u8>></code> and
+/// <code>Cursor<[&\[u8\]][bytes]></code>.
///
/// # Examples
///
/// code, but use an in-memory buffer in our tests. We can do this with
/// `Cursor`:
///
-/// [bytes]: crate::slice
+/// [bytes]: crate::slice "slice"
/// [`File`]: crate::fs::File
///
/// ```no_run
/// Transforms this `Read` instance to an [`Iterator`] over its bytes.
///
- /// The returned type implements [`Iterator`] where the `Item` is
- /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`.
+ /// The returned type implements [`Iterator`] where the [`Item`] is
+ /// <code>[Result]<[u8], [io::Error]></code>.
/// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
/// otherwise. EOF is mapped to returning [`None`] from this iterator.
///
///
/// [`File`]s implement `Read`:
///
- /// [`File`]: crate::fs::File
- /// [`Result`]: crate::result::Result
- /// [`io::Error`]: self::Error
+ /// [`Item`]: Iterator::Item
+ /// [`File`]: crate::fs::File "fs::File"
+ /// [Result]: crate::result::Result "Result"
+ /// [io::Error]: self::Error "io::Error"
///
/// ```no_run
/// use std::io;
/// `byte`.
///
/// The iterator returned from this function will return instances of
- /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
+ /// <code>[io::Result]<[Vec]\<u8>></code>. Each vector returned will *not* have
/// the delimiter byte at the end.
///
/// This function will yield errors whenever [`read_until`] would have
/// also yielded an error.
///
- /// [`io::Result`]: self::Result
+ /// [io::Result]: self::Result "io::Result"
/// [`read_until`]: BufRead::read_until
///
/// # Examples
/// Returns an iterator over the lines of this reader.
///
/// The iterator returned from this function will yield instances of
- /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
+ /// <code>[io::Result]<[String]></code>. Each string returned will *not* have a newline
/// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end.
///
- /// [`io::Result`]: self::Result
+ /// [io::Result]: self::Result "io::Result"
///
/// # Examples
///
/// Constructs a new handle to an empty reader.
///
-/// All reads from the returned reader will return [`Ok`]`(0)`.
+/// All reads from the returned reader will return <code>[Ok]\(0)</code>.
///
/// # Examples
///
///
/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function.
///
-/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`,
-/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`:
+/// * [`SocketAddrV4`], [`SocketAddrV6`], <code>([IpAddr], [u16])</code>,
+/// <code>([Ipv4Addr], [u16])</code>, <code>([Ipv6Addr], [u16])</code>:
/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially.
///
-/// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation
+/// * <code>(&[str], [u16])</code>: <code>&[str]</code> should be either a string representation
/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host
/// name. [`u16`] is the port number.
///
-/// * [`&str`]: the string should be either a string representation of a
+/// * <code>&[str]</code>: the string should be either a string representation of a
/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like
/// `<host_name>:<port>` pair where `<port>` is a [`u16`] value.
///
/// Addresses returned by the operating system that are not IP addresses are
/// silently ignored.
///
-/// [`FromStr`]: crate::str::FromStr
-/// [`&str`]: str
-/// [`TcpStream`]: crate::net::TcpStream
+/// [`FromStr`]: crate::str::FromStr "std::str::FromStr"
+/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream"
/// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs
-/// [`UdpSocket`]: crate::net::UdpSocket
+/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket"
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
type Iter: Iterator<Item = SocketAddr>;
- /// Converts this object to an iterator of resolved `SocketAddr`s.
+ /// Converts this object to an iterator of resolved [`SocketAddr`]s.
///
/// The returned iterator might not actually yield any values depending on the
/// outcome of any resolution performed.
pub enum Shutdown {
/// The reading portion of the [`TcpStream`] should be shut down.
///
- /// All currently blocked and future [reads] will return [`Ok`]`(0)`.
+ /// All currently blocked and future [reads] will return <code>[Ok]\(0)</code>.
///
- /// [reads]: crate::io::Read
+ /// [reads]: crate::io::Read "io::Read"
#[stable(feature = "rust1", since = "1.0.0")]
Read,
/// The writing portion of the [`TcpStream`] should be shut down.
///
/// All currently blocked and future [writes] will return an error.
///
- /// [writes]: crate::io::Write
+ /// [writes]: crate::io::Write "io::Write"
#[stable(feature = "rust1", since = "1.0.0")]
Write,
/// Both the reading and the writing portions of the [`TcpStream`] should be shut down.
#[cfg(target_os = "solaris")]
pub mod solaris;
+#[cfg(target_os = "solid_asp3")]
+pub mod solid;
#[cfg(target_os = "vxworks")]
pub mod vxworks;
--- /dev/null
+//! SOLID-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::solid::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::solid::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
--- /dev/null
+//! SOLID-specific extensions to general I/O primitives
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "solid_ext", issue = "none")]
+
+use crate::net;
+use crate::sys;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+pub type RawFd = i32;
+
+/// A trait to extract the raw SOLID Sockets file descriptor from an underlying
+/// object.
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self
+ }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self
+ }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+ fd
+ }
+}
+
+macro_rules! impl_as_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl AsRawFd for net::$t {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self.as_inner().socket().as_inner()
+ }
+ }
+ )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ impl FromRawFd for net::$t {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+ }
+ }
+ )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ impl IntoRawFd for net::$t {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+ }
+ )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
--- /dev/null
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+pub mod io;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+}
/// Returns an iterator over the entries within a directory.
///
- /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New
+ /// The iterator will yield instances of <code>[io::Result]<[fs::DirEntry]></code>. New
/// errors may be encountered after an iterator is initially constructed.
///
/// This is an alias to [`fs::read_dir`].
--- /dev/null
+//! ABI for μITRON derivatives
+pub type int_t = crate::os::raw::c_int;
+pub type uint_t = crate::os::raw::c_uint;
+pub type bool_t = int_t;
+
+/// Kernel object ID
+pub type ID = int_t;
+
+/// The current task.
+pub const TSK_SELF: ID = 0;
+
+/// Relative time
+pub type RELTIM = u32;
+
+/// Timeout (a valid `RELTIM` value or `TMO_FEVR`)
+pub type TMO = u32;
+
+/// The infinite timeout value
+pub const TMO_FEVR: TMO = TMO::MAX;
+
+/// The maximum valid value of `RELTIM`
+pub const TMAX_RELTIM: RELTIM = 4_000_000_000;
+
+/// System time
+pub type SYSTIM = u64;
+
+/// Error code type
+pub type ER = int_t;
+
+/// Error code type, `ID` on success
+pub type ER_ID = int_t;
+
+/// Task or interrupt priority
+pub type PRI = int_t;
+
+/// The special value of `PRI` representing the current task's priority.
+pub const TPRI_SELF: PRI = 0;
+
+/// Object attributes
+pub type ATR = uint_t;
+
+/// Use the priority inheritance protocol
+#[cfg(target_os = "solid_asp3")]
+pub const TA_INHERIT: ATR = 0x02;
+
+/// Activate the task on creation
+pub const TA_ACT: ATR = 0x01;
+
+/// The maximum count of a semaphore
+pub const TMAX_MAXSEM: uint_t = uint_t::MAX;
+
+/// Callback parameter
+pub type EXINF = isize;
+
+/// Task entrypoint
+pub type TASK = Option<unsafe extern "C" fn(EXINF)>;
+
+// Error codes
+pub const E_OK: ER = 0;
+pub const E_SYS: ER = -5;
+pub const E_NOSPT: ER = -9;
+pub const E_RSFN: ER = -10;
+pub const E_RSATR: ER = -11;
+pub const E_PAR: ER = -17;
+pub const E_ID: ER = -18;
+pub const E_CTX: ER = -25;
+pub const E_MACV: ER = -26;
+pub const E_OACV: ER = -27;
+pub const E_ILUSE: ER = -28;
+pub const E_NOMEM: ER = -33;
+pub const E_NOID: ER = -34;
+pub const E_NORES: ER = -35;
+pub const E_OBJ: ER = -41;
+pub const E_NOEXS: ER = -42;
+pub const E_QOVR: ER = -43;
+pub const E_RLWAI: ER = -49;
+pub const E_TMOUT: ER = -50;
+pub const E_DLT: ER = -51;
+pub const E_CLS: ER = -52;
+pub const E_RASTER: ER = -53;
+pub const E_WBLK: ER = -57;
+pub const E_BOVR: ER = -58;
+pub const E_COMM: ER = -65;
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CSEM {
+ pub sematr: ATR,
+ pub isemcnt: uint_t,
+ pub maxsem: uint_t,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CMTX {
+ pub mtxatr: ATR,
+ pub ceilpri: PRI,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CTSK {
+ pub tskatr: ATR,
+ pub exinf: EXINF,
+ pub task: TASK,
+ pub itskpri: PRI,
+ pub stksz: usize,
+ pub stk: *mut u8,
+}
+
+extern "C" {
+ #[link_name = "__asp3_acre_tsk"]
+ pub fn acre_tsk(pk_ctsk: *const T_CTSK) -> ER_ID;
+ #[link_name = "__asp3_get_tid"]
+ pub fn get_tid(p_tskid: *mut ID) -> ER;
+ #[link_name = "__asp3_dly_tsk"]
+ pub fn dly_tsk(dlytim: RELTIM) -> ER;
+ #[link_name = "__asp3_ter_tsk"]
+ pub fn ter_tsk(tskid: ID) -> ER;
+ #[link_name = "__asp3_del_tsk"]
+ pub fn del_tsk(tskid: ID) -> ER;
+ #[link_name = "__asp3_get_pri"]
+ pub fn get_pri(tskid: ID, p_tskpri: *mut PRI) -> ER;
+ #[link_name = "__asp3_rot_rdq"]
+ pub fn rot_rdq(tskpri: PRI) -> ER;
+ #[link_name = "__asp3_slp_tsk"]
+ pub fn slp_tsk() -> ER;
+ #[link_name = "__asp3_tslp_tsk"]
+ pub fn tslp_tsk(tmout: TMO) -> ER;
+ #[link_name = "__asp3_wup_tsk"]
+ pub fn wup_tsk(tskid: ID) -> ER;
+ #[link_name = "__asp3_unl_cpu"]
+ pub fn unl_cpu() -> ER;
+ #[link_name = "__asp3_dis_dsp"]
+ pub fn dis_dsp() -> ER;
+ #[link_name = "__asp3_ena_dsp"]
+ pub fn ena_dsp() -> ER;
+ #[link_name = "__asp3_sns_dsp"]
+ pub fn sns_dsp() -> bool_t;
+ #[link_name = "__asp3_get_tim"]
+ pub fn get_tim(p_systim: *mut SYSTIM) -> ER;
+ #[link_name = "__asp3_acre_mtx"]
+ pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID;
+ #[link_name = "__asp3_del_mtx"]
+ pub fn del_mtx(tskid: ID) -> ER;
+ #[link_name = "__asp3_loc_mtx"]
+ pub fn loc_mtx(mtxid: ID) -> ER;
+ #[link_name = "__asp3_ploc_mtx"]
+ pub fn ploc_mtx(mtxid: ID) -> ER;
+ #[link_name = "__asp3_tloc_mtx"]
+ pub fn tloc_mtx(mtxid: ID, tmout: TMO) -> ER;
+ #[link_name = "__asp3_unl_mtx"]
+ pub fn unl_mtx(mtxid: ID) -> ER;
+ pub fn exd_tsk() -> ER;
+}
--- /dev/null
+//! POSIX conditional variable implementation based on user-space wait queues.
+use super::{abi, error::expect_success_aborting, spin::SpinMutex, task, time::with_tmos_strong};
+use crate::{mem::replace, ptr::NonNull, sys::mutex::Mutex, time::Duration};
+
+// The implementation is inspired by the queue-based implementation shown in
+// Andrew D. Birrell's paper "Implementing Condition Variables with Semaphores"
+
+pub struct Condvar {
+ waiters: SpinMutex<waiter_queue::WaiterQueue>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+pub type MovableCondvar = Condvar;
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
+ }
+
+ pub unsafe fn init(&mut self) {}
+
+ pub unsafe fn notify_one(&self) {
+ self.waiters.with_locked(|waiters| {
+ if let Some(task) = waiters.pop_front() {
+ // Unpark the task
+ match unsafe { abi::wup_tsk(task) } {
+ // The task already has a token.
+ abi::E_QOVR => {}
+ // Can't undo the effect; abort the program on failure
+ er => {
+ expect_success_aborting(er, &"wup_tsk");
+ }
+ }
+ }
+ });
+ }
+
+ pub unsafe fn notify_all(&self) {
+ self.waiters.with_locked(|waiters| {
+ while let Some(task) = waiters.pop_front() {
+ // Unpark the task
+ match unsafe { abi::wup_tsk(task) } {
+ // The task already has a token.
+ abi::E_QOVR => {}
+ // Can't undo the effect; abort the program on failure
+ er => {
+ expect_success_aborting(er, &"wup_tsk");
+ }
+ }
+ }
+ });
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ // Construct `Waiter`.
+ let mut waiter = waiter_queue::Waiter::new();
+ let waiter = NonNull::from(&mut waiter);
+
+ self.waiters.with_locked(|waiters| unsafe {
+ waiters.insert(waiter);
+ });
+
+ unsafe { mutex.unlock() };
+
+ // Wait until `waiter` is removed from the queue
+ loop {
+ // Park the current task
+ expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
+
+ if !self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) {
+ break;
+ }
+ }
+
+ unsafe { mutex.lock() };
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ // Construct and pin `Waiter`
+ let mut waiter = waiter_queue::Waiter::new();
+ let waiter = NonNull::from(&mut waiter);
+
+ self.waiters.with_locked(|waiters| unsafe {
+ waiters.insert(waiter);
+ });
+
+ unsafe { mutex.unlock() };
+
+ // Park the current task and do not wake up until the timeout elapses
+ // or the task gets woken up by `notify_*`
+ match with_tmos_strong(dur, |tmo| {
+ let er = unsafe { abi::tslp_tsk(tmo) };
+ if er == 0 {
+ // We were unparked. Are we really dequeued?
+ if self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) {
+ // No we are not. Continue waiting.
+ return abi::E_TMOUT;
+ }
+ }
+ er
+ }) {
+ abi::E_TMOUT => {}
+ er => {
+ expect_success_aborting(er, &"tslp_tsk");
+ }
+ }
+
+ // Remove `waiter` from `self.waiters`. If `waiter` is still in
+ // `waiters`, it means we woke up because of a timeout. Otherwise,
+ // we woke up because of `notify_*`.
+ let success = self.waiters.with_locked(|waiters| unsafe { !waiters.remove(waiter) });
+
+ unsafe { mutex.lock() };
+ success
+ }
+
+ pub unsafe fn destroy(&self) {}
+}
+
+mod waiter_queue {
+ use super::*;
+
+ pub struct WaiterQueue {
+ head: Option<ListHead>,
+ }
+
+ #[derive(Copy, Clone)]
+ struct ListHead {
+ first: NonNull<Waiter>,
+ last: NonNull<Waiter>,
+ }
+
+ unsafe impl Send for ListHead {}
+ unsafe impl Sync for ListHead {}
+
+ pub struct Waiter {
+ // These fields are only accessed through `&[mut] WaiterQueue`.
+ /// The waiting task's ID. Will be zeroed when the task is woken up
+ /// and removed from a queue.
+ task: abi::ID,
+ priority: abi::PRI,
+ prev: Option<NonNull<Waiter>>,
+ next: Option<NonNull<Waiter>>,
+ }
+
+ unsafe impl Send for Waiter {}
+ unsafe impl Sync for Waiter {}
+
+ impl Waiter {
+ #[inline]
+ pub fn new() -> Self {
+ let task = task::current_task_id();
+ let priority = task::task_priority(abi::TSK_SELF);
+
+ // Zeroness of `Waiter::task` indicates whether the `Waiter` is
+ // linked to a queue or not. This invariant is important for
+ // the correctness.
+ debug_assert_ne!(task, 0);
+
+ Self { task, priority, prev: None, next: None }
+ }
+ }
+
+ impl WaiterQueue {
+ #[inline]
+ pub const fn new() -> Self {
+ Self { head: None }
+ }
+
+ /// # Safety
+ ///
+ /// - The caller must own `*waiter_ptr`. The caller will lose the
+ /// ownership until `*waiter_ptr` is removed from `self`.
+ ///
+ /// - `*waiter_ptr` must be valid until it's removed from the queue.
+ ///
+ /// - `*waiter_ptr` must not have been previously inserted to a `WaiterQueue`.
+ ///
+ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
+ unsafe {
+ let waiter = waiter_ptr.as_mut();
+
+ debug_assert!(waiter.prev.is_none());
+ debug_assert!(waiter.next.is_none());
+
+ if let Some(head) = &mut self.head {
+ // Find the insertion position and insert `waiter`
+ let insert_after = {
+ let mut cursor = head.last;
+ loop {
+ if waiter.priority <= cursor.as_ref().priority {
+ // `cursor` and all previous waiters have the same or higher
+ // priority than `current_task_priority`. Insert the new
+ // waiter right after `cursor`.
+ break Some(cursor);
+ }
+ cursor = if let Some(prev) = cursor.as_ref().prev {
+ prev
+ } else {
+ break None;
+ };
+ }
+ };
+
+ if let Some(mut insert_after) = insert_after {
+ // Insert `waiter` after `insert_after`
+ let insert_before = insert_after.as_ref().prev;
+
+ waiter.prev = Some(insert_after);
+ insert_after.as_mut().next = Some(waiter_ptr);
+
+ waiter.next = insert_before;
+ if let Some(mut insert_before) = insert_before {
+ insert_before.as_mut().prev = Some(waiter_ptr);
+ }
+ } else {
+ // Insert `waiter` to the front
+ waiter.next = Some(head.first);
+ head.first.as_mut().prev = Some(waiter_ptr);
+ head.first = waiter_ptr;
+ }
+ } else {
+ // `waiter` is the only element
+ self.head = Some(ListHead { first: waiter_ptr, last: waiter_ptr });
+ }
+ }
+ }
+
+ /// Given a `Waiter` that was previously inserted to `self`, remove
+ /// it from `self` if it's still there.
+ #[inline]
+ pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull<Waiter>) -> bool {
+ unsafe {
+ let waiter = waiter_ptr.as_mut();
+ if waiter.task != 0 {
+ let head = self.head.as_mut().unwrap();
+
+ match (waiter.prev, waiter.next) {
+ (Some(mut prev), Some(mut next)) => {
+ prev.as_mut().next = Some(next);
+ next.as_mut().next = Some(prev);
+ }
+ (None, Some(mut next)) => {
+ head.first = next;
+ next.as_mut().next = None;
+ }
+ (Some(mut prev), None) => {
+ prev.as_mut().next = None;
+ head.last = prev;
+ }
+ (None, None) => {
+ self.head = None;
+ }
+ }
+
+ waiter.task = 0;
+
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ /// Given a `Waiter` that was previously inserted to `self`, return a
+ /// flag indicating whether it's still in `self`.
+ #[inline]
+ pub unsafe fn is_queued(&self, waiter: NonNull<Waiter>) -> bool {
+ unsafe { waiter.as_ref().task != 0 }
+ }
+
+ pub fn pop_front(&mut self) -> Option<abi::ID> {
+ unsafe {
+ let head = self.head.as_mut()?;
+ let waiter = head.first.as_mut();
+
+ // Get the ID
+ let id = replace(&mut waiter.task, 0);
+
+ // Unlink the waiter
+ if let Some(mut next) = waiter.next {
+ head.first = next;
+ next.as_mut().prev = None;
+ } else {
+ self.head = None;
+ }
+
+ Some(id)
+ }
+ }
+ }
+}
--- /dev/null
+use crate::{fmt, io::ErrorKind};
+
+use super::abi;
+
+/// Wraps a μITRON error code.
+#[derive(Debug, Copy, Clone)]
+pub struct ItronError {
+ er: abi::ER,
+}
+
+impl ItronError {
+ /// Construct `ItronError` from the specified error code. Returns `None` if the
+ /// error code does not represent a failure or warning.
+ #[inline]
+ pub fn new(er: abi::ER) -> Option<Self> {
+ if er < 0 { Some(Self { er }) } else { None }
+ }
+
+ /// Returns `Ok(er)` if `er` represents a success or `Err(_)` otherwise.
+ #[inline]
+ pub fn err_if_negative(er: abi::ER) -> Result<abi::ER, Self> {
+ if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) }
+ }
+
+ /// Get the raw error code.
+ #[inline]
+ pub fn as_raw(&self) -> abi::ER {
+ self.er
+ }
+}
+
+impl fmt::Display for ItronError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Allow the platforms to extend `error_name`
+ if let Some(name) = crate::sys::error::error_name(self.er) {
+ write!(f, "{} ({})", name, self.er)
+ } else {
+ write!(f, "{}", self.er)
+ }
+ }
+}
+
+/// Describe the specified μITRON error code. Returns `None` if it's an
+/// undefined error code.
+pub fn error_name(er: abi::ER) -> Option<&'static str> {
+ match er {
+ // Success
+ er if er >= 0 => None,
+
+ // μITRON 4.0
+ abi::E_SYS => Some("system error"),
+ abi::E_NOSPT => Some("unsupported function"),
+ abi::E_RSFN => Some("reserved function code"),
+ abi::E_RSATR => Some("reserved attribute"),
+ abi::E_PAR => Some("parameter error"),
+ abi::E_ID => Some("invalid ID number"),
+ abi::E_CTX => Some("context error"),
+ abi::E_MACV => Some("memory access violation"),
+ abi::E_OACV => Some("object access violation"),
+ abi::E_ILUSE => Some("illegal service call use"),
+ abi::E_NOMEM => Some("insufficient memory"),
+ abi::E_NOID => Some("no ID number available"),
+ abi::E_OBJ => Some("object state error"),
+ abi::E_NOEXS => Some("non-existent object"),
+ abi::E_QOVR => Some("queue overflow"),
+ abi::E_RLWAI => Some("forced release from waiting"),
+ abi::E_TMOUT => Some("polling failure or timeout"),
+ abi::E_DLT => Some("waiting object deleted"),
+ abi::E_CLS => Some("waiting object state changed"),
+ abi::E_WBLK => Some("non-blocking code accepted"),
+ abi::E_BOVR => Some("buffer overflow"),
+
+ // The TOPPERS third generation kernels
+ abi::E_NORES => Some("insufficient system resources"),
+ abi::E_RASTER => Some("termination request raised"),
+ abi::E_COMM => Some("communication failure"),
+
+ _ => None,
+ }
+}
+
+pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
+ match er {
+ // Success
+ er if er >= 0 => ErrorKind::Uncategorized,
+
+ // μITRON 4.0
+ // abi::E_SYS
+ abi::E_NOSPT => ErrorKind::Unsupported, // Some("unsupported function"),
+ abi::E_RSFN => ErrorKind::InvalidInput, // Some("reserved function code"),
+ abi::E_RSATR => ErrorKind::InvalidInput, // Some("reserved attribute"),
+ abi::E_PAR => ErrorKind::InvalidInput, // Some("parameter error"),
+ abi::E_ID => ErrorKind::NotFound, // Some("invalid ID number"),
+ // abi::E_CTX
+ abi::E_MACV => ErrorKind::PermissionDenied, // Some("memory access violation"),
+ abi::E_OACV => ErrorKind::PermissionDenied, // Some("object access violation"),
+ // abi::E_ILUSE
+ abi::E_NOMEM => ErrorKind::OutOfMemory, // Some("insufficient memory"),
+ abi::E_NOID => ErrorKind::OutOfMemory, // Some("no ID number available"),
+ // abi::E_OBJ
+ abi::E_NOEXS => ErrorKind::NotFound, // Some("non-existent object"),
+ // abi::E_QOVR
+ abi::E_RLWAI => ErrorKind::Interrupted, // Some("forced release from waiting"),
+ abi::E_TMOUT => ErrorKind::TimedOut, // Some("polling failure or timeout"),
+ // abi::E_DLT
+ // abi::E_CLS
+ // abi::E_WBLK
+ // abi::E_BOVR
+
+ // The TOPPERS third generation kernels
+ abi::E_NORES => ErrorKind::OutOfMemory, // Some("insufficient system resources"),
+ // abi::E_RASTER
+ // abi::E_COMM
+ _ => ErrorKind::Uncategorized,
+ }
+}
+
+/// Similar to `ItronError::err_if_negative(er).expect()` except that, while
+/// panicking, it prints the message to `panic_output` and aborts the program
+/// instead. This ensures the error message is not obscured by double
+/// panicking.
+///
+/// This is useful for diagnosing creation failures of synchronization
+/// primitives that are used by `std`'s internal mechanisms. Such failures
+/// are common when the system is mis-configured to provide a too-small pool for
+/// kernel objects.
+#[inline]
+pub fn expect_success(er: abi::ER, msg: &&str) -> abi::ER {
+ match ItronError::err_if_negative(er) {
+ Ok(x) => x,
+ Err(e) => fail(e, msg),
+ }
+}
+
+/// Similar to `ItronError::err_if_negative(er).expect()` but aborts instead.
+///
+/// Use this where panicking is not allowed or the effect of the failure
+/// would be persistent.
+#[inline]
+pub fn expect_success_aborting(er: abi::ER, msg: &&str) -> abi::ER {
+ match ItronError::err_if_negative(er) {
+ Ok(x) => x,
+ Err(e) => fail_aborting(e, msg),
+ }
+}
+
+#[cold]
+pub fn fail(e: impl fmt::Display, msg: &&str) -> ! {
+ if crate::thread::panicking() {
+ fail_aborting(e, msg)
+ } else {
+ panic!("{} failed: {}", *msg, e)
+ }
+}
+
+#[cold]
+pub fn fail_aborting(e: impl fmt::Display, msg: &&str) -> ! {
+ rtabort!("{} failed: {}", *msg, e)
+}
--- /dev/null
+//! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and
+//! `TA_INHERIT` are available.
+use super::{
+ abi,
+ error::{expect_success, expect_success_aborting, fail, ItronError},
+ spin::SpinIdOnceCell,
+};
+use crate::cell::UnsafeCell;
+
+pub struct Mutex {
+ /// The ID of the underlying mutex object
+ mtx: SpinIdOnceCell<()>,
+}
+
+pub type MovableMutex = Mutex;
+
+/// Create a mutex object. This function never panics.
+fn new_mtx() -> Result<abi::ID, ItronError> {
+ ItronError::err_if_negative(unsafe {
+ abi::acre_mtx(&abi::T_CMTX {
+ // Priority inheritance mutex
+ mtxatr: abi::TA_INHERIT,
+ // Unused
+ ceilpri: 0,
+ })
+ })
+}
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { mtx: SpinIdOnceCell::new() }
+ }
+
+ pub unsafe fn init(&mut self) {
+ // Initialize `self.mtx` eagerly
+ let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx"));
+ unsafe { self.mtx.set_unchecked((id, ())) };
+ }
+
+ /// Get the inner mutex's ID, which is lazily created.
+ fn raw(&self) -> abi::ID {
+ match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) {
+ Ok((id, ())) => id,
+ Err(e) => fail(e, &"acre_mtx"),
+ }
+ }
+
+ pub unsafe fn lock(&self) {
+ let mtx = self.raw();
+ expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx");
+ }
+
+ pub unsafe fn unlock(&self) {
+ let mtx = unsafe { self.mtx.get_unchecked().0 };
+ expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx");
+ }
+
+ pub unsafe fn try_lock(&self) -> bool {
+ let mtx = self.raw();
+ match unsafe { abi::ploc_mtx(mtx) } {
+ abi::E_TMOUT => false,
+ er => {
+ expect_success(er, &"ploc_mtx");
+ true
+ }
+ }
+ }
+
+ pub unsafe fn destroy(&self) {
+ if let Some(mtx) = self.mtx.get().map(|x| x.0) {
+ expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx");
+ }
+ }
+}
+
+pub(super) struct MutexGuard<'a>(&'a Mutex);
+
+impl<'a> MutexGuard<'a> {
+ #[inline]
+ pub(super) fn lock(x: &'a Mutex) -> Self {
+ unsafe { x.lock() };
+ Self(x)
+ }
+}
+
+impl Drop for MutexGuard<'_> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { self.0.unlock() };
+ }
+}
+
+// All empty stubs because this platform does not yet support threads, so lock
+// acquisition always succeeds.
+pub struct ReentrantMutex {
+ /// The ID of the underlying mutex object
+ mtx: abi::ID,
+ /// The lock count.
+ count: UnsafeCell<usize>,
+}
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+ pub const unsafe fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) }
+ }
+
+ pub unsafe fn init(&mut self) {
+ self.mtx = expect_success(
+ unsafe {
+ abi::acre_mtx(&abi::T_CMTX {
+ // Priority inheritance mutex
+ mtxatr: abi::TA_INHERIT,
+ // Unused
+ ceilpri: 0,
+ })
+ },
+ &"acre_mtx",
+ );
+ }
+
+ pub unsafe fn lock(&self) {
+ match unsafe { abi::loc_mtx(self.mtx) } {
+ abi::E_OBJ => {
+ // Recursive lock
+ unsafe {
+ let count = &mut *self.count.get();
+ if let Some(new_count) = count.checked_add(1) {
+ *count = new_count;
+ } else {
+ // counter overflow
+ rtabort!("lock count overflow");
+ }
+ }
+ }
+ er => {
+ expect_success(er, &"loc_mtx");
+ }
+ }
+ }
+
+ pub unsafe fn unlock(&self) {
+ unsafe {
+ let count = &mut *self.count.get();
+ if *count > 0 {
+ *count -= 1;
+ return;
+ }
+ }
+
+ expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx");
+ }
+
+ pub unsafe fn try_lock(&self) -> bool {
+ let er = unsafe { abi::ploc_mtx(self.mtx) };
+ if er == abi::E_OBJ {
+ // Recursive lock
+ unsafe {
+ let count = &mut *self.count.get();
+ if let Some(new_count) = count.checked_add(1) {
+ *count = new_count;
+ } else {
+ // counter overflow
+ rtabort!("lock count overflow");
+ }
+ }
+ true
+ } else if er == abi::E_TMOUT {
+ // Locked by another thread
+ false
+ } else {
+ expect_success(er, &"ploc_mtx");
+ // Top-level lock by the current thread
+ true
+ }
+ }
+
+ pub unsafe fn destroy(&self) {
+ expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx");
+ }
+}
--- /dev/null
+use super::abi;
+use crate::{
+ cell::UnsafeCell,
+ convert::TryFrom,
+ mem::MaybeUninit,
+ sync::atomic::{AtomicBool, AtomicUsize, Ordering},
+};
+
+/// A mutex implemented by `dis_dsp` (for intra-core synchronization) and a
+/// spinlock (for inter-core synchronization).
+pub struct SpinMutex<T = ()> {
+ locked: AtomicBool,
+ data: UnsafeCell<T>,
+}
+
+impl<T> SpinMutex<T> {
+ #[inline]
+ pub const fn new(x: T) -> Self {
+ Self { locked: AtomicBool::new(false), data: UnsafeCell::new(x) }
+ }
+
+ /// Acquire a lock.
+ #[inline]
+ pub fn with_locked<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
+ struct SpinMutexGuard<'a>(&'a AtomicBool);
+
+ impl Drop for SpinMutexGuard<'_> {
+ #[inline]
+ fn drop(&mut self) {
+ self.0.store(false, Ordering::Release);
+ unsafe { abi::ena_dsp() };
+ }
+ }
+
+ let _guard;
+ if unsafe { abi::sns_dsp() } == 0 {
+ let er = unsafe { abi::dis_dsp() };
+ debug_assert!(er >= 0);
+
+ // Wait until the current processor acquires a lock.
+ while self.locked.swap(true, Ordering::Acquire) {}
+
+ _guard = SpinMutexGuard(&self.locked);
+ }
+
+ f(unsafe { &mut *self.data.get() })
+ }
+}
+
+/// `OnceCell<(abi::ID, T)>` implemented by `dis_dsp` (for intra-core
+/// synchronization) and a spinlock (for inter-core synchronization).
+///
+/// It's assumed that `0` is not a valid ID, and all kernel
+/// object IDs fall into range `1..=usize::MAX`.
+pub struct SpinIdOnceCell<T = ()> {
+ id: AtomicUsize,
+ spin: SpinMutex<()>,
+ extra: UnsafeCell<MaybeUninit<T>>,
+}
+
+const ID_UNINIT: usize = 0;
+
+impl<T> SpinIdOnceCell<T> {
+ #[inline]
+ pub const fn new() -> Self {
+ Self {
+ id: AtomicUsize::new(ID_UNINIT),
+ extra: UnsafeCell::new(MaybeUninit::uninit()),
+ spin: SpinMutex::new(()),
+ }
+ }
+
+ #[inline]
+ pub fn get(&self) -> Option<(abi::ID, &T)> {
+ match self.id.load(Ordering::Acquire) {
+ ID_UNINIT => None,
+ id => Some((id as abi::ID, unsafe { (&*self.extra.get()).assume_init_ref() })),
+ }
+ }
+
+ #[inline]
+ pub fn get_mut(&mut self) -> Option<(abi::ID, &mut T)> {
+ match *self.id.get_mut() {
+ ID_UNINIT => None,
+ id => Some((id as abi::ID, unsafe { (&mut *self.extra.get()).assume_init_mut() })),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn get_unchecked(&self) -> (abi::ID, &T) {
+ (self.id.load(Ordering::Acquire) as abi::ID, unsafe {
+ (&*self.extra.get()).assume_init_ref()
+ })
+ }
+
+ /// Assign the content without checking if it's already initialized or
+ /// being initialized.
+ pub unsafe fn set_unchecked(&self, (id, extra): (abi::ID, T)) {
+ debug_assert!(self.get().is_none());
+
+ // Assumption: A positive `abi::ID` fits in `usize`.
+ debug_assert!(id >= 0);
+ debug_assert!(usize::try_from(id).is_ok());
+ let id = id as usize;
+
+ unsafe { *self.extra.get() = MaybeUninit::new(extra) };
+ self.id.store(id, Ordering::Release);
+ }
+
+ /// Gets the contents of the cell, initializing it with `f` if
+ /// the cell was empty. If the cell was empty and `f` failed, an
+ /// error is returned.
+ ///
+ /// Warning: `f` must not perform a blocking operation, which
+ /// includes panicking.
+ #[inline]
+ pub fn get_or_try_init<F, E>(&self, f: F) -> Result<(abi::ID, &T), E>
+ where
+ F: FnOnce() -> Result<(abi::ID, T), E>,
+ {
+ // Fast path
+ if let Some(x) = self.get() {
+ return Ok(x);
+ }
+
+ self.initialize(f)?;
+
+ debug_assert!(self.get().is_some());
+
+ // Safety: The inner value has been initialized
+ Ok(unsafe { self.get_unchecked() })
+ }
+
+ fn initialize<F, E>(&self, f: F) -> Result<(), E>
+ where
+ F: FnOnce() -> Result<(abi::ID, T), E>,
+ {
+ self.spin.with_locked(|_| {
+ if self.id.load(Ordering::Relaxed) == ID_UNINIT {
+ let (initialized_id, initialized_extra) = f()?;
+
+ // Assumption: A positive `abi::ID` fits in `usize`.
+ debug_assert!(initialized_id >= 0);
+ debug_assert!(usize::try_from(initialized_id).is_ok());
+ let initialized_id = initialized_id as usize;
+
+ // Store the initialized contents. Use the release ordering to
+ // make sure the write is visible to the callers of `get`.
+ unsafe { *self.extra.get() = MaybeUninit::new(initialized_extra) };
+ self.id.store(initialized_id, Ordering::Release);
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<T> Drop for SpinIdOnceCell<T> {
+ #[inline]
+ fn drop(&mut self) {
+ if self.get_mut().is_some() {
+ unsafe { (&mut *self.extra.get()).assume_init_drop() };
+ }
+ }
+}
--- /dev/null
+use super::{
+ abi,
+ error::{fail, fail_aborting, ItronError},
+};
+
+use crate::mem::MaybeUninit;
+
+/// Get the ID of the task in Running state. Panics on failure.
+#[inline]
+pub fn current_task_id() -> abi::ID {
+ try_current_task_id().unwrap_or_else(|e| fail(e, &"get_tid"))
+}
+
+/// Get the ID of the task in Running state. Aborts on failure.
+#[inline]
+pub fn current_task_id_aborting() -> abi::ID {
+ try_current_task_id().unwrap_or_else(|e| fail_aborting(e, &"get_tid"))
+}
+
+/// Get the ID of the task in Running state.
+#[inline]
+pub fn try_current_task_id() -> Result<abi::ID, ItronError> {
+ unsafe {
+ let mut out = MaybeUninit::uninit();
+ ItronError::err_if_negative(abi::get_tid(out.as_mut_ptr()))?;
+ Ok(out.assume_init())
+ }
+}
+
+/// Get the specified task's priority. Panics on failure.
+#[inline]
+pub fn task_priority(task: abi::ID) -> abi::PRI {
+ try_task_priority(task).unwrap_or_else(|e| fail(e, &"get_pri"))
+}
+
+/// Get the specified task's priority.
+#[inline]
+pub fn try_task_priority(task: abi::ID) -> Result<abi::PRI, ItronError> {
+ unsafe {
+ let mut out = MaybeUninit::uninit();
+ ItronError::err_if_negative(abi::get_pri(task, out.as_mut_ptr()))?;
+ Ok(out.assume_init())
+ }
+}
--- /dev/null
+//! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
+//! `exd_tsk` are available.
+use super::{
+ abi,
+ error::{expect_success, expect_success_aborting, ItronError},
+ task,
+ time::dur2reltims,
+};
+use crate::{
+ cell::UnsafeCell,
+ convert::TryFrom,
+ ffi::CStr,
+ hint, io,
+ mem::ManuallyDrop,
+ sync::atomic::{AtomicUsize, Ordering},
+ sys::thread_local_dtor::run_dtors,
+ time::Duration,
+};
+
+pub struct Thread {
+ inner: ManuallyDrop<Box<ThreadInner>>,
+
+ /// The ID of the underlying task.
+ task: abi::ID,
+}
+
+/// State data shared between a parent thread and child thread. It's dropped on
+/// a transition to one of the final states.
+struct ThreadInner {
+ /// This field is used on thread creation to pass a closure from
+ /// `Thread::new` to the created task.
+ start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
+
+ /// A state machine. Each transition is annotated with `[...]` in the
+ /// source code.
+ ///
+ /// ```text
+ ///
+ /// <P>: parent, <C>: child, (?): don't-care
+ ///
+ /// DETACHED (-1) --------------------> EXITED (?)
+ /// <C>finish/exd_tsk
+ /// ^
+ /// |
+ /// | <P>detach
+ /// |
+ ///
+ /// INIT (0) -----------------------> FINISHED (-1)
+ /// <C>finish
+ /// | |
+ /// | <P>join/slp_tsk | <P>join/del_tsk
+ /// | | <P>detach/del_tsk
+ /// v v
+ ///
+ /// JOINING JOINED (?)
+ /// (parent_tid)
+ /// ^
+ /// \ /
+ /// \ <C>finish/wup_tsk / <P>slp_tsk-complete/ter_tsk
+ /// \ / & del_tsk
+ /// \ /
+ /// '--> JOIN_FINALIZE ---'
+ /// (-1)
+ ///
+ lifecycle: AtomicUsize,
+}
+
+// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
+// the task represented by `ThreadInner`.
+unsafe impl Sync for ThreadInner {}
+
+const LIFECYCLE_INIT: usize = 0;
+const LIFECYCLE_FINISHED: usize = usize::MAX;
+const LIFECYCLE_DETACHED: usize = usize::MAX;
+const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX;
+const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX;
+const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
+// there's no single value for `JOINING`
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::<usize>();
+
+impl Thread {
+ /// # Safety
+ ///
+ /// See `thread::Builder::spawn_unchecked` for safety requirements.
+ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ // Inherit the current task's priority
+ let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?;
+ let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?;
+
+ let inner = Box::new(ThreadInner {
+ start: UnsafeCell::new(ManuallyDrop::new(p)),
+ lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
+ });
+
+ unsafe extern "C" fn trampoline(exinf: isize) {
+ // Safety: `ThreadInner` is alive at this point
+ let inner = unsafe { &*(exinf as *const ThreadInner) };
+
+ // Safety: Since `trampoline` is called only once for each
+ // `ThreadInner` and only `trampoline` touches `start`,
+ // `start` contains contents and is safe to mutably borrow.
+ let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
+ p();
+
+ // Fix the current thread's state just in case, so that the
+ // destructors won't abort
+ // Safety: Not really unsafe
+ let _ = unsafe { abi::unl_cpu() };
+ let _ = unsafe { abi::ena_dsp() };
+
+ // Run TLS destructors now because they are not
+ // called automatically for terminated tasks.
+ unsafe { run_dtors() };
+
+ let old_lifecycle = inner
+ .lifecycle
+ .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
+
+ match old_lifecycle {
+ LIFECYCLE_DETACHED => {
+ // [DETACHED → EXITED]
+ // No one will ever join, so we'll ask the collector task to
+ // delete the task.
+
+ // In this case, `inner`'s ownership has been moved to us,
+ // And we are responsible for dropping it. The acquire
+ // ordering is not necessary because the parent thread made
+ // no memory acccess needing synchronization since the call
+ // to `acre_tsk`.
+ // Safety: See above.
+ let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
+
+ // Safety: There are no pinned references to the stack
+ unsafe { terminate_and_delete_current_task() };
+ }
+ LIFECYCLE_INIT => {
+ // [INIT → FINISHED]
+ // The parent hasn't decided whether to join or detach this
+ // thread yet. Whichever option the parent chooses,
+ // it'll have to delete this task.
+ // Since the parent might drop `*inner` as soon as it sees
+ // `FINISHED`, the release ordering must be used in the
+ // above `swap` call.
+ }
+ parent_tid => {
+ // Since the parent might drop `*inner` and terminate us as
+ // soon as it sees `JOIN_FINALIZE`, the release ordering
+ // must be used in the above `swap` call.
+
+ // [JOINING → JOIN_FINALIZE]
+ // Wake up the parent task.
+ expect_success(
+ unsafe {
+ let mut er = abi::wup_tsk(parent_tid as _);
+ if er == abi::E_QOVR {
+ // `E_QOVR` indicates there's already
+ // a parking token
+ er = abi::E_OK;
+ }
+ er
+ },
+ &"wup_tsk",
+ );
+ }
+ }
+ }
+
+ let inner_ptr = (&*inner) as *const ThreadInner;
+
+ let new_task = ItronError::err_if_negative(unsafe {
+ abi::acre_tsk(&abi::T_CTSK {
+ // Activate this task immediately
+ tskatr: abi::TA_ACT,
+ exinf: inner_ptr as abi::EXINF,
+ // The entry point
+ task: Some(trampoline),
+ itskpri: priority,
+ stksz: stack,
+ // Let the kernel allocate the stack,
+ stk: crate::ptr::null_mut(),
+ })
+ })
+ .map_err(|e| e.as_io_error())?;
+
+ Ok(Self { inner: ManuallyDrop::new(inner), task: new_task })
+ }
+
+ pub fn yield_now() {
+ expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // nope
+ }
+
+ pub fn sleep(dur: Duration) {
+ for timeout in dur2reltims(dur) {
+ expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
+ }
+ }
+
+ pub fn join(mut self) {
+ let inner = &*self.inner;
+ // Get the current task ID. Panicking here would cause a resource leak,
+ // so just abort on failure.
+ let current_task = task::current_task_id_aborting();
+ debug_assert!(usize::try_from(current_task).is_ok());
+ debug_assert_ne!(current_task as usize, LIFECYCLE_INIT);
+ debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED);
+
+ let current_task = current_task as usize;
+
+ match inner.lifecycle.swap(current_task, Ordering::Acquire) {
+ LIFECYCLE_INIT => {
+ // [INIT → JOINING]
+ // The child task will transition the state to `JOIN_FINALIZE`
+ // and wake us up.
+ loop {
+ expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
+ // To synchronize with the child task's memory accesses to
+ // `inner` up to the point of the assignment of
+ // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the
+ // `load`.
+ if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
+ break;
+ }
+ }
+
+ // [JOIN_FINALIZE → JOINED]
+ }
+ LIFECYCLE_FINISHED => {
+ // [FINISHED → JOINED]
+ // To synchronize with the child task's memory accesses to
+ // `inner` up to the point of the assignment of `FINISHED`,
+ // `Ordering::Acquire` must be used for the above `swap` call`.
+ }
+ _ => unsafe { hint::unreachable_unchecked() },
+ }
+
+ // Terminate and delete the task
+ // Safety: `self.task` still represents a task we own (because this
+ // method or `detach_inner` is called only once for each
+ // `Thread`). The task indicated that it's safe to delete by
+ // entering the `FINISHED` or `JOIN_FINALIZE` state.
+ unsafe { terminate_and_delete_task(self.task) };
+
+ // In either case, we are responsible for dropping `inner`.
+ // Safety: The contents of `self.inner` will not be accessed hereafter
+ let _inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+
+ // Skip the destructor (because it would attempt to detach the thread)
+ crate::mem::forget(self);
+ }
+}
+
+impl Drop for Thread {
+ fn drop(&mut self) {
+ // Detach the thread.
+ match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
+ LIFECYCLE_INIT => {
+ // [INIT → DETACHED]
+ // When the time comes, the child will figure out that no
+ // one will ever join it.
+ // The ownership of `self.inner` is moved to the child thread.
+ // However, the release ordering is not necessary because we
+ // made no memory acccess needing synchronization since the call
+ // to `acre_tsk`.
+ }
+ LIFECYCLE_FINISHED => {
+ // [FINISHED → JOINED]
+ // The task has already decided that we should delete the task.
+ // To synchronize with the child task's memory accesses to
+ // `inner` up to the point of the assignment of `FINISHED`,
+ // the acquire ordering is required for the above `swap` call.
+
+ // Terminate and delete the task
+ // Safety: `self.task` still represents a task we own (because
+ // this method or `join_inner` is called only once for
+ // each `Thread`). The task indicated that it's safe to
+ // delete by entering the `FINISHED` state.
+ unsafe { terminate_and_delete_task(self.task) };
+
+ // Wwe are responsible for dropping `inner`.
+ // Safety: The contents of `self.inner` will not be accessed
+ // hereafter
+ unsafe { ManuallyDrop::drop(&mut self.inner) };
+ }
+ _ => unsafe { hint::unreachable_unchecked() },
+ }
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> {
+ None
+ }
+ pub unsafe fn init() -> Option<Guard> {
+ None
+ }
+}
+
+/// Terminate and delete the specified task.
+///
+/// This function will abort if `deleted_task` refers to the calling task.
+///
+/// It is assumed that the specified task is solely managed by the caller -
+/// i.e., other threads must not "resuscitate" the specified task or delete it
+/// prematurely while this function is still in progress. It is allowed for the
+/// specified task to exit by its own.
+///
+/// # Safety
+///
+/// The task must be safe to terminate. This is in general not true
+/// because there might be pinned references to the task's stack.
+unsafe fn terminate_and_delete_task(deleted_task: abi::ID) {
+ // Terminate the task
+ // Safety: Upheld by the caller
+ match unsafe { abi::ter_tsk(deleted_task) } {
+ // Indicates the task is already dormant, ignore it
+ abi::E_OBJ => {}
+ er => {
+ expect_success_aborting(er, &"ter_tsk");
+ }
+ }
+
+ // Delete the task
+ // Safety: Upheld by the caller
+ expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
+}
+
+/// Terminate and delete the calling task.
+///
+/// Atomicity is not required - i.e., it can be assumed that other threads won't
+/// `ter_tsk` the calling task while this function is still in progress. (This
+/// property makes it easy to implement this operation on μITRON-derived kernels
+/// that don't support `exd_tsk`.)
+///
+/// # Safety
+///
+/// The task must be safe to terminate. This is in general not true
+/// because there might be pinned references to the task's stack.
+unsafe fn terminate_and_delete_current_task() -> ! {
+ expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk");
+ // Safety: `exd_tsk` never returns on success
+ unsafe { crate::hint::unreachable_unchecked() };
+}
+
+pub fn available_concurrency() -> io::Result<crate::num::NonZeroUsize> {
+ super::unsupported()
+}
--- /dev/null
+use super::{abi, error::expect_success};
+use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(abi::SYSTIM);
+
+impl Instant {
+ pub fn now() -> Instant {
+ // Safety: The provided pointer is valid
+ unsafe {
+ let mut out = MaybeUninit::uninit();
+ expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
+ Instant(out.assume_init())
+ }
+ }
+
+ pub const fn zero() -> Instant {
+ Instant(0)
+ }
+
+ pub fn actually_monotonic() -> bool {
+ // There are ways to change the system time
+ false
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.0.checked_sub(other.0).map(|ticks| {
+ // `SYSTIM` is measured in microseconds
+ Duration::from_micros(ticks)
+ })
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ // `SYSTIM` is measured in microseconds
+ let ticks = other.as_micros();
+
+ Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ // `SYSTIM` is measured in microseconds
+ let ticks = other.as_micros();
+
+ Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
+ }
+}
+
+/// Split `Duration` into zero or more `RELTIM`s.
+#[inline]
+pub fn dur2reltims(dur: Duration) -> impl Iterator<Item = abi::RELTIM> {
+ // `RELTIM` is microseconds
+ let mut ticks = dur.as_micros();
+
+ crate::iter::from_fn(move || {
+ if ticks == 0 {
+ None
+ } else if ticks <= abi::TMAX_RELTIM as u128 {
+ Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM)
+ } else {
+ ticks -= abi::TMAX_RELTIM as u128;
+ Some(abi::TMAX_RELTIM)
+ }
+ })
+}
+
+/// Split `Duration` into one or more `TMO`s.
+#[inline]
+fn dur2tmos(dur: Duration) -> impl Iterator<Item = abi::TMO> {
+ // `TMO` is microseconds
+ let mut ticks = dur.as_micros();
+ let mut end = false;
+
+ crate::iter::from_fn(move || {
+ if end {
+ None
+ } else if ticks <= abi::TMAX_RELTIM as u128 {
+ end = true;
+ Some(crate::mem::replace(&mut ticks, 0) as abi::TMO)
+ } else {
+ ticks -= abi::TMAX_RELTIM as u128;
+ Some(abi::TMAX_RELTIM)
+ }
+ })
+}
+
+/// Split `Duration` into one or more API calls with timeout.
+#[inline]
+pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
+ let mut er = abi::E_TMOUT;
+ for tmo in dur2tmos(dur) {
+ er = f(tmo);
+ if er != abi::E_TMOUT {
+ break;
+ }
+ }
+ er
+}
+
+/// Split `Duration` into one or more API calls with timeout. This function can
+/// handle spurious wakeups.
+#[inline]
+pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
+ // `TMO` and `SYSTIM` are microseconds.
+ // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause
+ // a problem in practice. (`u64::MAX` μs ≈ 584942 years)
+ let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM;
+
+ let start = Instant::now().0;
+ let mut elapsed = 0;
+ let mut er = abi::E_TMOUT;
+ while elapsed <= ticks {
+ er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO);
+ if er != abi::E_TMOUT {
+ break;
+ }
+ elapsed = Instant::now().0.wrapping_sub(start);
+ }
+
+ er
+}
+
+#[cfg(test)]
+mod tests;
--- /dev/null
+use super::*;
+
+fn reltim2dur(t: u64) -> Duration {
+ Duration::from_micros(t)
+}
+
+#[test]
+fn test_dur2reltims() {
+ assert_eq!(dur2reltims(reltim2dur(0)).collect::<Vec<_>>(), vec![]);
+ assert_eq!(dur2reltims(reltim2dur(42)).collect::<Vec<_>>(), vec![42]);
+ assert_eq!(
+ dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(),
+ vec![abi::TMAX_RELTIM]
+ );
+ assert_eq!(
+ dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(),
+ vec![abi::TMAX_RELTIM, 10000]
+ );
+}
+
+#[test]
+fn test_dur2tmos() {
+ assert_eq!(dur2tmos(reltim2dur(0)).collect::<Vec<_>>(), vec![0]);
+ assert_eq!(dur2tmos(reltim2dur(42)).collect::<Vec<_>>(), vec![42]);
+ assert_eq!(
+ dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(),
+ vec![abi::TMAX_RELTIM]
+ );
+ assert_eq!(
+ dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(),
+ vec![abi::TMAX_RELTIM, 10000]
+ );
+}
} else if #[cfg(windows)] {
mod windows;
pub use self::windows::*;
+ } else if #[cfg(target_os = "solid_asp3")] {
+ mod solid;
+ pub use self::solid::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use self::hermit::*;
--- /dev/null
+//! `solid_fs.h`
+use crate::os::raw::{c_char, c_int, c_uchar};
+pub use libc::{
+ blksize_t, dev_t, ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR,
+ O_TRUNC, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, S_IEXEC, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO,
+ S_IFMT, S_IFREG, S_IREAD, S_IWRITE,
+};
+
+pub const O_ACCMODE: c_int = 0x3;
+
+pub const SOLID_MAX_PATH: usize = 256;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct dirent {
+ pub d_ino: ino_t,
+ pub d_type: c_uchar,
+ pub d_name: [c_char; 256usize],
+}
+
+pub const DT_UNKNOWN: c_uchar = 0;
+pub const DT_FIFO: c_uchar = 1;
+pub const DT_CHR: c_uchar = 2;
+pub const DT_DIR: c_uchar = 4;
+pub const DT_BLK: c_uchar = 6;
+pub const DT_REG: c_uchar = 8;
+pub const DT_LNK: c_uchar = 10;
+pub const DT_SOCK: c_uchar = 12;
+pub const DT_WHT: c_uchar = 14;
+
+pub type S_DIR = c_int;
+
+extern "C" {
+ pub fn SOLID_FS_Open(fd: *mut c_int, path: *const c_char, mode: c_int) -> c_int;
+ pub fn SOLID_FS_Close(fd: c_int) -> c_int;
+ pub fn SOLID_FS_Read(fd: c_int, buf: *mut u8, size: usize, result: *mut usize) -> c_int;
+ pub fn SOLID_FS_Write(fd: c_int, buf: *const u8, size: usize, result: *mut usize) -> c_int;
+ pub fn SOLID_FS_Lseek(fd: c_int, offset: off_t, whence: c_int) -> c_int;
+ pub fn SOLID_FS_Sync(fd: c_int) -> c_int;
+ pub fn SOLID_FS_Ftell(fd: c_int, result: *mut off_t) -> c_int;
+ pub fn SOLID_FS_Feof(fd: c_int, result: *mut c_int) -> c_int;
+ pub fn SOLID_FS_Fsize(fd: c_int, result: *mut usize) -> c_int;
+ pub fn SOLID_FS_Truncate(path: *const c_char, size: off_t) -> c_int;
+ pub fn SOLID_FS_OpenDir(path: *const c_char, pDir: *mut S_DIR) -> c_int;
+ pub fn SOLID_FS_CloseDir(dir: S_DIR) -> c_int;
+ pub fn SOLID_FS_ReadDir(dir: S_DIR, dirp: *mut dirent) -> c_int;
+ pub fn SOLID_FS_Stat(path: *const c_char, buf: *mut stat) -> c_int;
+ pub fn SOLID_FS_Unlink(path: *const c_char) -> c_int;
+ pub fn SOLID_FS_Rename(oldpath: *const c_char, newpath: *const c_char) -> c_int;
+ pub fn SOLID_FS_Chmod(path: *const c_char, mode: c_int) -> c_int;
+ pub fn SOLID_FS_Utime(path: *const c_char, time: time_t) -> c_int;
+ pub fn SOLID_FS_Mkdir(path: *const c_char) -> c_int;
+}
--- /dev/null
+use crate::os::raw::c_int;
+
+mod fs;
+pub mod sockets;
+pub use self::fs::*;
+
+pub const SOLID_BP_PROGRAM_EXITED: usize = 15;
+pub const SOLID_BP_CSABORT: usize = 16;
+
+#[inline(always)]
+pub fn breakpoint_program_exited(tid: usize) {
+ unsafe {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid),
+ #[cfg(target_arch = "aarch64")]
+ () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid),
+ }
+ }
+}
+
+#[inline(always)]
+pub fn breakpoint_abort() {
+ unsafe {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => asm!("bkpt #{}", const SOLID_BP_CSABORT),
+ #[cfg(target_arch = "aarch64")]
+ () => asm!("hlt #{}", const SOLID_BP_CSABORT),
+ }
+ }
+}
+
+// `solid_types.h`
+pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};
+
+pub const SOLID_ERR_NOTFOUND: ER = -1000;
+pub const SOLID_ERR_NOTSUPPORTED: ER = -1001;
+pub const SOLID_ERR_EBADF: ER = -1002;
+pub const SOLID_ERR_INVALIDCONTENT: ER = -1003;
+pub const SOLID_ERR_NOTUSED: ER = -1004;
+pub const SOLID_ERR_ALREADYUSED: ER = -1005;
+pub const SOLID_ERR_OUTOFBOUND: ER = -1006;
+pub const SOLID_ERR_BADSEQUENCE: ER = -1007;
+pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008;
+pub const SOLID_ERR_BUSY: ER = -1009;
+pub const SOLID_ERR_TIMEOUT: ER = -1010;
+pub const SOLID_ERR_INVALIDACCESS: ER = -1011;
+pub const SOLID_ERR_NOTREADY: ER = -1012;
+
+// `solid_rtc.h`
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct SOLID_RTC_TIME {
+ pub tm_sec: c_int,
+ pub tm_min: c_int,
+ pub tm_hour: c_int,
+ pub tm_mday: c_int,
+ pub tm_mon: c_int,
+ pub tm_year: c_int,
+ pub tm_wday: c_int,
+}
+
+extern "C" {
+ pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int;
+}
+
+// `solid_log.h`
+extern "C" {
+ pub fn SOLID_LOG_write(s: *const u8, l: usize);
+}
+
+// `solid_mem.h`
+extern "C" {
+ pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8));
+}
+
+// `solid_rng.h`
+extern "C" {
+ pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int;
+}
+
+// `rwlock.h`
+extern "C" {
+ pub fn rwl_loc_rdl(id: ID) -> ER;
+ pub fn rwl_loc_wrl(id: ID) -> ER;
+ pub fn rwl_ploc_rdl(id: ID) -> ER;
+ pub fn rwl_ploc_wrl(id: ID) -> ER;
+ pub fn rwl_unl_rwl(id: ID) -> ER;
+ pub fn rwl_acre_rwl() -> ER_ID;
+ pub fn rwl_del_rwl(id: ID) -> ER;
+}
--- /dev/null
+use crate::os::raw::{c_char, c_uint, c_void};
+pub use libc::{c_int, c_long, size_t, ssize_t, suseconds_t, time_t, timeval};
+
+pub const SOLID_NET_ERR_BASE: c_int = -2000;
+pub const EINPROGRESS: c_int = SOLID_NET_ERR_BASE - libc::EINPROGRESS;
+
+pub const AF_INET6: i32 = 10;
+pub const AF_INET: i32 = 2;
+pub const IPPROTO_IP: i32 = 0;
+pub const IPPROTO_IPV6: i32 = 41;
+pub const IPPROTO_TCP: i32 = 6;
+pub const IPV6_ADD_MEMBERSHIP: i32 = 12;
+pub const IPV6_DROP_MEMBERSHIP: i32 = 13;
+pub const IPV6_MULTICAST_LOOP: i32 = 19;
+pub const IPV6_V6ONLY: i32 = 27;
+pub const IP_TTL: i32 = 2;
+pub const IP_MULTICAST_TTL: i32 = 5;
+pub const IP_MULTICAST_LOOP: i32 = 7;
+pub const IP_ADD_MEMBERSHIP: i32 = 3;
+pub const IP_DROP_MEMBERSHIP: i32 = 4;
+pub const SHUT_RD: i32 = 0;
+pub const SHUT_RDWR: i32 = 2;
+pub const SHUT_WR: i32 = 1;
+pub const SOCK_DGRAM: i32 = 2;
+pub const SOCK_STREAM: i32 = 1;
+pub const SOL_SOCKET: i32 = 4095;
+pub const SO_BROADCAST: i32 = 32;
+pub const SO_ERROR: i32 = 4103;
+pub const SO_RCVTIMEO: i32 = 4102;
+pub const SO_REUSEADDR: i32 = 4;
+pub const SO_SNDTIMEO: i32 = 4101;
+pub const SO_LINGER: i32 = 128;
+pub const TCP_NODELAY: i32 = 1;
+pub const MSG_PEEK: c_int = 1;
+pub const FIONBIO: c_long = 0x8008667eu32 as c_long;
+pub const EAI_NONAME: i32 = -2200;
+pub const EAI_SERVICE: i32 = -2201;
+pub const EAI_FAIL: i32 = -2202;
+pub const EAI_MEMORY: i32 = -2203;
+pub const EAI_FAMILY: i32 = -2204;
+
+pub type sa_family_t = u8;
+pub type socklen_t = u32;
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct in_addr {
+ pub s_addr: in_addr_t,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ip_mreq {
+ pub imr_multiaddr: in_addr,
+ pub imr_interface: in_addr,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ipv6_mreq {
+ pub ipv6mr_multiaddr: in6_addr,
+ pub ipv6mr_interface: c_uint,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct msghdr {
+ pub msg_name: *mut c_void,
+ pub msg_namelen: socklen_t,
+ pub msg_iov: *mut iovec,
+ pub msg_iovlen: c_int,
+ pub msg_control: *mut c_void,
+ pub msg_controllen: socklen_t,
+ pub msg_flags: c_int,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sockaddr {
+ pub sa_len: u8,
+ pub sa_family: sa_family_t,
+ pub sa_data: [c_char; 14usize],
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sockaddr_in {
+ pub sin_len: u8,
+ pub sin_family: sa_family_t,
+ pub sin_port: in_port_t,
+ pub sin_addr: in_addr,
+ pub sin_zero: [c_char; 8usize],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct sockaddr_in6 {
+ pub sin6_len: u8,
+ pub sin6_family: sa_family_t,
+ pub sin6_port: in_port_t,
+ pub sin6_flowinfo: u32,
+ pub sin6_addr: in6_addr,
+ pub sin6_scope_id: u32,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sockaddr_storage {
+ pub s2_len: u8,
+ pub ss_family: sa_family_t,
+ pub s2_data1: [c_char; 2usize],
+ pub s2_data2: [u32; 3usize],
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct addrinfo {
+ pub ai_flags: c_int,
+ pub ai_family: c_int,
+ pub ai_socktype: c_int,
+ pub ai_protocol: c_int,
+ pub ai_addrlen: socklen_t,
+ pub ai_addr: *mut sockaddr,
+ pub ai_canonname: *mut c_char,
+ pub ai_next: *mut addrinfo,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct linger {
+ pub l_onoff: c_int,
+ pub l_linger: c_int,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct iovec {
+ pub iov_base: *mut c_void,
+ pub iov_len: usize,
+}
+
+/// This value can be chosen by an application
+pub const SOLID_NET_FD_SETSIZE: usize = 1;
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct fd_set {
+ pub num_fds: usize,
+ pub fds: [c_int; SOLID_NET_FD_SETSIZE],
+}
+
+extern "C" {
+ #[link_name = "SOLID_NET_StrError"]
+ pub fn strerror(errnum: c_int) -> *const c_char;
+
+ pub fn SOLID_NET_GetLastError() -> c_int;
+
+ #[link_name = "SOLID_NET_Accept"]
+ pub fn accept(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int;
+
+ #[link_name = "SOLID_NET_Bind"]
+ pub fn bind(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int;
+
+ #[link_name = "SOLID_NET_Connect"]
+ pub fn connect(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int;
+
+ #[link_name = "SOLID_NET_Close"]
+ pub fn close(s: c_int) -> c_int;
+
+ #[link_name = "SOLID_NET_GetPeerName"]
+ pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
+
+ #[link_name = "SOLID_NET_GetSockName"]
+ pub fn getsockname(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
+
+ #[link_name = "SOLID_NET_GetSockOpt"]
+ pub fn getsockopt(
+ s: c_int,
+ level: c_int,
+ optname: c_int,
+ optval: *mut c_void,
+ optlen: *mut socklen_t,
+ ) -> c_int;
+
+ #[link_name = "SOLID_NET_SetSockOpt"]
+ pub fn setsockopt(
+ s: c_int,
+ level: c_int,
+ optname: c_int,
+ optval: *const c_void,
+ optlen: socklen_t,
+ ) -> c_int;
+
+ #[link_name = "SOLID_NET_Ioctl"]
+ pub fn ioctl(s: c_int, cmd: c_long, argp: *mut c_void) -> c_int;
+
+ #[link_name = "SOLID_NET_Listen"]
+ pub fn listen(s: c_int, backlog: c_int) -> c_int;
+
+ #[link_name = "SOLID_NET_Recv"]
+ pub fn recv(s: c_int, mem: *mut c_void, len: size_t, flags: c_int) -> ssize_t;
+
+ #[link_name = "SOLID_NET_Read"]
+ pub fn read(s: c_int, mem: *mut c_void, len: size_t) -> ssize_t;
+
+ #[link_name = "SOLID_NET_Readv"]
+ pub fn readv(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t;
+
+ #[link_name = "SOLID_NET_RecvFrom"]
+ pub fn recvfrom(
+ s: c_int,
+ mem: *mut c_void,
+ len: size_t,
+ flags: c_int,
+ from: *mut sockaddr,
+ fromlen: *mut socklen_t,
+ ) -> ssize_t;
+
+ #[link_name = "SOLID_NET_Send"]
+ pub fn send(s: c_int, mem: *const c_void, len: size_t, flags: c_int) -> ssize_t;
+
+ #[link_name = "SOLID_NET_SendMsg"]
+ pub fn sendmsg(s: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
+
+ #[link_name = "SOLID_NET_SendTo"]
+ pub fn sendto(
+ s: c_int,
+ mem: *const c_void,
+ len: size_t,
+ flags: c_int,
+ to: *const sockaddr,
+ tolen: socklen_t,
+ ) -> ssize_t;
+
+ #[link_name = "SOLID_NET_Shutdown"]
+ pub fn shutdown(s: c_int, how: c_int) -> c_int;
+
+ #[link_name = "SOLID_NET_Socket"]
+ pub fn socket(domain: c_int, type_: c_int, protocol: c_int) -> c_int;
+
+ #[link_name = "SOLID_NET_Write"]
+ pub fn write(s: c_int, mem: *const c_void, len: size_t) -> ssize_t;
+
+ #[link_name = "SOLID_NET_Writev"]
+ pub fn writev(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t;
+
+ #[link_name = "SOLID_NET_FreeAddrInfo"]
+ pub fn freeaddrinfo(ai: *mut addrinfo);
+
+ #[link_name = "SOLID_NET_GetAddrInfo"]
+ pub fn getaddrinfo(
+ nodename: *const c_char,
+ servname: *const c_char,
+ hints: *const addrinfo,
+ res: *mut *mut addrinfo,
+ ) -> c_int;
+
+ #[link_name = "SOLID_NET_Select"]
+ pub fn select(
+ maxfdp1: c_int,
+ readset: *mut fd_set,
+ writeset: *mut fd_set,
+ exceptset: *mut fd_set,
+ timeout: *mut timeval,
+ ) -> c_int;
+}
--- /dev/null
+use crate::{
+ alloc::{GlobalAlloc, Layout, System},
+ sys::common::alloc::{realloc_fallback, MIN_ALIGN},
+};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ unsafe { libc::malloc(layout.size()) as *mut u8 }
+ } else {
+ unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 }
+ }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ unsafe { libc::free(ptr as *mut libc::c_void) }
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ unsafe {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+ }
+}
--- /dev/null
+pub mod os {
+ pub const FAMILY: &str = "itron";
+ pub const OS: &str = "solid";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
--- /dev/null
+use super::{abi, itron, net};
+use crate::io::ErrorKind;
+
+pub use self::itron::error::{expect_success, ItronError as SolidError};
+
+/// Describe the specified SOLID error code. Returns `None` if it's an
+/// undefined error code.
+///
+/// The SOLID error codes are a superset of μITRON error codes.
+pub fn error_name(er: abi::ER) -> Option<&'static str> {
+ match er {
+ // Success
+ er if er >= 0 => None,
+ er if er < abi::sockets::SOLID_NET_ERR_BASE => net::error_name(er),
+
+ abi::SOLID_ERR_NOTFOUND => Some("not found"),
+ abi::SOLID_ERR_NOTSUPPORTED => Some("not supported"),
+ abi::SOLID_ERR_EBADF => Some("bad flags"),
+ abi::SOLID_ERR_INVALIDCONTENT => Some("invalid content"),
+ abi::SOLID_ERR_NOTUSED => Some("not used"),
+ abi::SOLID_ERR_ALREADYUSED => Some("already used"),
+ abi::SOLID_ERR_OUTOFBOUND => Some("out of bounds"),
+ abi::SOLID_ERR_BADSEQUENCE => Some("bad sequence"),
+ abi::SOLID_ERR_UNKNOWNDEVICE => Some("unknown device"),
+ abi::SOLID_ERR_BUSY => Some("busy"),
+ abi::SOLID_ERR_TIMEOUT => Some("operation timed out"),
+ abi::SOLID_ERR_INVALIDACCESS => Some("invalid access"),
+ abi::SOLID_ERR_NOTREADY => Some("not ready"),
+
+ _ => itron::error::error_name(er),
+ }
+}
+
+pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
+ match er {
+ // Success
+ er if er >= 0 => ErrorKind::Uncategorized,
+ er if er < abi::sockets::SOLID_NET_ERR_BASE => net::decode_error_kind(er),
+
+ abi::SOLID_ERR_NOTFOUND => ErrorKind::NotFound,
+ abi::SOLID_ERR_NOTSUPPORTED => ErrorKind::Unsupported,
+ abi::SOLID_ERR_EBADF => ErrorKind::InvalidInput,
+ abi::SOLID_ERR_INVALIDCONTENT => ErrorKind::InvalidData,
+ // abi::SOLID_ERR_NOTUSED
+ // abi::SOLID_ERR_ALREADYUSED
+ abi::SOLID_ERR_OUTOFBOUND => ErrorKind::InvalidInput,
+ // abi::SOLID_ERR_BADSEQUENCE
+ abi::SOLID_ERR_UNKNOWNDEVICE => ErrorKind::NotFound,
+ // abi::SOLID_ERR_BUSY
+ abi::SOLID_ERR_TIMEOUT => ErrorKind::TimedOut,
+ // abi::SOLID_ERR_INVALIDACCESS
+ // abi::SOLID_ERR_NOTREADY
+ _ => itron::error::decode_error_kind(er),
+ }
+}
--- /dev/null
+use super::{abi, error};
+use crate::{
+ ffi::{CStr, CString, OsStr, OsString},
+ fmt,
+ io::{self, IoSlice, IoSliceMut, SeekFrom},
+ mem::MaybeUninit,
+ os::raw::{c_int, c_short},
+ os::solid::ffi::OsStrExt,
+ path::{Path, PathBuf},
+ sync::Arc,
+ sys::time::SystemTime,
+ sys::unsupported,
+};
+
+pub use crate::sys_common::fs::try_exists;
+
+/// A file descriptor.
+#[derive(Clone, Copy)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+struct FileDesc {
+ fd: c_int,
+}
+
+impl FileDesc {
+ #[inline]
+ fn new(fd: c_int) -> FileDesc {
+ assert_ne!(fd, -1i32);
+ // Safety: we just asserted that the value is in the valid range and
+ // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { FileDesc { fd } }
+ }
+
+ #[inline]
+ fn raw(&self) -> c_int {
+ self.fd
+ }
+}
+
+pub struct File {
+ fd: FileDesc,
+}
+
+#[derive(Clone)]
+pub struct FileAttr {
+ stat: abi::stat,
+}
+
+// all DirEntry's will have a reference to this struct
+struct InnerReadDir {
+ dirp: abi::S_DIR,
+ root: PathBuf,
+}
+
+pub struct ReadDir {
+ inner: Arc<InnerReadDir>,
+}
+
+pub struct DirEntry {
+ entry: abi::dirent,
+ inner: Arc<InnerReadDir>,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+ // generic
+ read: bool,
+ write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: i32,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions(c_short);
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType(c_short);
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl FileAttr {
+ pub fn size(&self) -> u64 {
+ self.stat.st_size as u64
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ FilePermissions(self.stat.st_mode)
+ }
+
+ pub fn file_type(&self) -> FileType {
+ FileType(self.stat.st_mode)
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from_time_t(self.stat.st_mtime))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from_time_t(self.stat.st_atime))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from_time_t(self.stat.st_ctime))
+ }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ (self.0 & abi::S_IWRITE) == 0
+ }
+
+ pub fn set_readonly(&mut self, readonly: bool) {
+ if readonly {
+ self.0 &= !abi::S_IWRITE;
+ } else {
+ self.0 |= abi::S_IWRITE;
+ }
+ }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ self.is(abi::S_IFDIR)
+ }
+ pub fn is_file(&self) -> bool {
+ self.is(abi::S_IFREG)
+ }
+ pub fn is_symlink(&self) -> bool {
+ false
+ }
+
+ pub fn is(&self, mode: c_short) -> bool {
+ self.0 & abi::S_IFMT == mode
+ }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ unsafe {
+ let mut dir = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_OpenDir(
+ cstr(p)?.as_ptr(),
+ dir.as_mut_ptr(),
+ ))
+ .map_err(|e| e.as_io_error())?;
+ let inner = Arc::new(InnerReadDir { dirp: dir.assume_init(), root: p.to_owned() });
+ Ok(ReadDir { inner })
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+ // Thus the result will be e g 'ReadDir("/home")'
+ fmt::Debug::fmt(&*self.inner.root, f)
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ unsafe {
+ let mut out_dirent = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir(
+ self.inner.dirp,
+ out_dirent.as_mut_ptr(),
+ ))
+ .ok()?;
+ Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) }))
+ }
+ }
+}
+
+impl Drop for InnerReadDir {
+ fn drop(&mut self) {
+ unsafe { abi::SOLID_FS_CloseDir(self.dirp) };
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ self.inner.root.join(OsStr::from_bytes(
+ unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes(),
+ ))
+ }
+
+ pub fn file_name(&self) -> OsString {
+ OsStr::from_bytes(unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes())
+ .to_os_string()
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ lstat(&self.path())
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ match self.entry.d_type {
+ abi::DT_CHR => Ok(FileType(abi::S_IFCHR)),
+ abi::DT_FIFO => Ok(FileType(abi::S_IFIFO)),
+ abi::DT_REG => Ok(FileType(abi::S_IFREG)),
+ abi::DT_DIR => Ok(FileType(abi::S_IFDIR)),
+ abi::DT_BLK => Ok(FileType(abi::S_IFBLK)),
+ _ => lstat(&self.path()).map(|m| m.file_type()),
+ }
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ }
+ }
+
+ pub fn read(&mut self, read: bool) {
+ self.read = read;
+ }
+ pub fn write(&mut self, write: bool) {
+ self.write = write;
+ }
+ pub fn append(&mut self, append: bool) {
+ self.append = append;
+ }
+ pub fn truncate(&mut self, truncate: bool) {
+ self.truncate = truncate;
+ }
+ pub fn create(&mut self, create: bool) {
+ self.create = create;
+ }
+ pub fn create_new(&mut self, create_new: bool) {
+ self.create_new = create_new;
+ }
+
+ pub fn custom_flags(&mut self, flags: i32) {
+ self.custom_flags = flags;
+ }
+ pub fn mode(&mut self, _mode: u32) {}
+
+ fn get_access_mode(&self) -> io::Result<c_int> {
+ match (self.read, self.write, self.append) {
+ (true, false, false) => Ok(abi::O_RDONLY),
+ (false, true, false) => Ok(abi::O_WRONLY),
+ (true, true, false) => Ok(abi::O_RDWR),
+ (false, _, true) => Ok(abi::O_WRONLY | abi::O_APPEND),
+ (true, _, true) => Ok(abi::O_RDWR | abi::O_APPEND),
+ (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)),
+ }
+ }
+
+ fn get_creation_mode(&self) -> io::Result<c_int> {
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) => {
+ if self.truncate || self.create || self.create_new {
+ return Err(io::Error::from_raw_os_error(libc::EINVAL));
+ }
+ }
+ (_, true) => {
+ if self.truncate && !self.create_new {
+ return Err(io::Error::from_raw_os_error(libc::EINVAL));
+ }
+ }
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => 0,
+ (true, false, false) => abi::O_CREAT,
+ (false, true, false) => abi::O_TRUNC,
+ (true, true, false) => abi::O_CREAT | abi::O_TRUNC,
+ (_, _, true) => abi::O_CREAT | abi::O_EXCL,
+ })
+ }
+}
+
+fn cstr(path: &Path) -> io::Result<CString> {
+ Ok(CString::new(path.as_os_str().as_bytes())?)
+}
+
+impl File {
+ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let flags = opts.get_access_mode()?
+ | opts.get_creation_mode()?
+ | (opts.custom_flags as c_int & !abi::O_ACCMODE);
+ unsafe {
+ let mut fd = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_Open(
+ fd.as_mut_ptr(),
+ cstr(path)?.as_ptr(),
+ flags,
+ ))
+ .map_err(|e| e.as_io_error())?;
+ Ok(File { fd: FileDesc::new(fd.assume_init()) })
+ }
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ unsupported()
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ self.flush()
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ self.flush()
+ }
+
+ pub fn truncate(&self, _size: u64) -> io::Result<()> {
+ unsupported()
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ unsafe {
+ let mut out_num_bytes = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_Read(
+ self.fd.raw(),
+ buf.as_mut_ptr(),
+ buf.len(),
+ out_num_bytes.as_mut_ptr(),
+ ))
+ .map_err(|e| e.as_io_error())?;
+ Ok(out_num_bytes.assume_init())
+ }
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ crate::io::default_read_vectored(|buf| self.read(buf), bufs)
+ }
+
+ pub fn is_read_vectored(&self) -> bool {
+ false
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ unsafe {
+ let mut out_num_bytes = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_Write(
+ self.fd.raw(),
+ buf.as_ptr(),
+ buf.len(),
+ out_num_bytes.as_mut_ptr(),
+ ))
+ .map_err(|e| e.as_io_error())?;
+ Ok(out_num_bytes.assume_init())
+ }
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ crate::io::default_write_vectored(|buf| self.write(buf), bufs)
+ }
+
+ pub fn is_write_vectored(&self) -> bool {
+ false
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Sync(self.fd.raw()) })
+ .map_err(|e| e.as_io_error())?;
+ Ok(())
+ }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, pos) = match pos {
+ // Casting to `i64` is fine, too large values will end up as
+ // negative which will cause an error in `SOLID_FS_Lseek`.
+ SeekFrom::Start(off) => (abi::SEEK_SET, off as i64),
+ SeekFrom::End(off) => (abi::SEEK_END, off),
+ SeekFrom::Current(off) => (abi::SEEK_CUR, off),
+ };
+ error::SolidError::err_if_negative(unsafe {
+ abi::SOLID_FS_Lseek(self.fd.raw(), pos, whence)
+ })
+ .map_err(|e| e.as_io_error())?;
+
+ // Get the new offset
+ unsafe {
+ let mut out_offset = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_Ftell(
+ self.fd.raw(),
+ out_offset.as_mut_ptr(),
+ ))
+ .map_err(|e| e.as_io_error())?;
+ Ok(out_offset.assume_init() as u64)
+ }
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ unsupported()
+ }
+
+ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+ unsupported()
+ }
+}
+
+impl Drop for File {
+ fn drop(&mut self) {
+ unsafe { abi::SOLID_FS_Close(self.fd.raw()) };
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder {}
+ }
+
+ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+ error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Mkdir(cstr(p)?.as_ptr()) })
+ .map_err(|e| e.as_io_error())?;
+ Ok(())
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("File").field("fd", &self.fd.raw()).finish()
+ }
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+ if stat(p)?.file_type().is_dir() {
+ Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory"))
+ } else {
+ error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
+ .map_err(|e| e.as_io_error())?;
+ Ok(())
+ }
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+ error::SolidError::err_if_negative(unsafe {
+ abi::SOLID_FS_Rename(cstr(old)?.as_ptr(), cstr(new)?.as_ptr())
+ })
+ .map_err(|e| e.as_io_error())?;
+ Ok(())
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+ error::SolidError::err_if_negative(unsafe {
+ abi::SOLID_FS_Chmod(cstr(p)?.as_ptr(), perm.0.into())
+ })
+ .map_err(|e| e.as_io_error())?;
+ Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+ if stat(p)?.file_type().is_dir() {
+ error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
+ .map_err(|e| e.as_io_error())?;
+ Ok(())
+ } else {
+ Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory"))
+ }
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+ for child in readdir(path)? {
+ let child = child?;
+ let child_type = child.file_type()?;
+ if child_type.is_dir() {
+ remove_dir_all(&child.path())?;
+ } else {
+ unlink(&child.path())?;
+ }
+ }
+ rmdir(path)
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+ // This target doesn't support symlinks
+ stat(p)?;
+ Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link"))
+}
+
+pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
+ // This target doesn't support symlinks
+ unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ // This target doesn't support symlinks
+ unsupported()
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+ // This target doesn't support symlinks
+ lstat(p)
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+ unsafe {
+ let mut out_stat = MaybeUninit::uninit();
+ error::SolidError::err_if_negative(abi::SOLID_FS_Stat(
+ cstr(p)?.as_ptr(),
+ out_stat.as_mut_ptr(),
+ ))
+ .map_err(|e| e.as_io_error())?;
+ Ok(FileAttr { stat: out_stat.assume_init() })
+ }
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ use crate::fs::File;
+
+ let mut reader = File::open(from)?;
+ let mut writer = File::create(to)?;
+
+ io::copy(&mut reader, &mut writer)
+}
--- /dev/null
+use crate::marker::PhantomData;
+use crate::slice;
+
+use super::abi::sockets::iovec;
+use libc::c_void;
+
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct IoSlice<'a> {
+ vec: iovec,
+ _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoSlice<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+ IoSlice {
+ vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn advance(&mut self, n: usize) {
+ if self.vec.iov_len < n {
+ panic!("advancing IoSlice beyond its length");
+ }
+
+ unsafe {
+ self.vec.iov_len -= n;
+ self.vec.iov_base = self.vec.iov_base.add(n);
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+ }
+}
+
+#[repr(transparent)]
+pub struct IoSliceMut<'a> {
+ vec: iovec,
+ _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoSliceMut<'a> {
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+ IoSliceMut {
+ vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() },
+ _p: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn advance(&mut self, n: usize) {
+ if self.vec.iov_len < n {
+ panic!("advancing IoSliceMut beyond its length");
+ }
+
+ unsafe {
+ self.vec.iov_len -= n;
+ self.vec.iov_base = self.vec.iov_base.add(n);
+ }
+ }
+
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+ }
+
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+ }
+}
--- /dev/null
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+ let p = unsafe {
+ libc::memchr(
+ haystack.as_ptr() as *const libc::c_void,
+ needle as libc::c_int,
+ haystack.len(),
+ )
+ };
+ if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+ let p = unsafe {
+ libc::memrchr(
+ haystack.as_ptr() as *const libc::c_void,
+ needle as libc::c_int,
+ haystack.len(),
+ )
+ };
+ if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
+}
--- /dev/null
+#![allow(dead_code)]
+#![allow(missing_docs, nonstandard_style)]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+mod abi;
+
+#[path = "../itron"]
+mod itron {
+ pub(super) mod abi;
+ pub mod condvar;
+ pub(super) mod error;
+ pub mod mutex;
+ pub(super) mod spin;
+ pub(super) mod task;
+ pub mod thread;
+ pub(super) mod time;
+ use super::unsupported;
+}
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+pub mod env;
+// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
+// `crate::sys::error`
+pub(crate) mod error;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+pub mod rwlock;
+pub mod stdio;
+pub use self::itron::{condvar, mutex, thread};
+pub mod memchr;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
+pub mod time;
+
+// SAFETY: must be called only once during runtime initialization.
+// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+
+// SAFETY: must be called only once during runtime cleanup.
+pub unsafe fn cleanup() {}
+
+pub fn unsupported<T>() -> crate::io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> crate::io::Error {
+ crate::io::Error::new_const(
+ crate::io::ErrorKind::Unsupported,
+ &"operation not supported on this platform",
+ )
+}
+
+pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
+ error::decode_error_kind(code)
+}
+
+#[inline(always)]
+pub fn abort_internal() -> ! {
+ loop {
+ abi::breakpoint_abort();
+ }
+}
+
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+// NB. used by both libunwind and libpanic_abort
+pub extern "C" fn __rust_abort() {
+ abort_internal();
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ unsafe {
+ let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit();
+ let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16);
+ assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result);
+ let [x1, x2] = out.assume_init();
+ (x1, x2)
+ }
+}
+
+pub use libc::strlen;
--- /dev/null
+use super::abi;
+use crate::{
+ cmp,
+ ffi::CStr,
+ io::{self, ErrorKind, IoSlice, IoSliceMut},
+ mem,
+ net::{Shutdown, SocketAddr},
+ ptr, str,
+ sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr},
+ sys_common::{AsInner, FromInner, IntoInner},
+ time::Duration,
+};
+
+use self::netc::{sockaddr, socklen_t, MSG_PEEK};
+use libc::{c_int, c_void, size_t};
+
+pub mod netc {
+ pub use super::super::abi::sockets::*;
+}
+
+pub type wrlen_t = size_t;
+
+const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
+
+const fn max_iov() -> usize {
+ // Judging by the source code, it's unlimited, but specify a lower
+ // value just in case.
+ 1024
+}
+
+/// A file descriptor.
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+struct FileDesc {
+ fd: c_int,
+}
+
+impl FileDesc {
+ #[inline]
+ fn new(fd: c_int) -> FileDesc {
+ assert_ne!(fd, -1i32);
+ // Safety: we just asserted that the value is in the valid range and
+ // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { FileDesc { fd } }
+ }
+
+ #[inline]
+ fn raw(&self) -> c_int {
+ self.fd
+ }
+
+ /// Extracts the actual file descriptor without closing it.
+ #[inline]
+ fn into_raw(self) -> c_int {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+
+ fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
+ })?;
+ Ok(ret as usize)
+ }
+
+ fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ netc::readv(
+ self.fd,
+ bufs.as_ptr() as *const netc::iovec,
+ cmp::min(bufs.len(), max_iov()) as c_int,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ #[inline]
+ fn is_read_vectored(&self) -> bool {
+ true
+ }
+
+ fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
+ })?;
+ Ok(ret as usize)
+ }
+
+ fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ netc::writev(
+ self.fd,
+ bufs.as_ptr() as *const netc::iovec,
+ cmp::min(bufs.len(), max_iov()) as c_int,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ true
+ }
+
+ fn duplicate(&self) -> io::Result<FileDesc> {
+ super::unsupported()
+ }
+}
+
+impl AsInner<c_int> for FileDesc {
+ fn as_inner(&self) -> &c_int {
+ &self.fd
+ }
+}
+
+impl Drop for FileDesc {
+ fn drop(&mut self) {
+ unsafe { netc::close(self.fd) };
+ }
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+ ($($t:ident)*) => ($(impl IsMinusOne for $t {
+ fn is_minus_one(&self) -> bool {
+ *self == -1
+ }
+ })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
+ if t.is_minus_one() { Err(last_error()) } else { Ok(t) }
+}
+
+/// A variant of `cvt` for `getaddrinfo` which return 0 for a success.
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+ if err == 0 {
+ Ok(())
+ } else {
+ let msg: &dyn crate::fmt::Display = match err {
+ netc::EAI_NONAME => &"name or service not known",
+ netc::EAI_SERVICE => &"service not supported",
+ netc::EAI_FAIL => &"non-recoverable failure in name resolution",
+ netc::EAI_MEMORY => &"memory allocation failure",
+ netc::EAI_FAMILY => &"family not supported",
+ _ => &err,
+ };
+ Err(io::Error::new(
+ io::ErrorKind::Uncategorized,
+ &format!("failed to lookup address information: {}", msg)[..],
+ ))
+ }
+}
+
+/// Just to provide the same interface as sys/unix/net.rs
+pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
+where
+ T: IsMinusOne,
+ F: FnMut() -> T,
+{
+ cvt(f())
+}
+
+/// Returns the last error from the network subsystem.
+fn last_error() -> io::Error {
+ io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() })
+}
+
+pub(super) fn error_name(er: abi::ER) -> Option<&'static str> {
+ unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok()
+}
+
+pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
+ let errno = netc::SOLID_NET_ERR_BASE - er;
+ match errno as libc::c_int {
+ libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
+ libc::ECONNRESET => ErrorKind::ConnectionReset,
+ libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
+ libc::EPIPE => ErrorKind::BrokenPipe,
+ libc::ENOTCONN => ErrorKind::NotConnected,
+ libc::ECONNABORTED => ErrorKind::ConnectionAborted,
+ libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+ libc::EADDRINUSE => ErrorKind::AddrInUse,
+ libc::ENOENT => ErrorKind::NotFound,
+ libc::EINTR => ErrorKind::Interrupted,
+ libc::EINVAL => ErrorKind::InvalidInput,
+ libc::ETIMEDOUT => ErrorKind::TimedOut,
+ libc::EEXIST => ErrorKind::AlreadyExists,
+ libc::ENOSYS => ErrorKind::Unsupported,
+ libc::ENOMEM => ErrorKind::OutOfMemory,
+ libc::EAGAIN => ErrorKind::WouldBlock,
+
+ _ => ErrorKind::Uncategorized,
+ }
+}
+
+pub fn init() {}
+
+pub struct Socket(FileDesc);
+
+impl Socket {
+ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+ let fam = match *addr {
+ SocketAddr::V4(..) => netc::AF_INET,
+ SocketAddr::V6(..) => netc::AF_INET6,
+ };
+ Socket::new_raw(fam, ty)
+ }
+
+ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+ unsafe {
+ let fd = cvt(netc::socket(fam, ty, 0))?;
+ let fd = FileDesc::new(fd);
+ let socket = Socket(fd);
+
+ Ok(socket)
+ }
+ }
+
+ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+ self.set_nonblocking(true)?;
+ let r = unsafe {
+ let (addrp, len) = addr.into_inner();
+ cvt(netc::connect(self.0.raw(), addrp, len))
+ };
+ self.set_nonblocking(false)?;
+
+ match r {
+ Ok(_) => return Ok(()),
+ // there's no ErrorKind for EINPROGRESS
+ Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
+ Err(e) => return Err(e),
+ }
+
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::Error::new_const(
+ io::ErrorKind::InvalidInput,
+ &"cannot set a 0 duration timeout",
+ ));
+ }
+
+ let mut timeout =
+ netc::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+
+ let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] };
+
+ let mut writefds = fds;
+ let mut errorfds = fds;
+
+ let n = unsafe {
+ cvt(netc::select(
+ self.0.raw() + 1,
+ ptr::null_mut(),
+ &mut writefds,
+ &mut errorfds,
+ &mut timeout,
+ ))?
+ };
+
+ match n {
+ 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
+ _ => {
+ let can_write = writefds.num_fds != 0;
+ if !can_write {
+ if let Some(e) = self.take_error()? {
+ return Err(e);
+ }
+ }
+ Ok(())
+ }
+ }
+ }
+
+ pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
+ let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?;
+ let fd = FileDesc::new(fd);
+ Ok(Socket(fd))
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ self.0.duplicate().map(Socket)
+ }
+
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, MSG_PEEK)
+ }
+
+ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ #[inline]
+ pub fn is_read_vectored(&self) -> bool {
+ self.0.is_read_vectored()
+ }
+
+ fn recv_from_with_flags(
+ &self,
+ buf: &mut [u8],
+ flags: c_int,
+ ) -> io::Result<(usize, SocketAddr)> {
+ let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+
+ let n = cvt(unsafe {
+ netc::recvfrom(
+ self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen,
+ )
+ })?;
+ Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, MSG_PEEK)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ #[inline]
+ pub fn is_write_vectored(&self) -> bool {
+ self.0.is_write_vectored()
+ }
+
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+ return Err(io::Error::new_const(
+ io::ErrorKind::InvalidInput,
+ &"cannot set a 0 duration timeout",
+ ));
+ }
+
+ let secs = if dur.as_secs() > netc::c_long::MAX as u64 {
+ netc::c_long::MAX
+ } else {
+ dur.as_secs() as netc::c_long
+ };
+ let mut timeout = netc::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+ };
+ setsockopt(self, netc::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
+ let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+ if raw.tv_sec == 0 && raw.tv_usec == 0 {
+ Ok(None)
+ } else {
+ let sec = raw.tv_sec as u64;
+ let nsec = (raw.tv_usec as u32) * 1000;
+ Ok(Some(Duration::new(sec, nsec)))
+ }
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Write => netc::SHUT_WR,
+ Shutdown::Read => netc::SHUT_RD,
+ Shutdown::Both => netc::SHUT_RDWR,
+ };
+ cvt(unsafe { netc::shutdown(self.0.raw(), how) })?;
+ Ok(())
+ }
+
+ pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+ let linger = netc::linger {
+ l_onoff: linger.is_some() as netc::c_int,
+ l_linger: linger.unwrap_or_default().as_secs() as netc::c_int,
+ };
+
+ setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
+ }
+
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
+
+ Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking = nonblocking as c_int;
+ cvt(unsafe {
+ netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
+ })
+ .map(drop)
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
+ if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
+ }
+
+ // This method is used by sys_common code to abstract over targets.
+ pub fn as_raw(&self) -> c_int {
+ *self.as_inner()
+ }
+}
+
+impl AsInner<c_int> for Socket {
+ fn as_inner(&self) -> &c_int {
+ self.0.as_inner()
+ }
+}
+
+impl FromInner<c_int> for Socket {
+ fn from_inner(fd: c_int) -> Socket {
+ Socket(FileDesc::new(fd))
+ }
+}
+
+impl IntoInner<c_int> for Socket {
+ fn into_inner(self) -> c_int {
+ self.0.into_raw()
+ }
+}
--- /dev/null
+use super::unsupported;
+use crate::error::Error as StdError;
+use crate::ffi::{CStr, CString, OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::os::{
+ raw::{c_char, c_int},
+ solid::ffi::{OsStrExt, OsStringExt},
+};
+use crate::path::{self, PathBuf};
+use crate::sys_common::rwlock::StaticRWLock;
+use crate::vec;
+
+use super::{abi, error, itron, memchr};
+
+// `solid` directly maps `errno`s to μITRON error codes.
+impl itron::error::ItronError {
+ #[inline]
+ pub(crate) fn as_io_error(self) -> crate::io::Error {
+ crate::io::Error::from_raw_os_error(self.as_raw())
+ }
+}
+
+pub fn errno() -> i32 {
+ 0
+}
+
+pub fn error_string(errno: i32) -> String {
+ if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a !);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ *self.0
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+ I: Iterator<Item = T>,
+ T: AsRef<OsStr>,
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on this platform yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "not supported on this platform yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+static ENV_LOCK: StaticRWLock = StaticRWLock::new();
+
+pub struct Env {
+ iter: vec::IntoIter<(OsString, OsString)>,
+}
+
+impl !Send for Env {}
+impl !Sync for Env {}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+ extern "C" {
+ static mut environ: *const *const c_char;
+ }
+
+ unsafe {
+ let _guard = ENV_LOCK.read();
+ let mut result = Vec::new();
+ if !environ.is_null() {
+ while !(*environ).is_null() {
+ if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+ result.push(key_value);
+ }
+ environ = environ.add(1);
+ }
+ }
+ return Env { iter: result.into_iter() };
+ }
+
+ fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+ // Strategy (copied from glibc): Variable name and value are separated
+ // by an ASCII equals sign '='. Since a variable name must not be
+ // empty, allow variable names starting with an equals sign. Skip all
+ // malformed lines.
+ if input.is_empty() {
+ return None;
+ }
+ let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+ pos.map(|p| {
+ (
+ OsStringExt::from_vec(input[..p].to_vec()),
+ OsStringExt::from_vec(input[p + 1..].to_vec()),
+ )
+ })
+ }
+}
+
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+ // environment variables with a nul byte can't be set, so their value is
+ // always None as well
+ let k = CString::new(k.as_bytes()).ok()?;
+ unsafe {
+ let _guard = ENV_LOCK.read();
+ let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+ if s.is_null() {
+ None
+ } else {
+ Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
+ }
+ }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ let k = CString::new(k.as_bytes())?;
+ let v = CString::new(v.as_bytes())?;
+
+ unsafe {
+ let _guard = ENV_LOCK.write();
+ cvt_env(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
+ }
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+ let nbuf = CString::new(n.as_bytes())?;
+
+ unsafe {
+ let _guard = ENV_LOCK.write();
+ cvt_env(libc::unsetenv(nbuf.as_ptr())).map(drop)
+ }
+}
+
+/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this
+/// function just returns a generic error.
+fn cvt_env(t: c_int) -> io::Result<c_int> {
+ if t == -1 {
+ Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure"))
+ } else {
+ Ok(t)
+ }
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no standard temporary directory on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(_code: i32) -> ! {
+ let tid = itron::task::try_current_task_id().unwrap_or(0);
+ loop {
+ abi::breakpoint_program_exited(tid as usize);
+ }
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on this platform")
+}
--- /dev/null
+use crate::ffi::OsStr;
+use crate::path::Prefix;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'\\'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+ None
+}
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
--- /dev/null
+//! A readers-writer lock implementation backed by the SOLID kernel extension.
+use super::{
+ abi,
+ itron::{
+ error::{expect_success, expect_success_aborting, fail, ItronError},
+ spin::SpinIdOnceCell,
+ },
+};
+
+pub struct RWLock {
+ /// The ID of the underlying mutex object
+ rwl: SpinIdOnceCell<()>,
+}
+
+pub type MovableRWLock = RWLock;
+
+// Safety: `num_readers` is protected by `mtx_num_readers`
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+fn new_rwl() -> Result<abi::ID, ItronError> {
+ ItronError::err_if_negative(unsafe { abi::rwl_acre_rwl() })
+}
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock { rwl: SpinIdOnceCell::new() }
+ }
+
+ /// Get the inner mutex's ID, which is lazily created.
+ fn raw(&self) -> abi::ID {
+ match self.rwl.get_or_try_init(|| new_rwl().map(|id| (id, ()))) {
+ Ok((id, ())) => id,
+ Err(e) => fail(e, &"rwl_acre_rwl"),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ let rwl = self.raw();
+ expect_success(unsafe { abi::rwl_loc_rdl(rwl) }, &"rwl_loc_rdl");
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ let rwl = self.raw();
+ match unsafe { abi::rwl_ploc_rdl(rwl) } {
+ abi::E_TMOUT => false,
+ er => {
+ expect_success(er, &"rwl_ploc_rdl");
+ true
+ }
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ let rwl = self.raw();
+ expect_success(unsafe { abi::rwl_loc_wrl(rwl) }, &"rwl_loc_wrl");
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ let rwl = self.raw();
+ match unsafe { abi::rwl_ploc_wrl(rwl) } {
+ abi::E_TMOUT => false,
+ er => {
+ expect_success(er, &"rwl_ploc_wrl");
+ true
+ }
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ let rwl = self.raw();
+ expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ let rwl = self.raw();
+ expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ if let Some(rwl) = self.rwl.get().map(|x| x.0) {
+ expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl");
+ }
+ }
+}
--- /dev/null
+use super::abi;
+use crate::io;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+struct PanicOutput;
+
+impl Stdin {
+ pub const fn new() -> Stdin {
+ Stdin
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+ Ok(0)
+ }
+}
+
+impl Stdout {
+ pub const fn new() -> Stdout {
+ Stdout
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub const fn new() -> Stderr {
+ Stderr
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl PanicOutput {
+ pub const fn new() -> PanicOutput {
+ PanicOutput
+ }
+}
+
+impl io::Write for PanicOutput {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+ true
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Some(PanicOutput::new())
+}
--- /dev/null
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "none")]
+
+// Simplify dtor registration by using a list of destructors.
+
+use super::{abi, itron::task};
+use crate::cell::Cell;
+use crate::ptr;
+
+#[thread_local]
+static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+
+type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+ if DTORS.get().is_null() {
+ let tid = task::current_task_id_aborting();
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v));
+
+ // Register `tls_dtor` to make sure the TLS destructors are called
+ // for tasks created by other means than `std::thread`
+ unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) };
+ }
+
+ let list: &mut List = unsafe { &mut *DTORS.get() };
+ list.push((t, dtor));
+}
+
+pub unsafe fn run_dtors() {
+ let ptr = DTORS.get();
+ if !ptr.is_null() {
+ // Swap the destructor list, call all registered destructors,
+ // and repeat this until the list becomes permanently empty.
+ while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new()))
+ .filter(|list| !list.is_empty())
+ {
+ for (ptr, dtor) in list.into_iter() {
+ unsafe { dtor(ptr) };
+ }
+ }
+
+ // Drop the destructor list
+ unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) };
+ }
+}
+
+unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
+ unsafe { run_dtors() };
+}
--- /dev/null
+pub type Key = usize;
+
+#[inline]
+pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+ panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+ panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub unsafe fn get(_key: Key) -> *mut u8 {
+ panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+ panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ panic!("should not be used on the solid target");
+}
--- /dev/null
+use super::{abi, error::expect_success};
+use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+
+pub use super::itron::time::Instant;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(abi::time_t);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(0);
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ let rtc = unsafe {
+ let mut out = MaybeUninit::zeroed();
+ expect_success(abi::SOLID_RTC_ReadTime(out.as_mut_ptr()), &"SOLID_RTC_ReadTime");
+ out.assume_init()
+ };
+ let t = unsafe {
+ libc::mktime(&mut libc::tm {
+ tm_sec: rtc.tm_sec,
+ tm_min: rtc.tm_min,
+ tm_hour: rtc.tm_hour,
+ tm_mday: rtc.tm_mday,
+ tm_mon: rtc.tm_mon,
+ tm_year: rtc.tm_year,
+ tm_wday: rtc.tm_wday,
+ tm_yday: 0,
+ tm_isdst: 0,
+ tm_gmtoff: 0,
+ tm_zone: crate::ptr::null_mut(),
+ })
+ };
+ assert_ne!(t, -1, "mktime failed");
+ SystemTime(t)
+ }
+
+ pub(super) fn from_time_t(t: abi::time_t) -> Self {
+ Self(t)
+ }
+
+ pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+ if self.0 >= other.0 {
+ Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64)))
+ } else {
+ Err(Duration::from_secs((other.0 as u64).wrapping_sub(self.0 as u64)))
+ }
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?))
+ }
+}
/// | UNIX | [clock_gettime (Monotonic Clock)] |
/// | Darwin | [mach_absolute_time] |
/// | VXWorks | [clock_gettime (Monotonic Clock)] |
+/// | SOLID | `get_tim` |
/// | WASI | [__wasi_clock_time_get (Monotonic Clock)] |
/// | Windows | [QueryPerformanceCounter] |
///
/// | UNIX | [clock_gettime (Realtime Clock)] |
/// | Darwin | [gettimeofday] |
/// | VXWorks | [clock_gettime (Realtime Clock)] |
+/// | SOLID | `SOLID_RTC_ReadTime` |
/// | WASI | [__wasi_clock_time_get (Realtime Clock)] |
/// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] |
///
/// as the system clock being adjusted either forwards or backwards).
/// [`Instant`] can be used to measure elapsed time without this risk of failure.
///
- /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
+ /// If successful, <code>[Ok]\([Duration])</code> is returned where the duration represents
/// the amount of time elapsed from the specified measurement to this one.
///
/// Returns an [`Err`] if `earlier` is later than `self`, and the error
///
/// This function may fail as the underlying system clock is susceptible to
/// drift and updates (e.g., the system clock could go backwards), so this
- /// function might not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
+ /// function might not always succeed. If successful, <code>[Ok]\([Duration])</code> is
/// returned where the duration represents the amount of time elapsed from
/// this time measurement to the current time.
///
-Subproject commit 89b0e355bc3cff5cddec2290c84f36eb3a026aad
+Subproject commit 5fdbc476afc81a789806697fc4a2d9d19b8c9993
profiler = ["std/profiler"]
std_detect_file_io = ["std/std_detect_file_io"]
std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
+std_detect_env_override = ["std/std_detect_env_override"]
unix,
windows,
target_os = "psp",
+ target_os = "solid_asp3",
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
mod libunwind;
"library/backtrace",
"library/stdarch",
"compiler/rustc_codegen_cranelift",
+ "compiler/rustc_codegen_gcc",
"src/doc/book",
"src/doc/edition-guide",
"src/doc/embedded-book",
// Only execute if it's supposed to run as default
if desc.default && should_run.is_really_default() { self.ensure(step) } else { None }
}
+
+ /// Checks if any of the "should_run" paths is in the `Builder` paths.
+ pub(crate) fn was_invoked_explicitly<S: Step>(&'a self) -> bool {
+ let desc = StepDescription::from::<S>();
+ let should_run = (desc.should_run)(ShouldRun::new(self));
+
+ for path in &self.paths {
+ if should_run.paths.iter().any(|s| s.has(path))
+ && !desc.is_excluded(self, &PathSet::Suite(path.clone()))
+ {
+ return true;
+ }
+ }
+
+ false
+ }
}
#[cfg(test)]
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
+ run.paths(&[
+ "compiler/rustc_codegen_cranelift",
+ "rustc_codegen_cranelift",
+ "compiler/rustc_codegen_gcc",
+ "rustc_codegen_gcc",
+ ])
}
fn make_run(run: RunConfig<'_>) {
- for &backend in &[INTERNER.intern_str("cranelift")] {
+ for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] {
run.builder.ensure(CodegenBackend { target: run.target, backend });
}
}
// Used for deciding whether a particular step is one requested by the user on
// the `x.py doc` command line, which determines whether `--open` will open that
// page.
-fn components_simplified(path: &PathBuf) -> Vec<&str> {
+pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> {
path.iter().map(|component| component.to_str().unwrap_or("???")).collect()
}
-fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
- builder
- .paths
- .iter()
- .map(components_simplified)
- .any(|requested| requested.iter().copied().eq(path.split('/')))
-}
-
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct UnstableBook {
target: TargetSelection,
invoke_rustdoc(builder, compiler, target, path);
}
- if is_explicit_request(builder, "src/doc/book") {
+ if builder.was_invoked_explicitly::<Self>() {
let out = builder.doc_out(target);
let index = out.join("book").join("index.html");
open(builder, &index);
// We open doc/index.html as the default if invoked as `x.py doc --open`
// with no particular explicit doc requested (e.g. library/core).
- if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") {
+ if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>() {
let index = out.join("index.html");
open(builder, &index);
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let target = self.target;
- let mut is_explicit_request = false;
builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
let paths = builder
.map(components_simplified)
.filter_map(|path| {
if path.get(0) == Some(&"compiler") {
- is_explicit_request = true;
path.get(1).map(|p| p.to_owned())
} else {
None
})
.collect::<Vec<_>>();
- if !builder.config.compiler_docs && !is_explicit_request {
+ if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
builder.info("\tskipping - compiler/librustdoc docs disabled");
return;
}
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let target = self.target;
- builder.info(&format!("Documenting stage{} {} ({})", stage, stringify!($tool).to_lowercase(), target));
+ builder.info(
+ &format!(
+ "Documenting stage{} {} ({})",
+ stage,
+ stringify!($tool).to_lowercase(),
+ target,
+ ),
+ );
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
let compiler = builder.compiler(stage, builder.config.build);
- if !builder.config.compiler_docs {
+ if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
builder.info("\tskipping - compiler/tool docs disabled");
return;
}
cargo.rustdocflag("--document-private-items");
cargo.rustdocflag("--enable-index-page");
cargo.rustdocflag("--show-type-layout");
+ cargo.rustdocflag("--generate-link-to-definition");
cargo.rustdocflag("-Zunstable-options");
builder.run(&mut cargo.into());
}
name: INTERNER.intern_str("rustc"),
src: INTERNER.intern_path(out_base),
});
- if is_explicit_request(builder, "src/doc/rustc") {
+ if builder.was_invoked_explicitly::<Self>() {
let out = builder.doc_out(self.target);
let index = out.join("rustc").join("index.html");
open(builder, &index);
+use crate::TargetSelection;
use crate::{t, VERSION};
use std::fmt::Write as _;
use std::path::{Path, PathBuf};
let include_path = profile.include_path(src_path);
println!("`x.py` will now use the configuration at {}", include_path.display());
+ let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
+ let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/");
+
+ println!();
+
+ if !rustup_installed() && profile != Profile::User {
+ println!("`rustup` is not installed; cannot link `stage1` toolchain");
+ } else if stage_dir_exists(&stage_path[..]) {
+ attempt_toolchain_link(&stage_path[..]);
+ }
+
let suggestions = match profile {
Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
Profile::Tools => &[
}
}
+fn rustup_installed() -> bool {
+ Command::new("rustup")
+ .arg("--version")
+ .stdout(std::process::Stdio::null())
+ .output()
+ .map_or(false, |output| output.status.success())
+}
+
+fn stage_dir_exists(stage_path: &str) -> bool {
+ match fs::create_dir(&stage_path[..]) {
+ Ok(_) => true,
+ Err(_) => Path::new(&stage_path[..]).exists(),
+ }
+}
+
+fn attempt_toolchain_link(stage_path: &str) {
+ if toolchain_is_linked() {
+ return;
+ }
+
+ if try_link_toolchain(&stage_path[..]) {
+ println!(
+ "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
+ );
+ } else {
+ println!("`rustup` failed to link stage 1 build to `stage1` toolchain");
+ println!(
+ "To manually link stage 1 build to `stage1` toolchain, run:\n
+ `rustup toolchain link stage1 {}`",
+ &stage_path[..]
+ );
+ }
+}
+
+fn toolchain_is_linked() -> bool {
+ match Command::new("rustup")
+ .args(&["toolchain", "list"])
+ .stdout(std::process::Stdio::piped())
+ .output()
+ {
+ Ok(toolchain_list) => {
+ if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") {
+ return false;
+ }
+ // The toolchain has already been linked.
+ println!(
+ "`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
+ );
+ }
+ Err(_) => {
+ // In this case, we don't know if the `stage1` toolchain has been linked;
+ // but `rustup` failed, so let's not go any further.
+ println!(
+ "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain"
+ );
+ }
+ }
+ true
+}
+
+fn try_link_toolchain(stage_path: &str) -> bool {
+ Command::new("rustup")
+ .stdout(std::process::Stdio::null())
+ .args(&["toolchain", "link", "stage1", &stage_path[..]])
+ .output()
+ .map_or(false, |output| output.status.success())
+}
+
// Used to get the path for `Subcommand::Setup`
pub fn interactive_path() -> io::Result<Profile> {
fn abbrev_all() -> impl Iterator<Item = ((String, String), Profile)> {
- [Tests](tests/index.md)
- [Platform Support](platform-support.md)
- [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
+ - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
- [Target Tier Policy](target-tier-policy.md)
- [Targets](targets/index.md)
- [Built-in Targets](targets/built-in.md)
-------|:---:|:----:|-------
`aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64
`aarch64-apple-tvos` | * | | ARM64 tvOS
+[`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
`aarch64-unknown-hermit` | ? | |
`aarch64-unknown-uefi` | * | | ARM64 UEFI
`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
`armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
`armv7-wrs-vxworks-eabihf` | ? | |
+[`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3
+[`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat
`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
`armv7s-apple-ios` | ✓ | |
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
--- /dev/null
+# \*-kmc-solid_\*
+
+**Tier: 3**
+
+[SOLID] embedded development platform by Kyoto Microcomputer Co., Ltd.
+
+[SOLID]: https://www.kmckk.co.jp/eng/SOLID/
+
+The target names follow this format: `$ARCH-kmc-solid_$KERNEL-$ABI`, where `$ARCH` specifies the target processor architecture, `$KERNEL` the base kernel, and `$ABI` the target ABI (optional). The following targets are currently defined:
+
+| Target name | `target_arch` | `target_vendor` | `target_os` |
+|--------------------------------|---------------|-----------------|--------------|
+| `aarch64-kmc-solid_asp3` | `aarch64` | `kmc` | `solid_asp3` |
+| `armv7a-kmc-solid_asp3-eabi` | `arm` | `kmc` | `solid_asp3` |
+| `armv7a-kmc-solid_asp3-eabihf` | `arm` | `kmc` | `solid_asp3` |
+
+## Designated Developers
+
+- [@kawadakk](https://github.com/kawadakk)
+
+## Requirements
+
+This target is cross-compiled.
+A platform-provided C compiler toolchain is required, though it can be substituted by [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) for the purpose of building Rust and functional binaries.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build.
+
+```toml
+[build]
+target = ["aarch64-kmc-solid_asp3"]
+```
+
+Make sure `aarch64-kmc-elf-gcc` is included in `$PATH`. Alternatively, you can use GNU Arm Embedded Toolchain by adding the following to `config.toml`:
+
+```toml
+[target.aarch64-kmc-solid_asp3]
+cc = "arm-none-eabi-gcc"
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from any hosts.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+## Building Rust programs
+
+Building executables is not supported yet.
+
+If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target:
+
+```shell
+$ rustc --target aarch64-kmc-solid_asp3 your-code.rs --crate-type staticlib
+$ ls libyour_code.a
+```
+
+On Rust Nightly it's possible to build without the target artifacts available:
+
+```text
+cargo build -Z build-std --target aarch64-kmc-solid_asp3
+```
let (poly_trait, output) =
(data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
let new_ty = match poly_trait.trait_ {
- Type::ResolvedPath { ref path, ref did, ref is_generic } => {
+ Type::ResolvedPath { ref path, ref did } => {
let mut new_path = path.clone();
let last_segment =
new_path.segments.pop().expect("segments were empty");
.segments
.push(PathSegment { name: last_segment.name, args: new_params });
- Type::ResolvedPath {
- path: new_path,
- did: *did,
- is_generic: *is_generic,
- }
+ Type::ResolvedPath { path: new_path, did: *did }
}
_ => panic!("Unexpected data: {:?}, {:?}", ty, data),
};
Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
let ty = &*self_type;
match **trait_ {
- Type::ResolvedPath {
- path: ref trait_path,
- ref did,
- ref is_generic,
- } => {
+ Type::ResolvedPath { path: ref trait_path, ref did } => {
let mut new_trait_path = trait_path.clone();
if self.is_fn_ty(trait_) && left_name == sym::Output {
trait_: Type::ResolvedPath {
path: new_trait_path,
did: *did,
- is_generic: *is_generic,
},
generic_params: Vec::new(),
},
.instantiate(self.cx.tcx, impl_substs)
.predicates
.into_iter()
- .chain(Some(trait_ref.without_const().to_predicate(infcx.tcx)));
+ .chain(Some(
+ ty::Binder::dummy(trait_ref)
+ .without_const()
+ .to_predicate(infcx.tcx),
+ ));
for predicate in predicates {
debug!("testing predicate {:?}", predicate);
let obligation = traits::Obligation::new(
}
}
+ let document_hidden = cx.render_options.document_hidden;
let predicates = tcx.explicit_predicates_of(did);
let (trait_items, generics) = match impl_item {
Some(impl_) => (
impl_
.items
.iter()
- .map(|item| tcx.hir().impl_item(item.id).clean(cx))
+ .map(|item| tcx.hir().impl_item(item.id))
+ .filter(|item| {
+ // Filter out impl items whose corresponding trait item has `doc(hidden)`
+ // not to document such impl items.
+ // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.
+
+ // When `--document-hidden-items` is passed, we don't
+ // do any filtering, too.
+ if document_hidden {
+ return true;
+ }
+ if let Some(associated_trait) = associated_trait {
+ let assoc_kind = match item.kind {
+ hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
+ hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
+ hir::ImplItemKind::TyAlias(..) => ty::AssocKind::Type,
+ };
+ let trait_item = tcx
+ .associated_items(associated_trait.def_id)
+ .find_by_name_and_kind(
+ tcx,
+ item.ident,
+ assoc_kind,
+ associated_trait.def_id,
+ )
+ .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
+ !tcx.get_attrs(trait_item.def_id).lists(sym::doc).has_word(sym::hidden)
+ } else {
+ true
+ }
+ })
+ .map(|item| item.clean(cx))
.collect::<Vec<_>>(),
impl_.generics.clean(cx),
),
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
- let trait_ref = ty::TraitRef::identity(cx.tcx, def_id);
+ let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
let generic_args = generic_args.clean(cx);
let bindings = match generic_args {
debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
- ResolvedPath { path, did: trait_ref.def_id, is_generic: false }
+ ResolvedPath { path, did: trait_ref.def_id }
}
}
};
inline::record_extern_fqn(cx, did, kind);
let path = external_path(cx, did, false, vec![], substs);
- ResolvedPath { path, did, is_generic: false }
+ ResolvedPath { path, did }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
- ResolvedPath { path, did, is_generic: false }
+ ResolvedPath { path, did }
}
ty::Dynamic(ref obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
let path = external_path(cx, did, false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
let bound = PolyTrait {
- trait_: ResolvedPath { path, did, is_generic: false },
+ trait_: ResolvedPath { path, did },
generic_params: Vec::new(),
};
bounds.push(bound);
let path = external_path(cx, did, false, bindings, substs);
bounds.insert(
0,
- PolyTrait {
- trait_: ResolvedPath { path, did, is_generic: false },
- generic_params: Vec::new(),
- },
+ PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() },
);
DynTrait(bounds, lifetime)
}
}
-/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
-/// as well as doc comments.
-#[derive(Clone, Debug, Default)]
-crate struct Attributes {
- crate doc_strings: Vec<DocFragment>,
- crate other_attrs: Vec<ast::Attribute>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
/// A link that has not yet been rendered.
///
/// This link will be turned into a rendered link by [`Item::links`].
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
crate struct ItemLink {
/// The original link written in the markdown
pub(crate) link: String,
pub(crate) href: String,
}
+/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
+/// as well as doc comments.
+#[derive(Clone, Debug, Default)]
+crate struct Attributes {
+ crate doc_strings: Vec<DocFragment>,
+ crate other_attrs: Vec<ast::Attribute>,
+}
+
impl Attributes {
crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
self.other_attrs.lists(name)
let path = external_path(cx, did, false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
GenericBound::TraitBound(
- PolyTrait {
- trait_: ResolvedPath { path, did, is_generic: false },
- generic_params: Vec::new(),
- },
+ PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() },
hir::TraitBoundModifier::Maybe,
)
}
ResolvedPath {
path: Path,
did: DefId,
- /// `true` if is a `T::Name` path for associated types.
- is_generic: bool,
},
/// `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
ImplTrait(Vec<GenericBound>),
}
-#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
-/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't
-/// paths, like `Unit`.
-crate enum PrimitiveType {
- Isize,
- I8,
- I16,
- I32,
- I64,
- I128,
- Usize,
- U8,
- U16,
- U32,
- U64,
- U128,
- F32,
- F64,
- Char,
- Bool,
- Str,
- Slice,
- Array,
- Tuple,
- Unit,
- RawPointer,
- Reference,
- Fn,
- Never,
-}
-
crate trait GetDefId {
/// Use this method to get the [`DefId`] of a [`clean`] AST node.
/// This will return [`None`] when called on a primitive [`clean::Type`].
}
}
- crate fn is_generic(&self) -> bool {
- match *self {
- ResolvedPath { is_generic, .. } => is_generic,
+ /// Checks if this is a `T::Name` path for an associated type.
+ crate fn is_assoc_ty(&self) -> bool {
+ match self {
+ ResolvedPath { path, .. } => path.is_assoc_ty(),
_ => false,
}
}
};
Some((&self_, trait_did, *name))
}
-}
-impl Type {
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
ResolvedPath { did, .. } => return Some(did),
}
}
+/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't
+/// paths, like `Unit`.
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
+crate enum PrimitiveType {
+ Isize,
+ I8,
+ I16,
+ I32,
+ I64,
+ I128,
+ Usize,
+ U8,
+ U16,
+ U32,
+ U64,
+ U128,
+ F32,
+ F64,
+ Char,
+ Bool,
+ Str,
+ Slice,
+ Array,
+ Tuple,
+ Unit,
+ RawPointer,
+ Reference,
+ Fn,
+ Never,
+}
+
impl PrimitiveType {
crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
use ast::{FloatTy, IntTy, UintTy};
String::from(if self.global { "::" } else { "" })
+ &self.segments.iter().map(|s| s.name.to_string()).collect::<Vec<_>>().join("::")
}
+
+ /// Checks if this is a `T::Name` path for an associated type.
+ crate fn is_assoc_ty(&self) -> bool {
+ match self.res {
+ Res::SelfTy(..) if self.segments.len() != 1 => true,
+ Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
+ Res::Def(DefKind::AssocTy, _) => true,
+ _ => false,
+ }
+ }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate fn strip_type(ty: Type) -> Type {
match ty {
- Type::ResolvedPath { path, did, is_generic } => {
- Type::ResolvedPath { path: strip_path(&path), did, is_generic }
- }
+ Type::ResolvedPath { path, did } => Type::ResolvedPath { path: strip_path(&path), did },
Type::DynTrait(mut bounds, lt) => {
let first = bounds.remove(0);
let stripped_trait = strip_type(first.trait_);
crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
debug!("resolve_type({:?})", path);
- let is_generic = match path.res {
- Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)),
- Res::SelfTy(..) if path.segments.len() == 1 => {
- return Generic(kw::SelfUpper);
- }
- Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
- return Generic(path.segments[0].name);
+ match path.res {
+ Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
+ Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper),
+ Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
+ _ => {
+ let did = register_res(cx, path.res);
+ ResolvedPath { path, did }
}
- Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
- _ => false,
- };
- let did = register_res(cx, path.res);
- ResolvedPath { path, did, is_generic }
+ }
}
crate fn get_auto_trait_and_blanket_impls(
match *t {
clean::Generic(name) => write!(f, "{}", name),
- clean::ResolvedPath { did, ref path, is_generic } => {
+ clean::ResolvedPath { did, ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
- resolved_path(f, did, path, is_generic, use_absolute, cx)
+ resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
}
clean::DynTrait(ref bounds, ref lt) => {
f.write_str("dyn ")?;
hir::Mutability::Mut => "mut",
hir::Mutability::Not => "const",
};
- match **t {
- clean::Generic(_) | clean::ResolvedPath { is_generic: true, .. } => {
- if f.alternate() {
- primitive_link(
- f,
- clean::PrimitiveType::RawPointer,
- &format!("*{} {:#}", m, t.print(cx)),
- cx,
- )
- } else {
- primitive_link(
- f,
- clean::PrimitiveType::RawPointer,
- &format!("*{} {}", m, t.print(cx)),
- cx,
- )
- }
- }
- _ => {
- primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?;
- fmt::Display::fmt(&t.print(cx), f)
- }
+
+ if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
+ let text = if f.alternate() {
+ format!("*{} {:#}", m, t.print(cx))
+ } else {
+ format!("*{} {}", m, t.print(cx))
+ };
+ primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx)
+ } else {
+ primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?;
+ fmt::Display::fmt(&t.print(cx), f)
}
}
clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
/// The range in the markdown that the code within the code block occupies.
crate code: Range<usize>,
crate is_fenced: bool,
- crate syntax: Option<String>,
- crate is_ignore: bool,
+ crate lang_string: LangString,
}
/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
while let Some((event, offset)) = p.next() {
if let Event::Start(Tag::CodeBlock(syntax)) = event {
- let (syntax, code_start, code_end, range, is_fenced, is_ignore) = match syntax {
+ let (lang_string, code_start, code_end, range, is_fenced) = match syntax {
CodeBlockKind::Fenced(syntax) => {
let syntax = syntax.as_ref();
let lang_string = if syntax.is_empty() {
if !lang_string.rust {
continue;
}
- let is_ignore = lang_string.ignore != Ignore::None;
- let syntax = if syntax.is_empty() { None } else { Some(syntax.to_owned()) };
let (code_start, mut code_end) = match p.next() {
Some((Event::Text(_), offset)) => (offset.start, offset.end),
Some((_, sub_offset)) => {
is_fenced: true,
range: offset,
code,
- syntax,
- is_ignore,
+ lang_string,
});
continue;
}
is_fenced: true,
range: offset,
code,
- syntax,
- is_ignore,
+ lang_string,
});
continue;
}
while let Some((Event::Text(_), offset)) = p.next() {
code_end = offset.end;
}
- (syntax, code_start, code_end, offset, true, is_ignore)
+ (lang_string, code_start, code_end, offset, true)
}
CodeBlockKind::Indented => {
// The ending of the offset goes too far sometime so we reduce it by one in
// these cases.
if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
(
- None,
+ LangString::default(),
offset.start,
offset.end,
Range { start: offset.start, end: offset.end - 1 },
false,
- false,
)
} else {
- (None, offset.start, offset.end, offset, false, false)
+ (LangString::default(), offset.start, offset.end, offset, false)
}
}
};
is_fenced,
range,
code: Range { start: code_start, end: code_end },
- syntax,
- is_ignore,
+ lang_string,
});
}
}
let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
for implementor in implementors {
match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, did, is_generic: false, .. }
+ clean::ResolvedPath { ref path, did, .. }
| clean::BorrowedRef {
- type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. },
- ..
- } => {
+ type_: box clean::ResolvedPath { ref path, did, .. }, ..
+ } if !path.is_assoc_ty() => {
let &mut (prev_did, ref mut has_duplicates) =
implementor_dups.entry(path.last()).or_insert((did, false));
if prev_did != did {
// If there's already another implementor that has the same abridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let use_absolute = match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, is_generic: false, .. }
- | clean::BorrowedRef {
- type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
- ..
- } => implementor_dups[&path.last()].1,
+ clean::ResolvedPath { ref path, .. }
+ | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. }
+ if !path.is_assoc_ty() =>
+ {
+ implementor_dups[&path.last()].1
+ }
_ => false,
};
render_impl(
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::*;
match ty {
- ResolvedPath { path, did, is_generic: _ } => Type::ResolvedPath {
+ ResolvedPath { path, did } => Type::ResolvedPath {
name: path.whole_name(),
id: from_item_id(did.into()),
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
use rustc_parse::parse_stream_from_source_str;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FilePathMapping, SourceMap};
-use rustc_span::{FileName, InnerSpan};
+use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMMY_SP};
use crate::clean;
use crate::core::DocContext;
let source = dox[code_block.code].to_owned();
let sess = ParseSess::with_span_handler(handler, sm);
+ let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
+ let expn_data = ExpnData::default(
+ ExpnKind::AstPass(AstPass::TestHarness),
+ DUMMY_SP,
+ edition,
+ None,
+ None,
+ );
+ let span = DUMMY_SP.fresh_expansion(expn_data, self.cx.tcx.create_stable_hashing_context());
+
let is_empty = rustc_driver::catch_fatal_errors(|| {
parse_stream_from_source_str(
FileName::Custom(String::from("doctest")),
source,
&sess,
- None,
+ Some(span),
)
.is_empty()
})
};
let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
- let empty_block = code_block.syntax.is_none() && code_block.is_fenced;
- let is_ignore = code_block.is_ignore;
+ let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
+ let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
// The span and whether it is precise or not.
let (sp, precise_span) = match super::source_span_for_markdown_range(
return None;
}
if let Some(did) = imp.for_.def_id() {
- if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into())
+ if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
{
debug!("ImplStripper: impl item for stripped type; removing");
return None;
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
// We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/extern-drop-glue
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus -Copt-level=0
#![allow(dead_code)]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y
+// incremental
+// compile-flags:-Zprint-mono-items=eager -Zshare-generics=y
#![allow(dead_code)]
#![crate_type="lib"]
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Ccodegen-units=3
#![crate_type = "rlib"]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/inlining-from-extern-crate
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus
#![crate_type="lib"]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
// We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-drop-glue
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus -Copt-level=0
#![allow(dead_code)]
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic
+// incremental
+// compile-flags:-Zprint-mono-items=eager
#![allow(dead_code)]
#![crate_type="lib"]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining-but-not-all
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus=no
#![allow(dead_code)]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus
#![allow(dead_code)]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-transitive-inlining
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus
#![allow(dead_code)]
// ignore-test
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/methods-are-with-self-type
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
#![allow(dead_code)]
#![feature(start)]
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules
+// incremental
+// compile-flags:-Zprint-mono-items=eager
#![allow(dead_code)]
#![crate_type="lib"]
// no-prefer-dynamic
// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels
// prevent drop-glue from participating in share-generics.
-// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Cincremental=tmp/partitioning-tests/shared-generics-exe -Copt-level=0
+// incremental
+// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Copt-level=0
#![crate_type="rlib"]
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/statics
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
#![crate_type="rlib"]
//
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
// incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/vtable-through-const
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
// compile-flags:-Zinline-in-all-cgus
// This test case makes sure, that references made through constants are
-// compile-flags: -Z panic-in-drop=abort -O
+// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no
// Ensure that unwinding code paths are eliminated from the output after
// optimization.
+// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen
+// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that
+// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we
+// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC
+// targets. We should either forbid longjmps, or not assume nounwind, making this optimization
+// incompatible with the current behavior of running cleanuppads on longjmp unwinding.
+
+// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output
+
#![crate_type = "lib"]
use std::any::Any;
use std::mem::forget;
}
}
-// CHECK-LABEL: normal_drop
-// CHECK-NOT: should_not_appear_in_output
#[no_mangle]
pub fn normal_drop(x: ExternDrop) {
let guard = AssertNeverDrop;
forget(guard);
}
-// CHECK-LABEL: indirect_drop
-// CHECK-NOT: should_not_appear_in_output
#[no_mangle]
pub fn indirect_drop(x: Box<dyn Any>) {
let guard = AssertNeverDrop;
// lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let stack_val_interior_ref_2: &f64 = &stack_val.y;
let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 };
- let unique_val: Box<_> = box SomeStruct { x: 13, y: 26.5 };
+ let unique_val: Box<_> = Box::new(SomeStruct { x: 13, y: 26.5 });
let unique_val_ref: &SomeStruct = &*unique_val;
let unique_val_interior_ref_1: &isize = &unique_val.x;
let unique_val_interior_ref_2: &f64 = &unique_val.y;
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let stack_val_ref: &(i16, f32) = &stack_val;
let ref_to_unnamed: &(i16, f32) = &(-15, -20f32);
- let unique_val: Box<(i16, f32)> = box (-17, -22f32);
+ let unique_val: Box<(i16, f32)> = Box::new((-17, -22f32));
let unique_val_ref: &(i16, f32) = &*unique_val;
zzz(); // #break
// lldbr-check:(f64) *f64_ref = 3.5
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
- let bool_box: Box<bool> = box true;
+ let bool_box: Box<bool> = Box::new(true);
let bool_ref: &bool = &*bool_box;
- let int_box: Box<isize> = box -1;
+ let int_box: Box<isize> = Box::new(-1);
let int_ref: &isize = &*int_box;
- let char_box: Box<char> = box 'a';
+ let char_box: Box<char> = Box::new('a');
let char_ref: &char = &*char_box;
- let i8_box: Box<i8> = box 68;
+ let i8_box: Box<i8> = Box::new(68);
let i8_ref: &i8 = &*i8_box;
- let i16_box: Box<i16> = box -16;
+ let i16_box: Box<i16> = Box::new(-16);
let i16_ref: &i16 = &*i16_box;
- let i32_box: Box<i32> = box -32;
+ let i32_box: Box<i32> = Box::new(-32);
let i32_ref: &i32 = &*i32_box;
- let i64_box: Box<i64> = box -64;
+ let i64_box: Box<i64> = Box::new(-64);
let i64_ref: &i64 = &*i64_box;
- let uint_box: Box<usize> = box 1;
+ let uint_box: Box<usize> = Box::new(1);
let uint_ref: &usize = &*uint_box;
- let u8_box: Box<u8> = box 100;
+ let u8_box: Box<u8> = Box::new(100);
let u8_ref: &u8 = &*u8_box;
- let u16_box: Box<u16> = box 16;
+ let u16_box: Box<u16> = Box::new(16);
let u16_ref: &u16 = &*u16_box;
- let u32_box: Box<u32> = box 32;
+ let u32_box: Box<u32> = Box::new(32);
let u32_ref: &u32 = &*u32_box;
- let u64_box: Box<u64> = box 64;
+ let u64_box: Box<u64> = Box::new(64);
let u64_ref: &u64 = &*u64_box;
- let f32_box: Box<f32> = box 2.5;
+ let f32_box: Box<f32> = Box::new(2.5);
let f32_ref: &f32 = &*f32_box;
- let f64_box: Box<f64> = box 3.5;
+ let f64_box: Box<f64> = Box::new(3.5);
let f64_ref: &f64 = &*f64_box;
zzz(); // #break
// lldbr-check:((i32, f64)) *b = { 0 = 2 1 = 3.5 }
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
- let a = box 1;
- let b = box (2, 3.5f64);
+ let a = Box::new(1);
+ let b = Box::new((2, 3.5f64));
zzz(); // #break
}
// lldbr-check:(boxed_struct::StructWithDestructor) *boxed_with_dtor = { x = 77 y = 777 z = 7777 w = 77777 }
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
- let boxed_with_padding: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 };
-
- let boxed_with_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 };
+ let boxed_with_padding: Box<_> = Box::new(StructWithSomePadding {
+ x: 99,
+ y: 999,
+ z: 9999,
+ w: 99999,
+ });
+
+ let boxed_with_dtor: Box<_> = Box::new(StructWithDestructor {
+ x: 77,
+ y: 777,
+ z: 7777,
+ w: 77777,
+ });
zzz(); // #break
}
// lldbr-check:(i32) *y = 110
// lldb-command:continue
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#![allow(unused_variables)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
managed_box(&(34, 35));
borrowed_pointer(&(36, 37));
contained_borrowed_pointer((&38, 39));
- unique_pointer(box (40, 41, 42));
+ unique_pointer(Box::new((40, 41, 42)));
ref_binding((43, 44, 45));
ref_binding_in_tuple((46, (47, 48)));
ref_binding_in_struct(Struct { a: 49, b: 50 });
#![allow(unused_variables)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
y: -300001.5,
z: true
},
- box 854237.5);
+ Box::new(854237.5));
for &(v1,
&Struct { x: x1, y: ref y1, z: z1 },
#![allow(unused_variables)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let (&cc, _) = (&38, 39);
// unique pointer
- let box dd = box (40, 41, 42);
+ let box dd = Box::new((40, 41, 42));
// ref binding
let ref ee = (43, 44, 45);
// lldbr-check:(f32) arg2 = -10.5
// lldb-command:continue
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, 2_u16);
let _ = stack.self_by_val(-3, -4_i16);
- let owned: Box<_> = box Struct { x: 1234.5f64 };
+ let owned: Box<_> = Box::new(Struct { x: 1234.5f64 });
let _ = owned.self_by_ref(-5, -6_i32);
let _ = owned.self_by_val(-7, -8_i64);
let _ = owned.self_owned(-9, -10.5_f32);
// lldb-check:[...]$14 = -10
// lldb-command:continue
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, -2);
let _ = stack.self_by_val(-3, -4);
- let owned: Box<_> = box Enum::Variant1{ x: 1799, y: 1799 };
+ let owned: Box<_> = Box::new(Enum::Variant1{ x: 1799, y: 1799 });
let _ = owned.self_by_ref(-5, -6);
let _ = owned.self_by_val(-7, -8);
let _ = owned.self_owned(-9, -10);
// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
-
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, -2);
let _ = stack.self_by_val(-3, -4);
- let owned: Box<_> = box Struct { x: 1234.5f64 };
+ let owned: Box<_> = Box::new(Struct { x: 1234.5f64 });
let _ = owned.self_by_ref(-5, -6);
let _ = owned.self_by_val(-7, -8);
let _ = owned.self_owned(-9, -10);
// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
-
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, -2);
let _ = stack.self_by_val(-3, -4);
- let owned: Box<_> = box Struct { x: 200 };
+ let owned: Box<_> = Box::new(Struct { x: 200 });
let _ = owned.self_by_ref(-5, -6);
let _ = owned.self_by_val(-7, -8);
let _ = owned.self_owned(-9, -10);
// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
-
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, -2);
let _ = stack.self_by_val(-3, -4);
- let owned: Box<_> = box Struct { x: 200 };
+ let owned: Box<_> = Box::new(Struct { x: 200 });
let _ = owned.self_by_ref(-5, -6);
let _ = owned.self_by_val(-7, -8);
let _ = owned.self_owned(-9, -10);
// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
-
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, -2);
let _ = stack.self_by_val(-3, -4);
- let owned: Box<_> = box TupleStruct(200, -200.5);
+ let owned: Box<_> = Box::new(TupleStruct(200, -200.5));
let _ = owned.self_by_ref(-5, -6);
let _ = owned.self_by_val(-7, -8);
let _ = owned.self_owned(-9, -10);
// gdb-command:print long_cycle4.value
// gdb-check:$18 = 29.5
-// gdbr-command:print long_cycle_w_anonymous_types.value
+// gdbr-command:print long_cycle_w_anon_types.value
// gdb-check:$19 = 30
-// gdbr-command:print long_cycle_w_anonymous_types.next.val.value
+// gdbr-command:print long_cycle_w_anon_types.next.val.value
// gdb-check:$20 = 31
// gdb-command:continue
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Opt::{Empty, Val};
+use std::boxed::Box as B;
enum Opt<T> {
Empty,
fn main() {
let stack_unique: UniqueNode<u16> = UniqueNode {
next: Val {
- val: box UniqueNode {
+ val: Box::new(UniqueNode {
next: Empty,
value: 1,
- }
+ })
},
value: 0,
};
- let unique_unique: Box<UniqueNode<u32>> = box UniqueNode {
+ let unique_unique: Box<UniqueNode<u32>> = Box::new(UniqueNode {
next: Val {
- val: box UniqueNode {
+ val: Box::new(UniqueNode {
next: Empty,
value: 3,
- }
+ })
},
value: 2,
- };
+ });
let vec_unique: [UniqueNode<f32>; 1] = [UniqueNode {
next: Val {
- val: box UniqueNode {
+ val: Box::new(UniqueNode {
next: Empty,
value: 7.5,
- }
+ })
},
value: 6.5,
}];
let borrowed_unique: &UniqueNode<f64> = &UniqueNode {
next: Val {
- val: box UniqueNode {
+ val: Box::new(UniqueNode {
next: Empty,
value: 9.5,
- }
+ })
},
value: 8.5,
};
// LONG CYCLE
let long_cycle1: LongCycle1<u16> = LongCycle1 {
- next: box LongCycle2 {
- next: box LongCycle3 {
- next: box LongCycle4 {
+ next: Box::new(LongCycle2 {
+ next: Box::new(LongCycle3 {
+ next: Box::new(LongCycle4 {
next: None,
value: 23,
- },
+ }),
value: 22,
- },
+ }),
value: 21
- },
+ }),
value: 20
};
let long_cycle2: LongCycle2<u32> = LongCycle2 {
- next: box LongCycle3 {
- next: box LongCycle4 {
+ next: Box::new(LongCycle3 {
+ next: Box::new(LongCycle4 {
next: None,
value: 26,
- },
+ }),
value: 25,
- },
+ }),
value: 24
};
let long_cycle3: LongCycle3<u64> = LongCycle3 {
- next: box LongCycle4 {
+ next: Box::new(LongCycle4 {
next: None,
value: 28,
- },
+ }),
value: 27,
};
// It's important that LongCycleWithAnonymousTypes is encountered only at the end of the
// `box` chain.
- let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes {
+ let long_cycle_w_anon_types = B::new(B::new(B::new(B::new(B::new(LongCycleWithAnonymousTypes {
next: Val {
- val: box box box box box LongCycleWithAnonymousTypes {
+ val: Box::new(Box::new(Box::new(Box::new(Box::new(LongCycleWithAnonymousTypes {
next: Empty,
value: 31,
- }
+ })))))
},
value: 30
- };
+ })))));
zzz(); // #break
}
// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, -2);
let _ = stack.self_by_val(-3, -4);
- let owned: Box<_> = box Struct { x: 200 };
+ let owned: Box<_> = Box::new(Struct { x: 200 });
let _ = owned.self_by_ref(-5, -6);
let _ = owned.self_by_val(-7, -8);
let _ = owned.self_owned(-9, -10);
// lldbr-check:(f32) arg2 = -10.5
// lldb-command:continue
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let _ = stack.self_by_ref(-1, 2_u16);
let _ = stack.self_by_val(-3, -4_i16);
- let owned: Box<_> = box Struct { x: 879 };
+ let owned: Box<_> = Box::new(Struct { x: 879 });
let _ = owned.self_by_ref(-5, -6_i32);
let _ = owned.self_by_val(-7, -8_i64);
let _ = owned.self_owned(-9, -10.5_f32);
// lldb-command:run
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
let stack_struct = Struct { a:0, b: 1.0 };
let reference: &Trait = &stack_struct as &Trait;
- let unique: Box<Trait> = box Struct { a:2, b: 3.0 } as Box<Trait>;
+ let unique: Box<Trait> = Box::new(Struct { a:2, b: 3.0 }) as Box<Trait>;
}
// cdb-check:struct ForeignType2 * foreign2 = [...]
// cdb-check:struct ForeignType1 * foreign1 = [...]
-#![feature(box_syntax)]
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
let tuple2 = ((Struct1, mod1::mod2::Struct3), mod1::Variant1, 'x');
// Box
- let box1 = (box 1f32, 0i32);
- let box2 = (box mod1::mod2::Variant2(1f32), 0i32);
+ let box1 = (Box::new(1f32), 0i32);
+ let box2 = (Box::new(mod1::mod2::Variant2(1f32)), 0i32);
// References
let ref1 = (&Struct1, 0i32);
let slice2 = &*vec2;
// Trait Objects
- let box_trait = (box 0_isize) as Box<dyn Trait1>;
+ let box_trait = Box::new(0_isize) as Box<dyn Trait1>;
let ref_trait = &0_isize as &dyn Trait1;
let mut mut_int1 = 0_isize;
let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1;
- let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>;
+ let no_principal_trait = Box::new(0_isize) as Box<(dyn Send + Sync)>;
let has_associated_type_trait = &0_isize as &(dyn Trait3<u32, AssocType = isize> + Send);
- let generic_box_trait = (box 0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
+ let generic_box_trait = Box::new(0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
let generic_ref_trait = (&0_isize) as &dyn Trait2<Struct1, Struct1>;
let mut generic_mut_ref_trait_impl = 0_isize;
// lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } }
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// 0b01111100011111000111110001111100 = 2088533116
// 0b0111110001111100 = 31868
// 0b01111100 = 124
- let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 };
+ let the_a: Box<_> = Box::new(ABC::TheA { x: 0, y: 8970181431921507452 });
// 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
// 0b00010001000100010001000100010001 = 286331153
// 0b0001000100010001 = 4369
// 0b00010001 = 17
- let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153);
+ let the_b: Box<_> = Box::new(ABC::TheB (0, 286331153, 286331153));
- let univariant: Box<_> = box Univariant::TheOnlyCase(123234);
+ let univariant: Box<_> = Box::new(Univariant::TheOnlyCase(123234));
zzz(); // #break
}
// cdb-check:closure_local : 8 [Type: [...]]
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
};
let struct_ref = &a_struct;
- let owned: Box<_> = box 6;
+ let owned: Box<_> = Box::new(6);
let mut closure = || {
let closure_local = 8;
// lldbr-check:(isize) *owned = 5
#![allow(unused_variables)]
-#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
c: 4
};
- let owned: Box<_> = box 5;
+ let owned: Box<_> = Box::new(5);
let closure = move || {
zzz(); // #break
// cdb-command: dx owned
// cdb-check:owned : 0x[...] : 6 [Type: [...] *]
-#![feature(box_syntax)]
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
};
let struct_ref = &a_struct;
- let owned: Box<_> = box 6;
+ let owned: Box<_> = Box::new(6);
{
let mut first_closure = || {
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/box_expr.rs:6:11: 6:11
let _1: std::boxed::Box<S>; // in scope 0 at $DIR/box_expr.rs:7:9: 7:10
- let mut _2: std::boxed::Box<S>; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
- let _3: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12
- let mut _4: std::boxed::Box<S>; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11
+ let mut _2: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ let mut _3: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ let mut _4: *mut u8; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ let mut _5: std::boxed::Box<S>; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ let _6: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12
+ let mut _7: std::boxed::Box<S>; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11
scope 1 {
debug x => _1; // in scope 1 at $DIR/box_expr.rs:7:9: 7:10
}
+ scope 2 {
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10
- StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25
- _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25
- (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
+ _2 = SizeOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25
+ _3 = AlignOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25
// mir::Constant
- // + span: $DIR/box_expr.rs:7:17: 7:23
- // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) }
+ // + span: $DIR/box_expr.rs:7:13: 7:25
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
}
bb1: {
- _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25
- drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+ StorageLive(_5); // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
+ // mir::Constant
+ // + span: $DIR/box_expr.rs:7:17: 7:23
+ // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) }
}
bb2: {
- StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25
- StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12
- StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11
- _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11
- _3 = std::mem::drop::<Box<S>>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
+ _1 = move _5; // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+ drop(_5) -> bb3; // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+ }
+
+ bb3: {
+ StorageDead(_5); // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+ StorageLive(_6); // scope 1 at $DIR/box_expr.rs:8:5: 8:12
+ StorageLive(_7); // scope 1 at $DIR/box_expr.rs:8:10: 8:11
+ _7 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11
+ _6 = std::mem::drop::<Box<S>>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
// mir::Constant
// + span: $DIR/box_expr.rs:8:5: 8:9
// + literal: Const { ty: fn(std::boxed::Box<S>) {std::mem::drop::<std::boxed::Box<S>>}, val: Value(Scalar(<ZST>)) }
}
- bb3: {
- StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12
- StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13
+ bb4: {
+ StorageDead(_7); // scope 1 at $DIR/box_expr.rs:8:11: 8:12
+ StorageDead(_6); // scope 1 at $DIR/box_expr.rs:8:12: 8:13
_0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2
- drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+ drop(_1) -> bb5; // scope 0 at $DIR/box_expr.rs:9:1: 9:2
}
- bb4: {
+ bb5: {
StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2
return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2
}
- bb5 (cleanup): {
- drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12
- }
-
bb6 (cleanup): {
- drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+ drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:8:11: 8:12
}
bb7 (cleanup): {
- drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+ drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:9:1: 9:2
}
bb8 (cleanup): {
+ drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+ }
+
+ bb9 (cleanup): {
resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2
}
}
let _1: i32; // in scope 0 at $DIR/boxes.rs:12:9: 12:10
let mut _2: i32; // in scope 0 at $DIR/boxes.rs:12:13: 12:22
let mut _3: std::boxed::Box<i32>; // in scope 0 at $DIR/boxes.rs:12:14: 12:22
- let mut _4: std::boxed::Box<i32>; // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+ let mut _4: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+ let mut _5: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+ let mut _6: *mut u8; // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+ let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/boxes.rs:12:14: 12:22
scope 1 {
debug x => _1; // in scope 1 at $DIR/boxes.rs:12:9: 12:10
}
+ scope 2 {
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/boxes.rs:12:9: 12:10
StorageLive(_2); // scope 0 at $DIR/boxes.rs:12:13: 12:22
StorageLive(_3); // scope 0 at $DIR/boxes.rs:12:14: 12:22
- StorageLive(_4); // scope 0 at $DIR/boxes.rs:12:14: 12:22
- _4 = Box(i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22
- (*_4) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21
- _3 = move _4; // scope 0 at $DIR/boxes.rs:12:14: 12:22
- StorageDead(_4); // scope 0 at $DIR/boxes.rs:12:21: 12:22
+- _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22
+- _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22
+- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22
++ _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22
++ _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22
++ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22
+ // mir::Constant
+ // + span: $DIR/boxes.rs:12:14: 12:22
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ StorageLive(_7); // scope 0 at $DIR/boxes.rs:12:14: 12:22
+ _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22
+ (*_7) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21
+ _3 = move _7; // scope 0 at $DIR/boxes.rs:12:14: 12:22
+ StorageDead(_7); // scope 0 at $DIR/boxes.rs:12:21: 12:22
_2 = (*_3); // scope 0 at $DIR/boxes.rs:12:13: 12:22
_1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26
StorageDead(_2); // scope 0 at $DIR/boxes.rs:12:25: 12:26
- drop(_3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/boxes.rs:12:26: 12:27
+ drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:12:26: 12:27
}
- bb1: {
+ bb2: {
StorageDead(_3); // scope 0 at $DIR/boxes.rs:12:26: 12:27
nop; // scope 0 at $DIR/boxes.rs:11:11: 13:2
StorageDead(_1); // scope 0 at $DIR/boxes.rs:13:1: 13:2
return; // scope 0 at $DIR/boxes.rs:13:2: 13:2
}
- bb2 (cleanup): {
+ bb3 (cleanup): {
resume; // scope 0 at $DIR/boxes.rs:11:1: 13:2
}
}
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11
let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
- let mut _2: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
-+ let mut _4: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++ let mut _7: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
scope 1 {
debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11
}
-+ scope 2 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
+ scope 2 {
+ }
++ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
- StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- _2 = Box(std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-- (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ // mir::Constant
+ // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+- (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ // ty::Const
+ // + ty: alloc::raw_vec::RawVec<u32>
+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
- // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
- }
-
-- bb1: {
+- bb2: {
+ // + span: $DIR/inline-into-box-place.rs:8:33: 8:43
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
- _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
_0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
-- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
-+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
+- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
}
-- bb2: {
-+ bb1: {
+- bb3: {
++ bb2: {
StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2
}
-- bb3 (cleanup): {
-+ bb2 (cleanup): {
+- bb4 (cleanup): {
++ bb3 (cleanup): {
resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
- }
-
-- bb4 (cleanup): {
-- _3 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+- bb5 (cleanup): {
+- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
- // mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
- // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<std::vec::Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11
let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
- let mut _2: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
-+ let mut _4: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++ let mut _7: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
scope 1 {
debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11
}
-+ scope 2 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
+ scope 2 {
+ }
++ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
- StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- _2 = Box(std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-- (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ // mir::Constant
+ // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+- (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ // ty::Const
+ // + ty: alloc::raw_vec::RawVec<u32>
+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
- // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
- }
-
-- bb1: {
+- bb2: {
+ // + span: $DIR/inline-into-box-place.rs:8:33: 8:43
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
- _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+ StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
_0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
-- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
-+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
+- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
}
-- bb2: {
-+ bb1: {
+- bb3: {
++ bb2: {
StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2
}
-- bb3 (cleanup): {
-+ bb2 (cleanup): {
+- bb4 (cleanup): {
++ bb3 (cleanup): {
resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
- }
-
-- bb4 (cleanup): {
-- _3 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+- bb5 (cleanup): {
+- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
- // mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
- // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<std::vec::Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
fn test() -> Option<Box<u32>> {
let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30
let mut _1: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
- let mut _2: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
- let mut _3: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
- let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19
- let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- let _6: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- let mut _8: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ let mut _5: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ let mut _6: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19
+ let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ let _9: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ let mut _11: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ let _12: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
scope 1 {
- debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20
- scope 2 {
+ }
+ scope 2 {
+ debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+ scope 3 {
}
}
- scope 3 {
- debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20
- scope 4 {
+ scope 4 {
+ debug val => _12; // in scope 4 at $DIR/issue-62289.rs:9:15: 9:20
+ scope 5 {
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
- StorageLive(_2); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
- _2 = Box(u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
- StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
- StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
- _4 = Option::<u32>::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
- _3 = <Option<u32> as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
+ _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
// mir::Constant
- // + span: $DIR/issue-62289.rs:9:15: 9:20
- // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) }
+ // + span: $DIR/issue-62289.rs:9:10: 9:21
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
}
bb1: {
- StorageDead(_4); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- _5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
- switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
+ _7 = Option::<u32>::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
+ _6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ // mir::Constant
+ // + span: $DIR/issue-62289.rs:9:15: 9:20
+ // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) }
}
bb2: {
- StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
- _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
- (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
- StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
- drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+ StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
}
bb3: {
- unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+ (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:9:15: 9:20
+ StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ _1 = move _5; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+ drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
}
bb4: {
- StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- _6 = ((_3 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
- _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
- _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
- // mir::Constant
- // + span: $DIR/issue-62289.rs:9:19: 9:20
- // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
+ unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
}
bb5: {
- StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
- StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
- drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+ StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ _9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20
+ _11 = _9; // scope 3 at $DIR/issue-62289.rs:9:19: 9:20
+ _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20
+ // mir::Constant
+ // + span: $DIR/issue-62289.rs:9:19: 9:20
+ // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
}
bb6: {
- StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
- _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
- drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+ StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20
+ StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+ drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
}
bb7: {
- StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
- StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
- goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+ StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+ _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
+ drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
}
bb8: {
- StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
- StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
- goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+ StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
+ goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
}
bb9: {
- return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+ StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+ StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+ StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
+ goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
}
- bb10 (cleanup): {
- drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+ bb10: {
+ return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
}
bb11 (cleanup): {
- drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+ drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
}
bb12 (cleanup): {
+ drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+ }
+
+ bb13 (cleanup): {
resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2
}
}
let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:10:27: 10:27
let _1: [std::boxed::Box<i32>; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
let mut _2: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- let mut _3: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- let mut _4: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
- let mut _5: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ let mut _6: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ let mut _11: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
scope 1 {
debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:11:9: 11:10
- let _6: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
- scope 2 {
- debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+ let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+ scope 4 {
+ debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:12:10: 12:17
}
}
+ scope 2 {
+ }
+ scope 3 {
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
- _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
- drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+ _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
}
bb1: {
- StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
- StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
- StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
- _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
- (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
- _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
- drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+ StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+ _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+ drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
}
bb2: {
- StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
- _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27
- drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+ StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
}
bb3: {
- StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
- drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+ _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+ drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
}
bb4: {
+ StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+ _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27
+ drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ }
+
+ bb5: {
+ StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ }
+
+ bb6: {
StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
- StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
- _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+ StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+ _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
_0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2
- drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+ drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
}
- bb5: {
- StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
- drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+ bb7: {
+ StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+ drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
}
- bb6: {
+ bb8: {
StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2
}
- bb7 (cleanup): {
- drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+ bb9 (cleanup): {
+ drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
}
- bb8 (cleanup): {
- drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ bb10 (cleanup): {
+ drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
}
- bb9 (cleanup): {
- drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+ bb11 (cleanup): {
+ drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
}
- bb10 (cleanup): {
+ bb12 (cleanup): {
resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2
}
}
let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:4:24: 4:24
let _1: [std::boxed::Box<i32>; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
let mut _2: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- let mut _3: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- let mut _4: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
- let mut _5: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ let mut _6: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ let mut _11: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
scope 1 {
debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:5:9: 5:10
- let _6: std::boxed::Box<i32>; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
- scope 2 {
- debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+ let _12: std::boxed::Box<i32>; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+ scope 4 {
+ debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:6:14: 6:16
}
}
+ scope 2 {
+ }
+ scope 3 {
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
- _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
- drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+ _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
}
bb1: {
- StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
- StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
- StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
- _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
- (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
- _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
- drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+ StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+ _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+ drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
}
bb2: {
- StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
- _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27
- drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+ StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
}
bb3: {
- StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
- drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+ _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+ drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
}
bb4: {
+ StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+ _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27
+ drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ }
+
+ bb5: {
+ StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ }
+
+ bb6: {
StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
- StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
- _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+ StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+ _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
_0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2
- drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+ drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
}
- bb5: {
- StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
- drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+ bb7: {
+ StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+ drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
}
- bb6: {
+ bb8: {
StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2
}
- bb7 (cleanup): {
- drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+ bb9 (cleanup): {
+ drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
}
- bb8 (cleanup): {
- drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ bb10 (cleanup): {
+ drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
}
- bb9 (cleanup): {
- drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+ bb11 (cleanup): {
+ drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
}
- bb10 (cleanup): {
+ bb12 (cleanup): {
resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2
}
}
--- /dev/null
+// edition:2021
+
+#![deny(rustdoc::invalid_rust_codeblocks)]
+//~^ NOTE lint level is defined here
+
+// By default, rustdoc should use the edition of the crate.
+//! ```
+//! foo'b'
+//! ```
+//~^^^ ERROR could not parse
+//~| NOTE prefix `foo` is unknown
+
+// Rustdoc should respect `edition2018` when highlighting syntax.
+//! ```edition2018
+//! foo'b'
+//! ```
--- /dev/null
+error: could not parse code block as Rust code
+ --> $DIR/doctest-edition.rs:7:5
+ |
+LL | //! ```
+ | _____^
+LL | | //! foo'b'
+LL | | //! ```
+ | |_______^
+ |
+note: the lint level is defined here
+ --> $DIR/doctest-edition.rs:3:9
+ |
+LL | #![deny(rustdoc::invalid_rust_codeblocks)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: error from rustc: prefix `foo` is unknown
+help: mark blocks that do not contain Rust code as text
+ |
+LL | //! ```text
+ | ++++
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-flags: -Z unstable-options --document-hidden-items
+
+// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed.
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+// @has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @has - '//*[@id="tymethod.f"]' 'fn f()'
+// @has - '//*[@id="tymethod.g"]' 'fn g()'
+pub trait Trait {
+ #[doc(hidden)]
+ type Foo;
+ type Bar;
+ #[doc(hidden)]
+ fn f();
+ fn g();
+}
+
+// @has foo/struct.S.html
+// @has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @has - '//*[@id="method.f"]' 'fn f()'
+// @has - '//*[@id="method.g"]' 'fn g()'
+pub struct S;
+impl Trait for S {
+ type Foo = ();
+ type Bar = ();
+ fn f() {}
+ fn g() {}
+}
--- /dev/null
+// test for trait methods with `doc(hidden)`.
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @!has - '//*[@id="tymethod.f"]' 'fn f()'
+// @has - '//*[@id="tymethod.g"]' 'fn g()'
+pub trait Trait {
+ #[doc(hidden)]
+ type Foo;
+ type Bar;
+ #[doc(hidden)]
+ fn f();
+ fn g();
+}
+
+// @has foo/struct.S.html
+// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @!has - '//*[@id="method.f"]' 'fn f()'
+// @has - '//*[@id="method.g"]' 'fn g()'
+pub struct S;
+impl Trait for S {
+ type Foo = ();
+ type Bar = ();
+ fn f() {}
+ fn g() {}
+}
-#![feature(box_syntax, plugin, rustc_private)]
+#![feature(plugin, rustc_private)]
#![crate_type = "dylib"]
extern crate rustc_ast_pretty;
#[no_mangle]
fn __rustc_plugin_registrar(reg: &mut Registry) {
reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]);
- reg.lint_store.register_late_pass(|| box MissingAllowedAttrPass);
+ reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass));
}
declare_lint! {
// force-host
#![feature(rustc_private)]
-#![feature(box_syntax)]
extern crate rustc_driver;
extern crate rustc_hir;
&CRATE_NOT_GREY,
&CRATE_NOT_GREEN,
]);
- reg.lint_store.register_late_pass(|| box PassOkay);
- reg.lint_store.register_late_pass(|| box PassRedBlue);
- reg.lint_store.register_late_pass(|| box PassGreyGreen);
+ reg.lint_store.register_late_pass(|| Box::new(PassOkay));
+ reg.lint_store.register_late_pass(|| Box::new(PassRedBlue));
+ reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen));
}
// force-host
#![feature(rustc_private)]
-#![feature(box_syntax)]
extern crate rustc_driver;
extern crate rustc_hir;
#[no_mangle]
fn __rustc_plugin_registrar(reg: &mut Registry) {
reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]);
- reg.lint_store.register_late_pass(|| box Pass);
+ reg.lint_store.register_late_pass(|| Box::new(Pass));
}
// force-host
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
// Load rustc as a plugin to get macros.
extern crate rustc_driver;
#[no_mangle]
fn __rustc_plugin_registrar(reg: &mut Registry) {
reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]);
- reg.lint_store.register_late_pass(|| box Pass);
+ reg.lint_store.register_late_pass(|| Box::new(Pass));
reg.lint_store.register_group(
true,
"lint_me",
// force-host
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
extern crate rustc_ast;
#[no_mangle]
fn __rustc_plugin_registrar(reg: &mut Registry) {
reg.lint_store.register_lints(&[&TEST_LINT]);
- reg.lint_store.register_early_pass(|| box Pass);
+ reg.lint_store.register_early_pass(|| Box::new(Pass));
}
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
extern crate rustc_ast;
#[no_mangle]
fn __rustc_plugin_registrar(reg: &mut Registry) {
reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]);
- reg.lint_store.register_early_pass(|| box Pass);
+ reg.lint_store.register_early_pass(|| Box::new(Pass));
reg.lint_store.register_group(
true,
"clippy::group",
// force-host
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
extern crate rustc_middle;
extern crate rustc_driver;
#[no_mangle]
fn __rustc_plugin_registrar(_: &mut Registry) {
thread_local!(static FOO: RefCell<Option<Box<Any+Send>>> = RefCell::new(None));
- FOO.with(|s| *s.borrow_mut() = Some(box Foo { foo: 10 } as Box<Any+Send>));
+ FOO.with(|s| *s.borrow_mut() = Some(Box::new(Foo { foo: 10 }) as Box<Any+Send>));
}
// run-pass
#![allow(unused_imports)]
-#![feature(box_syntax)]
#![feature(rustc_private)]
extern crate rustc_macros;
#![allow(non_camel_case_types)]
#![allow(dead_code)]
-#![feature(box_syntax)]
-
struct pair<A,B> {
a: A, b: B
}
}
fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> {
- box Invoker {
+ Box::new(Invoker {
a: a,
b: b,
- } as Box<dyn Invokable<A>+'static>
+ }) as Box<dyn Invokable<A>+'static>
}
pub fn main() {
// run-pass
-#![feature(box_syntax)]
-
pub fn main() {
- // Tests for indexing into box/& [T; n]
+ // Tests for indexing into Box<[T; n]>/& [T; n]
let x: [isize; 3] = [1, 2, 3];
- let mut x: Box<[isize; 3]> = box x;
+ let mut x: Box<[isize; 3]> = x.into();
assert_eq!(x[0], 1);
assert_eq!(x[1], 2);
assert_eq!(x[2], 3);
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
-pub fn main() { let _quux: Box<Vec<usize>> = box Vec::new(); }
+pub fn main() {
+ let _quux: Box<Vec<usize>> = Box::new(Vec::new());
+}
--- /dev/null
+// only-aarch64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ let mut foo = 0;
+ unsafe {
+ asm!("", options(nomem, readonly));
+ //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+ asm!("", options(pure, nomem, noreturn));
+ //~^ ERROR the `pure` and `noreturn` options are mutually exclusive
+ //~^^ ERROR asm with the `pure` option must have at least one output
+ asm!("{}", in(reg) foo, options(pure, nomem));
+ //~^ ERROR asm with the `pure` option must have at least one output
+ asm!("{}", out(reg) foo, options(noreturn));
+ //~^ ERROR asm outputs are not allowed with the `noreturn` option
+ }
+
+ unsafe {
+ asm!("", clobber_abi("foo"));
+ //~^ ERROR invalid ABI for `clobber_abi`
+ asm!("{}", out(reg) foo, clobber_abi("C"));
+ //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+ asm!("", out("x0") foo, clobber_abi("C"));
+ }
+}
+
+global_asm!("", options(nomem));
+//~^ ERROR expected one of
+global_asm!("", options(readonly));
+//~^ ERROR expected one of
+global_asm!("", options(noreturn));
+//~^ ERROR expected one of
+global_asm!("", options(pure));
+//~^ ERROR expected one of
+global_asm!("", options(nostack));
+//~^ ERROR expected one of
+global_asm!("", options(preserves_flags));
+//~^ ERROR expected one of
--- /dev/null
+error: the `nomem` and `readonly` options are mutually exclusive
+ --> $DIR/bad-options.rs:8:18
+ |
+LL | asm!("", options(nomem, readonly));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the `pure` and `noreturn` options are mutually exclusive
+ --> $DIR/bad-options.rs:10:18
+ |
+LL | asm!("", options(pure, nomem, noreturn));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+ --> $DIR/bad-options.rs:10:18
+ |
+LL | asm!("", options(pure, nomem, noreturn));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+ --> $DIR/bad-options.rs:13:33
+ |
+LL | asm!("{}", in(reg) foo, options(pure, nomem));
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: asm outputs are not allowed with the `noreturn` option
+ --> $DIR/bad-options.rs:15:20
+ |
+LL | asm!("{}", out(reg) foo, options(noreturn));
+ | ^^^^^^^^^^^^
+
+error: asm with `clobber_abi` must specify explicit registers for outputs
+ --> $DIR/bad-options.rs:22:20
+ |
+LL | asm!("{}", out(reg) foo, clobber_abi("C"));
+ | ^^^^^^^^^^^^ ---------------- clobber_abi
+ | |
+ | generic outputs
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+ --> $DIR/bad-options.rs:28:25
+ |
+LL | global_asm!("", options(nomem));
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+ --> $DIR/bad-options.rs:30:25
+ |
+LL | global_asm!("", options(readonly));
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+ --> $DIR/bad-options.rs:32:25
+ |
+LL | global_asm!("", options(noreturn));
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+ --> $DIR/bad-options.rs:34:25
+ |
+LL | global_asm!("", options(pure));
+ | ^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+ --> $DIR/bad-options.rs:36:25
+ |
+LL | global_asm!("", options(nostack));
+ | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+ --> $DIR/bad-options.rs:38:25
+ |
+LL | global_asm!("", options(preserves_flags));
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: invalid ABI for `clobber_abi`
+ --> $DIR/bad-options.rs:20:18
+ |
+LL | asm!("", clobber_abi("foo"));
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`
+
+error: aborting due to 13 previous errors
+
--- /dev/null
+// only-aarch64
+// compile-flags: -C target-feature=+fp
+
+#![feature(asm)]
+
+fn main() {
+ let mut foo = 0;
+ let mut bar = 0;
+ unsafe {
+ // Bad register/register class
+
+ asm!("{}", in(foo) foo);
+ //~^ ERROR invalid register class `foo`: unknown register class
+ asm!("", in("foo") foo);
+ //~^ ERROR invalid register `foo`: unknown register
+ asm!("{:z}", in(reg) foo);
+ //~^ ERROR invalid asm template modifier for this register class
+ asm!("{:r}", in(vreg) foo);
+ //~^ ERROR invalid asm template modifier for this register class
+ asm!("{:r}", in(vreg_low16) foo);
+ //~^ ERROR invalid asm template modifier for this register class
+ asm!("{:a}", const 0);
+ //~^ ERROR asm template modifiers are not allowed for `const` arguments
+ asm!("{:a}", sym main);
+ //~^ ERROR asm template modifiers are not allowed for `sym` arguments
+ asm!("", in("x29") foo);
+ //~^ ERROR invalid register `x29`: the frame pointer cannot be used as an operand
+ asm!("", in("sp") foo);
+ //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand
+ asm!("", in("xzr") foo);
+ //~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand
+ asm!("", in("x18") foo);
+ //~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
+ asm!("", in("x19") foo);
+ //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
+
+ asm!("", in("p0") foo);
+ //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output
+ asm!("", out("p0") _);
+ asm!("{}", in(preg) foo);
+ //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output
+ asm!("{}", out(preg) _);
+ //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output
+
+ // Explicit register conflicts
+ // (except in/lateout which don't conflict)
+
+ asm!("", in("x0") foo, in("w0") bar);
+ //~^ ERROR register `x0` conflicts with register `x0`
+ asm!("", in("x0") foo, out("x0") bar);
+ //~^ ERROR register `x0` conflicts with register `x0`
+ asm!("", in("w0") foo, lateout("w0") bar);
+ asm!("", in("v0") foo, in("q0") bar);
+ //~^ ERROR register `v0` conflicts with register `v0`
+ asm!("", in("v0") foo, out("q0") bar);
+ //~^ ERROR register `v0` conflicts with register `v0`
+ asm!("", in("v0") foo, lateout("q0") bar);
+ }
+}
--- /dev/null
+error: invalid register class `foo`: unknown register class
+ --> $DIR/bad-reg.rs:12:20
+ |
+LL | asm!("{}", in(foo) foo);
+ | ^^^^^^^^^^^
+
+error: invalid register `foo`: unknown register
+ --> $DIR/bad-reg.rs:14:18
+ |
+LL | asm!("", in("foo") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid asm template modifier for this register class
+ --> $DIR/bad-reg.rs:16:15
+ |
+LL | asm!("{:z}", in(reg) foo);
+ | ^^^^ ----------- argument
+ | |
+ | template modifier
+ |
+ = note: the `reg` register class supports the following template modifiers: `w`, `x`
+
+error: invalid asm template modifier for this register class
+ --> $DIR/bad-reg.rs:18:15
+ |
+LL | asm!("{:r}", in(vreg) foo);
+ | ^^^^ ------------ argument
+ | |
+ | template modifier
+ |
+ = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`
+
+error: invalid asm template modifier for this register class
+ --> $DIR/bad-reg.rs:20:15
+ |
+LL | asm!("{:r}", in(vreg_low16) foo);
+ | ^^^^ ------------------ argument
+ | |
+ | template modifier
+ |
+ = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`
+
+error: asm template modifiers are not allowed for `const` arguments
+ --> $DIR/bad-reg.rs:22:15
+ |
+LL | asm!("{:a}", const 0);
+ | ^^^^ ------- argument
+ | |
+ | template modifier
+
+error: asm template modifiers are not allowed for `sym` arguments
+ --> $DIR/bad-reg.rs:24:15
+ |
+LL | asm!("{:a}", sym main);
+ | ^^^^ -------- argument
+ | |
+ | template modifier
+
+error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:26:18
+ |
+LL | asm!("", in("x29") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:28:18
+ |
+LL | asm!("", in("sp") foo);
+ | ^^^^^^^^^^^^
+
+error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:30:18
+ |
+LL | asm!("", in("xzr") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:32:18
+ |
+LL | asm!("", in("x18") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:34:18
+ |
+LL | asm!("", in("x19") foo);
+ | ^^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:37:18
+ |
+LL | asm!("", in("p0") foo);
+ | ^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:40:20
+ |
+LL | asm!("{}", in(preg) foo);
+ | ^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:42:20
+ |
+LL | asm!("{}", out(preg) _);
+ | ^^^^^^^^^^^
+
+error: register `x0` conflicts with register `x0`
+ --> $DIR/bad-reg.rs:48:32
+ |
+LL | asm!("", in("x0") foo, in("w0") bar);
+ | ------------ ^^^^^^^^^^^^ register `x0`
+ | |
+ | register `x0`
+
+error: register `x0` conflicts with register `x0`
+ --> $DIR/bad-reg.rs:50:32
+ |
+LL | asm!("", in("x0") foo, out("x0") bar);
+ | ------------ ^^^^^^^^^^^^^ register `x0`
+ | |
+ | register `x0`
+ |
+help: use `lateout` instead of `out` to avoid conflict
+ --> $DIR/bad-reg.rs:50:18
+ |
+LL | asm!("", in("x0") foo, out("x0") bar);
+ | ^^^^^^^^^^^^
+
+error: register `v0` conflicts with register `v0`
+ --> $DIR/bad-reg.rs:53:32
+ |
+LL | asm!("", in("v0") foo, in("q0") bar);
+ | ------------ ^^^^^^^^^^^^ register `v0`
+ | |
+ | register `v0`
+
+error: register `v0` conflicts with register `v0`
+ --> $DIR/bad-reg.rs:55:32
+ |
+LL | asm!("", in("v0") foo, out("q0") bar);
+ | ------------ ^^^^^^^^^^^^^ register `v0`
+ | |
+ | register `v0`
+ |
+help: use `lateout` instead of `out` to avoid conflict
+ --> $DIR/bad-reg.rs:55:18
+ |
+LL | asm!("", in("v0") foo, out("q0") bar);
+ | ^^^^^^^^^^^^
+
+error: aborting due to 19 previous errors
+
--- /dev/null
+// min-llvm-version: 10.0.1
+// only-aarch64
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![feature(asm, global_asm)]
+
+fn const_generic<const X: usize>() -> usize {
+ unsafe {
+ let a: usize;
+ asm!("mov {}, {}", out(reg) a, const X);
+ a
+ }
+}
+
+const fn constfn(x: usize) -> usize {
+ x
+}
+
+fn main() {
+ unsafe {
+ let a: usize;
+ asm!("mov {}, {}", out(reg) a, const 5);
+ assert_eq!(a, 5);
+
+ let b: usize;
+ asm!("mov {}, {}", out(reg) b, const constfn(5));
+ assert_eq!(b, 5);
+
+ let c: usize;
+ asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
+ assert_eq!(c, 10);
+ }
+
+ let d = const_generic::<5>();
+ assert_eq!(d, 5);
+}
+
+global_asm!("mov x0, {}", const 5);
+global_asm!("mov x0, {}", const constfn(5));
+global_asm!("mov x0, {}", const constfn(5) + constfn(5));
--- /dev/null
+// only-aarch64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(nomem, ));
+ //~^ ERROR the `nomem` option was already provided
+ asm!("", options(preserves_flags, ));
+ //~^ ERROR the `preserves_flags` option was already provided
+ asm!("", options(nostack, preserves_flags), options());
+ //~^ ERROR the `nostack` option was already provided
+ asm!("", options(nostack, ), options(), options());
+ //~^ ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ asm!(
+ "",
+ options(nomem, noreturn),
+ options(preserves_flags, ), //~ ERROR the `noreturn` option was already provided
+ options( nostack), //~ ERROR the `nomem` option was already provided
+ options(), //~ ERROR the `noreturn` option was already provided
+ );
+ }
+}
--- /dev/null
+// only-aarch64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(nomem, nomem));
+ //~^ ERROR the `nomem` option was already provided
+ asm!("", options(preserves_flags, preserves_flags));
+ //~^ ERROR the `preserves_flags` option was already provided
+ asm!("", options(nostack, preserves_flags), options(nostack));
+ //~^ ERROR the `nostack` option was already provided
+ asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ //~^ ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ asm!(
+ "",
+ options(nomem, noreturn),
+ options(preserves_flags, noreturn), //~ ERROR the `noreturn` option was already provided
+ options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+ options(noreturn), //~ ERROR the `noreturn` option was already provided
+ );
+ }
+}
--- /dev/null
+error: the `nomem` option was already provided
+ --> $DIR/duplicate-options.rs:8:33
+ |
+LL | asm!("", options(nomem, nomem));
+ | ^^^^^ this option was already provided
+
+error: the `preserves_flags` option was already provided
+ --> $DIR/duplicate-options.rs:10:43
+ |
+LL | asm!("", options(preserves_flags, preserves_flags));
+ | ^^^^^^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:12:61
+ |
+LL | asm!("", options(nostack, preserves_flags), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:35
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:53
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:71
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+ --> $DIR/duplicate-options.rs:21:38
+ |
+LL | options(preserves_flags, noreturn),
+ | ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+ --> $DIR/duplicate-options.rs:22:21
+ |
+LL | options(nomem, nostack),
+ | ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+ --> $DIR/duplicate-options.rs:23:21
+ |
+LL | options(noreturn),
+ | ^^^^^^^^ this option was already provided
+
+error: aborting due to 9 previous errors
+
--- /dev/null
+// only-aarch64
+
+#![feature(asm)]
+
+macro_rules! m {
+ ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
+ $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
+ $noreturn:ident $nostack:ident $options:ident) => {
+ unsafe {
+ asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+ //~^ ERROR asm outputs are not allowed with the `noreturn` option
+ const x, sym x,
+ $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack));
+ //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+ //~| ERROR the `pure` and `noreturn` options are mutually exclusive
+ }
+ };
+}
+
+fn main() {
+ m!(in out lateout inout inlateout const sym
+ pure nomem readonly preserves_flags
+ noreturn nostack options);
+}
--- /dev/null
+error: the `nomem` and `readonly` options are mutually exclusive
+ --> $DIR/interpolated-idents.rs:13:13
+ |
+LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / m!(in out lateout inout inlateout const sym
+LL | | pure nomem readonly preserves_flags
+LL | | noreturn nostack options);
+ | |_________________________________- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `pure` and `noreturn` options are mutually exclusive
+ --> $DIR/interpolated-idents.rs:13:13
+ |
+LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / m!(in out lateout inout inlateout const sym
+LL | | pure nomem readonly preserves_flags
+LL | | noreturn nostack options);
+ | |_________________________________- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm outputs are not allowed with the `noreturn` option
+ --> $DIR/interpolated-idents.rs:10:32
+ |
+LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+ | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
+...
+LL | m!(in out lateout inout inlateout const sym
+ | _____-
+ | |_____|
+ | |_____|
+ | |_____|
+ | |
+LL | | pure nomem readonly preserves_flags
+LL | | noreturn nostack options);
+ | | -
+ | |_________________________________|
+ | |_________________________________in this macro invocation
+ | |_________________________________in this macro invocation
+ | |_________________________________in this macro invocation
+ | in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// only-aarch64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ let mut foo = 0;
+ let mut bar = 0;
+ unsafe {
+ asm!();
+ //~^ ERROR requires at least a template string argument
+ asm!(foo);
+ //~^ ERROR asm template must be a string literal
+ asm!("{}" foo);
+ //~^ ERROR expected token: `,`
+ asm!("{}", foo);
+ //~^ ERROR expected operand, clobber_abi, options, or additional template string
+ asm!("{}", in foo);
+ //~^ ERROR expected `(`, found `foo`
+ asm!("{}", in(reg foo));
+ //~^ ERROR expected `)`, found `foo`
+ asm!("{}", in(reg));
+ //~^ ERROR expected expression, found end of macro arguments
+ asm!("{}", inout(=) foo => bar);
+ //~^ ERROR expected register class or explicit register
+ asm!("{}", inout(reg) foo =>);
+ //~^ ERROR expected expression, found end of macro arguments
+ asm!("{}", in(reg) foo => bar);
+ //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+ asm!("{}", sym foo + bar);
+ //~^ ERROR argument to `sym` must be a path expression
+ asm!("", options(foo));
+ //~^ ERROR expected one of
+ asm!("", options(nomem foo));
+ //~^ ERROR expected one of
+ asm!("", options(nomem, foo));
+ //~^ ERROR expected one of
+ asm!("{}", options(), const foo);
+ //~^ ERROR arguments are not allowed after options
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", clobber_abi(foo));
+ //~^ ERROR expected string literal
+ asm!("", clobber_abi("C" foo));
+ //~^ ERROR expected `)`, found `foo`
+ asm!("", clobber_abi("C", foo));
+ //~^ ERROR expected `)`, found `,`
+ asm!("{}", clobber_abi("C"), const foo);
+ //~^ ERROR arguments are not allowed after clobber_abi
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", options(), clobber_abi("C"));
+ //~^ ERROR clobber_abi is not allowed after options
+ asm!("{}", options(), clobber_abi("C"), const foo);
+ //~^ ERROR clobber_abi is not allowed after options
+ asm!("", clobber_abi("C"), clobber_abi("C"));
+ //~^ ERROR clobber_abi specified multiple times
+ asm!("{a}", a = const foo, a = const bar);
+ //~^ ERROR duplicate argument named `a`
+ //~^^ ERROR argument never used
+ //~^^^ ERROR attempt to use a non-constant value in a constant
+ //~^^^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", a = in("x0") foo);
+ //~^ ERROR explicit register arguments cannot have names
+ asm!("{a}", in("x0") foo, a = const bar);
+ //~^ ERROR named arguments cannot follow explicit register arguments
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("{a}", in("x0") foo, a = const bar);
+ //~^ ERROR named arguments cannot follow explicit register arguments
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("{1}", in("x0") foo, const bar);
+ //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", options(), "");
+ //~^ ERROR expected one of
+ asm!("{}", in(reg) foo, "{}", out(reg) foo);
+ //~^ ERROR expected one of
+ asm!(format!("{{{}}}", 0), in(reg) foo);
+ //~^ ERROR asm template must be a string literal
+ asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+ //~^ ERROR asm template must be a string literal
+ asm!("{}", in(reg) _);
+ //~^ ERROR _ cannot be used for input operands
+ asm!("{}", inout(reg) _);
+ //~^ ERROR _ cannot be used for input operands
+ asm!("{}", inlateout(reg) _);
+ //~^ ERROR _ cannot be used for input operands
+ }
+}
+
+const FOO: i32 = 1;
+const BAR: i32 = 2;
+global_asm!();
+//~^ ERROR requires at least a template string argument
+global_asm!(FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{}" FOO);
+//~^ ERROR expected token: `,`
+global_asm!("{}", FOO);
+//~^ ERROR expected operand, options, or additional template string
+global_asm!("{}", const);
+//~^ ERROR expected expression, found end of macro arguments
+global_asm!("{}", const(reg) FOO);
+//~^ ERROR expected one of
+global_asm!("", options(FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem, FOO));
+//~^ ERROR expected one of
+global_asm!("{}", options(), const FOO);
+//~^ ERROR arguments are not allowed after options
+global_asm!("", clobber_abi(FOO));
+//~^ ERROR expected string literal
+global_asm!("", clobber_abi("C" FOO));
+//~^ ERROR expected `)`, found `FOO`
+global_asm!("", clobber_abi("C", FOO));
+//~^ ERROR expected `)`, found `,`
+global_asm!("{}", clobber_abi("C"), const FOO);
+//~^ ERROR arguments are not allowed after clobber_abi
+//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
+global_asm!("", options(), clobber_abi("C"));
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("{}", options(), clobber_abi("C"), const FOO);
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("", clobber_abi("C"), clobber_abi("C"));
+//~^ ERROR clobber_abi specified multiple times
+global_asm!("{a}", a = const FOO, a = const BAR);
+//~^ ERROR duplicate argument named `a`
+//~^^ ERROR argument never used
+global_asm!("", options(), "");
+//~^ ERROR expected one of
+global_asm!("{}", const FOO, "{}", const FOO);
+//~^ ERROR expected one of
+global_asm!(format!("{{{}}}", 0), const FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+//~^ ERROR asm template must be a string literal
--- /dev/null
+error: requires at least a template string argument
+ --> $DIR/parse-error.rs:9:9
+ |
+LL | asm!();
+ | ^^^^^^^
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:11:14
+ |
+LL | asm!(foo);
+ | ^^^
+
+error: expected token: `,`
+ --> $DIR/parse-error.rs:13:19
+ |
+LL | asm!("{}" foo);
+ | ^^^ expected `,`
+
+error: expected operand, clobber_abi, options, or additional template string
+ --> $DIR/parse-error.rs:15:20
+ |
+LL | asm!("{}", foo);
+ | ^^^ expected operand, clobber_abi, options, or additional template string
+
+error: expected `(`, found `foo`
+ --> $DIR/parse-error.rs:17:23
+ |
+LL | asm!("{}", in foo);
+ | ^^^ expected `(`
+
+error: expected `)`, found `foo`
+ --> $DIR/parse-error.rs:19:27
+ |
+LL | asm!("{}", in(reg foo));
+ | ^^^ expected `)`
+
+error: expected expression, found end of macro arguments
+ --> $DIR/parse-error.rs:21:27
+ |
+LL | asm!("{}", in(reg));
+ | ^ expected expression
+
+error: expected register class or explicit register
+ --> $DIR/parse-error.rs:23:26
+ |
+LL | asm!("{}", inout(=) foo => bar);
+ | ^
+
+error: expected expression, found end of macro arguments
+ --> $DIR/parse-error.rs:25:37
+ |
+LL | asm!("{}", inout(reg) foo =>);
+ | ^ expected expression
+
+error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+ --> $DIR/parse-error.rs:27:32
+ |
+LL | asm!("{}", in(reg) foo => bar);
+ | ^^ expected one of 7 possible tokens
+
+error: argument to `sym` must be a path expression
+ --> $DIR/parse-error.rs:29:24
+ |
+LL | asm!("{}", sym foo + bar);
+ | ^^^^^^^^^
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:31:26
+ |
+LL | asm!("", options(foo));
+ | ^^^ expected one of 9 possible tokens
+
+error: expected one of `)` or `,`, found `foo`
+ --> $DIR/parse-error.rs:33:32
+ |
+LL | asm!("", options(nomem foo));
+ | ^^^ expected one of `)` or `,`
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:35:33
+ |
+LL | asm!("", options(nomem, foo));
+ | ^^^ expected one of 9 possible tokens
+
+error: arguments are not allowed after options
+ --> $DIR/parse-error.rs:37:31
+ |
+LL | asm!("{}", options(), const foo);
+ | --------- ^^^^^^^^^ argument
+ | |
+ | previous options
+
+error: expected string literal
+ --> $DIR/parse-error.rs:40:30
+ |
+LL | asm!("", clobber_abi(foo));
+ | ^^^ not a string literal
+
+error: expected `)`, found `foo`
+ --> $DIR/parse-error.rs:42:34
+ |
+LL | asm!("", clobber_abi("C" foo));
+ | ^^^ expected `)`
+
+error: expected `)`, found `,`
+ --> $DIR/parse-error.rs:44:33
+ |
+LL | asm!("", clobber_abi("C", foo));
+ | ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+ --> $DIR/parse-error.rs:46:38
+ |
+LL | asm!("{}", clobber_abi("C"), const foo);
+ | ---------------- ^^^^^^^^^ argument
+ | |
+ | clobber_abi
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:49:29
+ |
+LL | asm!("", options(), clobber_abi("C"));
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:51:31
+ |
+LL | asm!("{}", options(), clobber_abi("C"), const foo);
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi specified multiple times
+ --> $DIR/parse-error.rs:53:36
+ |
+LL | asm!("", clobber_abi("C"), clobber_abi("C"));
+ | ---------------- ^^^^^^^^^^^^^^^^
+ | |
+ | clobber_abi previously specified here
+
+error: duplicate argument named `a`
+ --> $DIR/parse-error.rs:55:36
+ |
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ------------- ^^^^^^^^^^^^^ duplicate argument
+ | |
+ | previously here
+
+error: argument never used
+ --> $DIR/parse-error.rs:55:36
+ |
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ^^^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: explicit register arguments cannot have names
+ --> $DIR/parse-error.rs:60:18
+ |
+LL | asm!("", a = in("x0") foo);
+ | ^^^^^^^^^^^^^^^^
+
+error: named arguments cannot follow explicit register arguments
+ --> $DIR/parse-error.rs:62:35
+ |
+LL | asm!("{a}", in("x0") foo, a = const bar);
+ | ------------ ^^^^^^^^^^^^^ named argument
+ | |
+ | explicit register argument
+
+error: named arguments cannot follow explicit register arguments
+ --> $DIR/parse-error.rs:65:35
+ |
+LL | asm!("{a}", in("x0") foo, a = const bar);
+ | ------------ ^^^^^^^^^^^^^ named argument
+ | |
+ | explicit register argument
+
+error: positional arguments cannot follow named arguments or explicit register arguments
+ --> $DIR/parse-error.rs:68:35
+ |
+LL | asm!("{1}", in("x0") foo, const bar);
+ | ------------ ^^^^^^^^^ positional argument
+ | |
+ | explicit register argument
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
+ --> $DIR/parse-error.rs:71:29
+ |
+LL | asm!("", options(), "");
+ | ^^ expected one of 9 possible tokens
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
+ --> $DIR/parse-error.rs:73:33
+ |
+LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
+ | ^^^^ expected one of 9 possible tokens
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:75:14
+ |
+LL | asm!(format!("{{{}}}", 0), in(reg) foo);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:77:21
+ |
+LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: _ cannot be used for input operands
+ --> $DIR/parse-error.rs:79:28
+ |
+LL | asm!("{}", in(reg) _);
+ | ^
+
+error: _ cannot be used for input operands
+ --> $DIR/parse-error.rs:81:31
+ |
+LL | asm!("{}", inout(reg) _);
+ | ^
+
+error: _ cannot be used for input operands
+ --> $DIR/parse-error.rs:83:35
+ |
+LL | asm!("{}", inlateout(reg) _);
+ | ^
+
+error: requires at least a template string argument
+ --> $DIR/parse-error.rs:90:1
+ |
+LL | global_asm!();
+ | ^^^^^^^^^^^^^^
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:92:13
+ |
+LL | global_asm!(FOO);
+ | ^^^
+
+error: expected token: `,`
+ --> $DIR/parse-error.rs:94:18
+ |
+LL | global_asm!("{}" FOO);
+ | ^^^ expected `,`
+
+error: expected operand, options, or additional template string
+ --> $DIR/parse-error.rs:96:19
+ |
+LL | global_asm!("{}", FOO);
+ | ^^^ expected operand, options, or additional template string
+
+error: expected expression, found end of macro arguments
+ --> $DIR/parse-error.rs:98:24
+ |
+LL | global_asm!("{}", const);
+ | ^ expected expression
+
+error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
+ --> $DIR/parse-error.rs:100:30
+ |
+LL | global_asm!("{}", const(reg) FOO);
+ | ^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+ --> $DIR/parse-error.rs:102:25
+ |
+LL | global_asm!("", options(FOO));
+ | ^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:104:25
+ |
+LL | global_asm!("", options(nomem FOO));
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:106:25
+ |
+LL | global_asm!("", options(nomem, FOO));
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: arguments are not allowed after options
+ --> $DIR/parse-error.rs:108:30
+ |
+LL | global_asm!("{}", options(), const FOO);
+ | --------- ^^^^^^^^^ argument
+ | |
+ | previous options
+
+error: expected string literal
+ --> $DIR/parse-error.rs:110:29
+ |
+LL | global_asm!("", clobber_abi(FOO));
+ | ^^^ not a string literal
+
+error: expected `)`, found `FOO`
+ --> $DIR/parse-error.rs:112:33
+ |
+LL | global_asm!("", clobber_abi("C" FOO));
+ | ^^^ expected `)`
+
+error: expected `)`, found `,`
+ --> $DIR/parse-error.rs:114:32
+ |
+LL | global_asm!("", clobber_abi("C", FOO));
+ | ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+ --> $DIR/parse-error.rs:116:37
+ |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+ | ---------------- ^^^^^^^^^ argument
+ | |
+ | clobber_abi
+
+error: `clobber_abi` cannot be used with `global_asm!`
+ --> $DIR/parse-error.rs:116:19
+ |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+ | ^^^^^^^^^^^^^^^^
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:119:28
+ |
+LL | global_asm!("", options(), clobber_abi("C"));
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:121:30
+ |
+LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi specified multiple times
+ --> $DIR/parse-error.rs:123:35
+ |
+LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
+ | ---------------- ^^^^^^^^^^^^^^^^
+ | |
+ | clobber_abi previously specified here
+
+error: duplicate argument named `a`
+ --> $DIR/parse-error.rs:125:35
+ |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+ | ------------- ^^^^^^^^^^^^^ duplicate argument
+ | |
+ | previously here
+
+error: argument never used
+ --> $DIR/parse-error.rs:125:35
+ |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+ | ^^^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `""`
+ --> $DIR/parse-error.rs:128:28
+ |
+LL | global_asm!("", options(), "");
+ | ^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
+ --> $DIR/parse-error.rs:130:30
+ |
+LL | global_asm!("{}", const FOO, "{}", const FOO);
+ | ^^^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:132:13
+ |
+LL | global_asm!(format!("{{{}}}", 0), const FOO);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:134:20
+ |
+LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:37:37
+ |
+LL | let mut foo = 0;
+ | ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL | asm!("{}", options(), const foo);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:46:44
+ |
+LL | let mut foo = 0;
+ | ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL | asm!("{}", clobber_abi("C"), const foo);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:55:31
+ |
+LL | let mut foo = 0;
+ | ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:55:46
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:62:45
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{a}", in("x0") foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:65:45
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{a}", in("x0") foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:68:41
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{1}", in("x0") foo, const bar);
+ | ^^^ non-constant value
+
+error: aborting due to 66 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
--- /dev/null
+// min-llvm-version: 10.0.1
+// only-aarch64
+// build-fail
+// compile-flags: -Ccodegen-units=1
+#![feature(asm)]
+
+// Checks that inline asm errors are mapped to the correct line in the source code.
+
+fn main() {
+ unsafe {
+ asm!("invalid_instruction");
+ //~^ ERROR: unrecognized instruction mnemonic
+
+ asm!("
+ invalid_instruction
+ ");
+ //~^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(r#"
+ invalid_instruction
+ "#);
+ //~^^ ERROR: unrecognized instruction mnemonic
+
+ asm!("
+ mov x0, x0
+ invalid_instruction
+ mov x0, x0
+ ");
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(r#"
+ mov x0, x0
+ invalid_instruction
+ mov x0, x0
+ "#);
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(concat!("invalid", "_", "instruction"));
+ //~^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ "invalid_instruction",
+ );
+ //~^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ "mov x0, x0",
+ "invalid_instruction",
+ "mov x0, x0",
+ );
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ "mov x0, x0\n",
+ "invalid_instruction",
+ "mov x0, x0",
+ );
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ "mov x0, x0",
+ concat!("invalid", "_", "instruction"),
+ "mov x0, x0",
+ );
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ concat!("mov x0", ", ", "x0"),
+ concat!("invalid", "_", "instruction"),
+ concat!("mov x0", ", ", "x0"),
+ );
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ // Make sure template strings get separated
+ asm!(
+ "invalid_instruction1",
+ "invalid_instruction2",
+ );
+ //~^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2",
+ ),
+ );
+ //~^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2",
+ ),
+ concat!(
+ "invalid", "_", "instruction3", "\n",
+ "invalid", "_", "instruction4",
+ ),
+ );
+ //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^^^ ERROR: unrecognized instruction mnemonic
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2", "\n",
+ ),
+ concat!(
+ "invalid", "_", "instruction3", "\n",
+ "invalid", "_", "instruction4", "\n",
+ ),
+ );
+ //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^^ ERROR: unrecognized instruction mnemonic
+ //~^^^^^^^^ ERROR: unrecognized instruction mnemonic
+ }
+}
--- /dev/null
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:11:15
+ |
+LL | asm!("invalid_instruction");
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:15:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:13
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:20:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:13
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:26:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:13
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:33:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:13
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:38:14
+ |
+LL | asm!(concat!("invalid", "_", "instruction"));
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:42:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:48:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:55:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:62:13
+ |
+LL | concat!("invalid", "_", "instruction"),
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:69:13
+ |
+LL | concat!("invalid", "_", "instruction"),
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:76:14
+ |
+LL | "invalid_instruction1",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction1
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:77:14
+ |
+LL | "invalid_instruction2",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction2
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:83:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction1
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:83:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction2
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:92:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction1
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:92:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction2
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:96:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction3
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:96:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:1
+ |
+LL | invalid_instruction4
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:107:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | invalid_instruction1
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:107:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:1
+ |
+LL | invalid_instruction2
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:111:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:1
+ |
+LL | invalid_instruction3
+ | ^
+
+error: unrecognized instruction mnemonic
+ --> $DIR/srcloc.rs:111:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:5:1
+ |
+LL | invalid_instruction4
+ | ^
+
+error: aborting due to 23 previous errors
+
--- /dev/null
+// min-llvm-version: 10.0.1
+// only-aarch64
+// only-linux
+// run-pass
+
+#![feature(asm, thread_local)]
+
+extern "C" fn f1() -> i32 {
+ 111
+}
+
+// The compiler will generate a shim to hide the caller location parameter.
+#[track_caller]
+fn f2() -> i32 {
+ 222
+}
+
+macro_rules! call {
+ ($func:path) => {
+ unsafe {
+ let result: i32;
+ asm!("bl {}", sym $func,
+ out("w0") result,
+ out("x20") _, out("x21") _, out("x22") _,
+ out("x23") _, out("x24") _, out("x25") _,
+ out("x26") _, out("x27") _, out("x28") _,
+ );
+ result
+ }
+ }
+}
+
+macro_rules! static_addr {
+ ($s:expr) => {
+ unsafe {
+ let result: *const u32;
+ asm!(
+ // ADRP gives the address of a 4KB page from a PC-relative address
+ "adrp {out}, {sym}",
+ // We then add the remaining lower 12 bits
+ "add {out}, {out}, #:lo12:{sym}",
+ out = out(reg) result,
+ sym = sym $s);
+ result
+ }
+ }
+}
+macro_rules! static_tls_addr {
+ ($s:expr) => {
+ unsafe {
+ let result: *const u32;
+ asm!(
+ // Load the thread pointer register
+ "mrs {out}, TPIDR_EL0",
+ // Add the top 12 bits of the symbol's offset
+ "add {out}, {out}, :tprel_hi12:{sym}",
+ // And the bottom 12 bits
+ "add {out}, {out}, :tprel_lo12:{sym}",
+ out = out(reg) result,
+ sym = sym $s
+ );
+ result
+ }
+ }
+}
+
+static S1: u32 = 111;
+#[thread_local]
+static S2: u32 = 222;
+
+fn main() {
+ assert_eq!(call!(f1), 111);
+ assert_eq!(call!(f2), 222);
+ assert_eq!(static_addr!(S1), &S1 as *const u32);
+ assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+ std::thread::spawn(|| {
+ assert_eq!(static_addr!(S1), &S1 as *const u32);
+ assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+ }).join().unwrap();
+}
--- /dev/null
+// only-aarch64
+
+#![feature(asm, repr_simd, never_type)]
+
+#[repr(simd)]
+#[derive(Clone, Copy)]
+struct SimdType(f32, f32, f32, f32);
+
+#[repr(simd)]
+struct SimdNonCopy(f32, f32, f32, f32);
+
+fn main() {
+ unsafe {
+ // Inputs must be initialized
+
+ let x: u64;
+ asm!("{}", in(reg) x);
+ //~^ ERROR use of possibly-uninitialized variable: `x`
+ let mut y: u64;
+ asm!("{}", inout(reg) y);
+ //~^ ERROR use of possibly-uninitialized variable: `y`
+ let _ = y;
+
+ // Outputs require mutable places
+
+ let v: Vec<u64> = vec![0, 1, 2];
+ asm!("{}", in(reg) v[0]);
+ asm!("{}", out(reg) v[0]);
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+ asm!("{}", inout(reg) v[0]);
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+
+ // Sym operands must point to a function or static
+
+ const C: i32 = 0;
+ static S: i32 = 0;
+ asm!("{}", sym S);
+ asm!("{}", sym main);
+ asm!("{}", sym C);
+ //~^ ERROR asm `sym` operand must point to a fn or static
+ asm!("{}", sym x);
+ //~^ ERROR asm `sym` operand must point to a fn or static
+
+ // Register operands must be Copy
+
+ asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+ //~^ ERROR arguments for inline assembly must be copyable
+
+ // Register operands must be integers, floats, SIMD vectors, pointers or
+ // function pointers.
+
+ asm!("{}", in(reg) 0i64);
+ asm!("{}", in(reg) 0f64);
+ asm!("{:v}", in(vreg) SimdType(0.0, 0.0, 0.0, 0.0));
+ asm!("{}", in(reg) 0 as *const u8);
+ asm!("{}", in(reg) 0 as *mut u8);
+ asm!("{}", in(reg) main as fn());
+ asm!("{}", in(reg) |x: i32| x);
+ //~^ ERROR cannot use value of type
+ asm!("{}", in(reg) vec![0]);
+ //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly
+ asm!("{}", in(reg) (1, 2, 3));
+ //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly
+ asm!("{}", in(reg) [1, 2, 3]);
+ //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly
+
+ // Register inputs (but not outputs) allow references and function types
+
+ let mut f = main;
+ let mut r = &mut 0;
+ asm!("{}", in(reg) f);
+ asm!("{}", inout(reg) f);
+ //~^ ERROR cannot use value of type `fn() {main}` for inline assembly
+ asm!("{}", in(reg) r);
+ asm!("{}", inout(reg) r);
+ //~^ ERROR cannot use value of type `&mut i32` for inline assembly
+ let _ = (f, r);
+
+ // Type checks ignore never type
+
+ let u: ! = unreachable!();
+ asm!("{}", in(reg) u);
+ }
+}
--- /dev/null
+error: arguments for inline assembly must be copyable
+ --> $DIR/type-check-2.rs:46:31
+ |
+LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `SimdNonCopy` does not implement the Copy trait
+
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly
+ --> $DIR/type-check-2.rs:58:28
+ |
+LL | asm!("{}", in(reg) |x: i32| x);
+ | ^^^^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `Vec<i32>` for inline assembly
+ --> $DIR/type-check-2.rs:60:28
+ |
+LL | asm!("{}", in(reg) vec![0]);
+ | ^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+ = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot use value of type `(i32, i32, i32)` for inline assembly
+ --> $DIR/type-check-2.rs:62:28
+ |
+LL | asm!("{}", in(reg) (1, 2, 3));
+ | ^^^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `[i32; 3]` for inline assembly
+ --> $DIR/type-check-2.rs:64:28
+ |
+LL | asm!("{}", in(reg) [1, 2, 3]);
+ | ^^^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `fn() {main}` for inline assembly
+ --> $DIR/type-check-2.rs:72:31
+ |
+LL | asm!("{}", inout(reg) f);
+ | ^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `&mut i32` for inline assembly
+ --> $DIR/type-check-2.rs:75:31
+ |
+LL | asm!("{}", inout(reg) r);
+ | ^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: asm `sym` operand must point to a fn or static
+ --> $DIR/type-check-2.rs:39:24
+ |
+LL | asm!("{}", sym C);
+ | ^
+
+error: asm `sym` operand must point to a fn or static
+ --> $DIR/type-check-2.rs:41:24
+ |
+LL | asm!("{}", sym x);
+ | ^
+
+error[E0381]: use of possibly-uninitialized variable: `x`
+ --> $DIR/type-check-2.rs:17:28
+ |
+LL | asm!("{}", in(reg) x);
+ | ^ use of possibly-uninitialized `x`
+
+error[E0381]: use of possibly-uninitialized variable: `y`
+ --> $DIR/type-check-2.rs:20:9
+ |
+LL | asm!("{}", inout(reg) y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/type-check-2.rs:28:29
+ |
+LL | let v: Vec<u64> = vec![0, 1, 2];
+ | - help: consider changing this to be mutable: `mut v`
+LL | asm!("{}", in(reg) v[0]);
+LL | asm!("{}", out(reg) v[0]);
+ | ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/type-check-2.rs:30:31
+ |
+LL | let v: Vec<u64> = vec![0, 1, 2];
+ | - help: consider changing this to be mutable: `mut v`
+...
+LL | asm!("{}", inout(reg) v[0]);
+ | ^ cannot borrow as mutable
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0381, E0596.
+For more information about an error, try `rustc --explain E0381`.
--- /dev/null
+// only-aarch64
+// compile-flags: -C target-feature=+neon
+
+#![feature(asm, global_asm, repr_simd, stdsimd)]
+
+use std::arch::aarch64::float64x2_t;
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct Simd256bit(f64, f64,f64, f64);
+
+fn main() {
+ let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) };
+ let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0);
+
+ unsafe {
+ // Types must be listed in the register class.
+
+ // Success cases
+ asm!("{:w}", in(reg) 0u8);
+ asm!("{:w}", in(reg) 0u16);
+ asm!("{:w}", in(reg) 0u32);
+ asm!("{:w}", in(reg) 0f32);
+ asm!("{}", in(reg) 0i64);
+ asm!("{}", in(reg) 0f64);
+
+ asm!("{:b}", in(vreg) 0u8);
+ asm!("{:h}", in(vreg) 0u16);
+ asm!("{:s}", in(vreg) 0u32);
+ asm!("{:s}", in(vreg) 0f32);
+ asm!("{:d}", in(vreg) 0u64);
+ asm!("{:d}", in(vreg) 0f64);
+ asm!("{:q}", in(vreg) f64x2);
+ asm!("{:v}", in(vreg) f64x2);
+
+ // Should be the same as vreg
+ asm!("{:q}", in(vreg_low16) f64x2);
+
+ // Template modifiers of a different size to the argument are fine
+ asm!("{:w}", in(reg) 0u64);
+ asm!("{:x}", in(reg) 0u32);
+ asm!("{:b}", in(vreg) 0u64);
+ asm!("{:d}", in(vreg_low16) f64x2);
+
+
+ // Template modifier suggestions for sub-registers
+
+ asm!("{}", in(reg) 0u8);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(reg) 0u16);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(reg) 0i32);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(reg) 0f32);
+ //~^ WARN formatting may not be suitable for sub-register argument
+
+ asm!("{}", in(vreg) 0i16);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(vreg) 0f32);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(vreg) 0f64);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(vreg_low16) 0f64);
+ //~^ WARN formatting may not be suitable for sub-register argument
+
+ asm!("{0} {0}", in(reg) 0i16);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{0} {0:x}", in(reg) 0i16);
+ //~^ WARN formatting may not be suitable for sub-register argument
+
+ // Invalid registers
+
+ asm!("{}", in(reg) 0i128);
+ //~^ ERROR type `i128` cannot be used with this register class
+ asm!("{}", in(reg) f64x2);
+ //~^ ERROR type `float64x2_t` cannot be used with this register class
+ asm!("{}", in(vreg) f64x4);
+ //~^ ERROR type `Simd256bit` cannot be used with this register class
+
+ // Split inout operands must have compatible types
+
+ let mut val_i16: i16;
+ let mut val_f32: f32;
+ let mut val_u32: u32;
+ let mut val_u64: u64;
+ let mut val_ptr: *mut u8;
+ asm!("{:x}", inout(reg) 0u16 => val_i16);
+ asm!("{:x}", inout(reg) 0u32 => val_f32);
+ //~^ ERROR incompatible types for asm inout argument
+ asm!("{:x}", inout(reg) 0u32 => val_ptr);
+ //~^ ERROR incompatible types for asm inout argument
+ asm!("{:x}", inout(reg) main => val_u32);
+ //~^ ERROR incompatible types for asm inout argument
+ asm!("{:x}", inout(reg) 0u64 => val_ptr);
+ asm!("{:x}", inout(reg) main => val_u64);
+ }
+}
+
+// Constants must be... constant
+
+static S: i32 = 1;
+const fn const_foo(x: i32) -> i32 {
+ x
+}
+const fn const_bar<T>(x: T) -> T {
+ x
+}
+global_asm!("{}", const S);
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_foo(0));
+global_asm!("{}", const const_foo(S));
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_bar(0));
+global_asm!("{}", const const_bar(S));
+//~^ ERROR constants cannot refer to statics
--- /dev/null
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:48:15
+ |
+LL | asm!("{}", in(reg) 0u8);
+ | ^^ --- for this argument
+ |
+ = note: `#[warn(asm_sub_register)]` on by default
+ = help: use the `w` modifier to have the register formatted as `w0`
+ = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:50:15
+ |
+LL | asm!("{}", in(reg) 0u16);
+ | ^^ ---- for this argument
+ |
+ = help: use the `w` modifier to have the register formatted as `w0`
+ = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:52:15
+ |
+LL | asm!("{}", in(reg) 0i32);
+ | ^^ ---- for this argument
+ |
+ = help: use the `w` modifier to have the register formatted as `w0`
+ = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:54:15
+ |
+LL | asm!("{}", in(reg) 0f32);
+ | ^^ ---- for this argument
+ |
+ = help: use the `w` modifier to have the register formatted as `w0`
+ = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:57:15
+ |
+LL | asm!("{}", in(vreg) 0i16);
+ | ^^ ---- for this argument
+ |
+ = help: use the `h` modifier to have the register formatted as `h0`
+ = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:59:15
+ |
+LL | asm!("{}", in(vreg) 0f32);
+ | ^^ ---- for this argument
+ |
+ = help: use the `s` modifier to have the register formatted as `s0`
+ = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:61:15
+ |
+LL | asm!("{}", in(vreg) 0f64);
+ | ^^ ---- for this argument
+ |
+ = help: use the `d` modifier to have the register formatted as `d0`
+ = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:63:15
+ |
+LL | asm!("{}", in(vreg_low16) 0f64);
+ | ^^ ---- for this argument
+ |
+ = help: use the `d` modifier to have the register formatted as `d0`
+ = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:66:15
+ |
+LL | asm!("{0} {0}", in(reg) 0i16);
+ | ^^^ ^^^ ---- for this argument
+ |
+ = help: use the `w` modifier to have the register formatted as `w0`
+ = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:68:15
+ |
+LL | asm!("{0} {0:x}", in(reg) 0i16);
+ | ^^^ ---- for this argument
+ |
+ = help: use the `w` modifier to have the register formatted as `w0`
+ = help: or use the `x` modifier to keep the default formatting of `x0`
+
+error: type `i128` cannot be used with this register class
+ --> $DIR/type-check-3.rs:73:28
+ |
+LL | asm!("{}", in(reg) 0i128);
+ | ^^^^^
+ |
+ = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+
+error: type `float64x2_t` cannot be used with this register class
+ --> $DIR/type-check-3.rs:75:28
+ |
+LL | asm!("{}", in(reg) f64x2);
+ | ^^^^^
+ |
+ = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+
+error: type `Simd256bit` cannot be used with this register class
+ --> $DIR/type-check-3.rs:77:29
+ |
+LL | asm!("{}", in(vreg) f64x4);
+ | ^^^^^
+ |
+ = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: incompatible types for asm inout argument
+ --> $DIR/type-check-3.rs:88:33
+ |
+LL | asm!("{:x}", inout(reg) 0u32 => val_f32);
+ | ^^^^ ^^^^^^^ type `f32`
+ | |
+ | type `u32`
+ |
+ = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+ --> $DIR/type-check-3.rs:90:33
+ |
+LL | asm!("{:x}", inout(reg) 0u32 => val_ptr);
+ | ^^^^ ^^^^^^^ type `*mut u8`
+ | |
+ | type `u32`
+ |
+ = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+ --> $DIR/type-check-3.rs:92:33
+ |
+LL | asm!("{:x}", inout(reg) main => val_u32);
+ | ^^^^ ^^^^^^^ type `u32`
+ | |
+ | type `fn()`
+ |
+ = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/type-check-3.rs:108:25
+ |
+LL | global_asm!("{}", const S);
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/type-check-3.rs:111:35
+ |
+LL | global_asm!("{}", const const_foo(S));
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/type-check-3.rs:114:35
+ |
+LL | global_asm!("{}", const const_bar(S));
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to 9 previous errors; 10 warnings emitted
+
+For more information about this error, try `rustc --explain E0013`.
+++ /dev/null
-// only-x86_64
-
-#![feature(asm, global_asm)]
-
-fn main() {
- let mut foo = 0;
- unsafe {
- asm!("", options(nomem, readonly));
- //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
- asm!("", options(pure, nomem, noreturn));
- //~^ ERROR the `pure` and `noreturn` options are mutually exclusive
- //~^^ ERROR asm with the `pure` option must have at least one output
- asm!("{}", in(reg) foo, options(pure, nomem));
- //~^ ERROR asm with the `pure` option must have at least one output
- asm!("{}", out(reg) foo, options(noreturn));
- //~^ ERROR asm outputs are not allowed with the `noreturn` option
- }
-
- unsafe {
- asm!("", clobber_abi("foo"));
- //~^ ERROR invalid ABI for `clobber_abi`
- asm!("{}", out(reg) foo, clobber_abi("C"));
- //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
- asm!("", out("eax") foo, clobber_abi("C"));
- }
-}
-
-global_asm!("", options(nomem));
-//~^ ERROR expected one of
-global_asm!("", options(readonly));
-//~^ ERROR expected one of
-global_asm!("", options(noreturn));
-//~^ ERROR expected one of
-global_asm!("", options(pure));
-//~^ ERROR expected one of
-global_asm!("", options(nostack));
-//~^ ERROR expected one of
-global_asm!("", options(preserves_flags));
-//~^ ERROR expected one of
+++ /dev/null
-error: the `nomem` and `readonly` options are mutually exclusive
- --> $DIR/bad-options.rs:8:18
- |
-LL | asm!("", options(nomem, readonly));
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the `pure` and `noreturn` options are mutually exclusive
- --> $DIR/bad-options.rs:10:18
- |
-LL | asm!("", options(pure, nomem, noreturn));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: asm with the `pure` option must have at least one output
- --> $DIR/bad-options.rs:10:18
- |
-LL | asm!("", options(pure, nomem, noreturn));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: asm with the `pure` option must have at least one output
- --> $DIR/bad-options.rs:13:33
- |
-LL | asm!("{}", in(reg) foo, options(pure, nomem));
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: asm outputs are not allowed with the `noreturn` option
- --> $DIR/bad-options.rs:15:20
- |
-LL | asm!("{}", out(reg) foo, options(noreturn));
- | ^^^^^^^^^^^^
-
-error: asm with `clobber_abi` must specify explicit registers for outputs
- --> $DIR/bad-options.rs:22:20
- |
-LL | asm!("{}", out(reg) foo, clobber_abi("C"));
- | ^^^^^^^^^^^^ ---------------- clobber_abi
- | |
- | generic outputs
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/bad-options.rs:28:25
- |
-LL | global_asm!("", options(nomem));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
- --> $DIR/bad-options.rs:30:25
- |
-LL | global_asm!("", options(readonly));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
- --> $DIR/bad-options.rs:32:25
- |
-LL | global_asm!("", options(noreturn));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
- --> $DIR/bad-options.rs:34:25
- |
-LL | global_asm!("", options(pure));
- | ^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
- --> $DIR/bad-options.rs:36:25
- |
-LL | global_asm!("", options(nostack));
- | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
- --> $DIR/bad-options.rs:38:25
- |
-LL | global_asm!("", options(preserves_flags));
- | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: invalid ABI for `clobber_abi`
- --> $DIR/bad-options.rs:20:18
- |
-LL | asm!("", clobber_abi("foo"));
- | ^^^^^^^^^^^^^^^^^^
- |
- = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
-
-error: aborting due to 13 previous errors
-
+++ /dev/null
-// only-x86_64
-// compile-flags: -C target-feature=+avx2
-
-#![feature(asm)]
-
-fn main() {
- let mut foo = 0;
- let mut bar = 0;
- unsafe {
- // Bad register/register class
-
- asm!("{}", in(foo) foo);
- //~^ ERROR invalid register class `foo`: unknown register class
- asm!("", in("foo") foo);
- //~^ ERROR invalid register `foo`: unknown register
- asm!("{:z}", in(reg) foo);
- //~^ ERROR invalid asm template modifier for this register class
- asm!("{:r}", in(xmm_reg) foo);
- //~^ ERROR invalid asm template modifier for this register class
- asm!("{:a}", const 0);
- //~^ ERROR asm template modifiers are not allowed for `const` arguments
- asm!("{:a}", sym main);
- //~^ ERROR asm template modifiers are not allowed for `sym` arguments
- asm!("{}", in(zmm_reg) foo);
- //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
- asm!("", in("zmm0") foo);
- //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
- asm!("", in("ebp") foo);
- //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand
- asm!("", in("rsp") foo);
- //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
- asm!("", in("ip") foo);
- //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
- asm!("", in("k0") foo);
- //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
- asm!("", in("ah") foo);
- //~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
-
- asm!("", in("st(2)") foo);
- //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
- asm!("", in("mm0") foo);
- //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
- asm!("", out("st(2)") _);
- asm!("", out("mm0") _);
- asm!("{}", in(x87_reg) foo);
- //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
- asm!("{}", in(mmx_reg) foo);
- //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
- asm!("{}", out(x87_reg) _);
- //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
- asm!("{}", out(mmx_reg) _);
- //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
-
- // Explicit register conflicts
- // (except in/lateout which don't conflict)
-
- asm!("", in("eax") foo, in("al") bar);
- //~^ ERROR register `al` conflicts with register `ax`
- asm!("", in("rax") foo, out("rax") bar);
- //~^ ERROR register `ax` conflicts with register `ax`
- asm!("", in("al") foo, lateout("al") bar);
- asm!("", in("xmm0") foo, in("ymm0") bar);
- //~^ ERROR register `ymm0` conflicts with register `xmm0`
- asm!("", in("xmm0") foo, out("ymm0") bar);
- //~^ ERROR register `ymm0` conflicts with register `xmm0`
- asm!("", in("xmm0") foo, lateout("ymm0") bar);
- }
-}
+++ /dev/null
-error: invalid register class `foo`: unknown register class
- --> $DIR/bad-reg.rs:12:20
- |
-LL | asm!("{}", in(foo) foo);
- | ^^^^^^^^^^^
-
-error: invalid register `foo`: unknown register
- --> $DIR/bad-reg.rs:14:18
- |
-LL | asm!("", in("foo") foo);
- | ^^^^^^^^^^^^^
-
-error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:16:15
- |
-LL | asm!("{:z}", in(reg) foo);
- | ^^^^ ----------- argument
- | |
- | template modifier
- |
- = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r`
-
-error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:18:15
- |
-LL | asm!("{:r}", in(xmm_reg) foo);
- | ^^^^ --------------- argument
- | |
- | template modifier
- |
- = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z`
-
-error: asm template modifiers are not allowed for `const` arguments
- --> $DIR/bad-reg.rs:20:15
- |
-LL | asm!("{:a}", const 0);
- | ^^^^ ------- argument
- | |
- | template modifier
-
-error: asm template modifiers are not allowed for `sym` arguments
- --> $DIR/bad-reg.rs:22:15
- |
-LL | asm!("{:a}", sym main);
- | ^^^^ -------- argument
- | |
- | template modifier
-
-error: register class `zmm_reg` requires the `avx512f` target feature
- --> $DIR/bad-reg.rs:24:20
- |
-LL | asm!("{}", in(zmm_reg) foo);
- | ^^^^^^^^^^^^^^^
-
-error: register class `zmm_reg` requires the `avx512f` target feature
- --> $DIR/bad-reg.rs:26:18
- |
-LL | asm!("", in("zmm0") foo);
- | ^^^^^^^^^^^^^^
-
-error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:28:18
- |
-LL | asm!("", in("ebp") foo);
- | ^^^^^^^^^^^^^
-
-error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:30:18
- |
-LL | asm!("", in("rsp") foo);
- | ^^^^^^^^^^^^^
-
-error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:32:18
- |
-LL | asm!("", in("ip") foo);
- | ^^^^^^^^^^^^
-
-error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:34:18
- |
-LL | asm!("", in("k0") foo);
- | ^^^^^^^^^^^^
-
-error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
- --> $DIR/bad-reg.rs:36:18
- |
-LL | asm!("", in("ah") foo);
- | ^^^^^^^^^^^^
-
-error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:39:18
- |
-LL | asm!("", in("st(2)") foo);
- | ^^^^^^^^^^^^^^^
-
-error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:41:18
- |
-LL | asm!("", in("mm0") foo);
- | ^^^^^^^^^^^^^
-
-error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:45:20
- |
-LL | asm!("{}", in(x87_reg) foo);
- | ^^^^^^^^^^^^^^^
-
-error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:47:20
- |
-LL | asm!("{}", in(mmx_reg) foo);
- | ^^^^^^^^^^^^^^^
-
-error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:49:20
- |
-LL | asm!("{}", out(x87_reg) _);
- | ^^^^^^^^^^^^^^
-
-error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:51:20
- |
-LL | asm!("{}", out(mmx_reg) _);
- | ^^^^^^^^^^^^^^
-
-error: register `al` conflicts with register `ax`
- --> $DIR/bad-reg.rs:57:33
- |
-LL | asm!("", in("eax") foo, in("al") bar);
- | ------------- ^^^^^^^^^^^^ register `al`
- | |
- | register `ax`
-
-error: register `ax` conflicts with register `ax`
- --> $DIR/bad-reg.rs:59:33
- |
-LL | asm!("", in("rax") foo, out("rax") bar);
- | ------------- ^^^^^^^^^^^^^^ register `ax`
- | |
- | register `ax`
- |
-help: use `lateout` instead of `out` to avoid conflict
- --> $DIR/bad-reg.rs:59:18
- |
-LL | asm!("", in("rax") foo, out("rax") bar);
- | ^^^^^^^^^^^^^
-
-error: register `ymm0` conflicts with register `xmm0`
- --> $DIR/bad-reg.rs:62:34
- |
-LL | asm!("", in("xmm0") foo, in("ymm0") bar);
- | -------------- ^^^^^^^^^^^^^^ register `ymm0`
- | |
- | register `xmm0`
-
-error: register `ymm0` conflicts with register `xmm0`
- --> $DIR/bad-reg.rs:64:34
- |
-LL | asm!("", in("xmm0") foo, out("ymm0") bar);
- | -------------- ^^^^^^^^^^^^^^^ register `ymm0`
- | |
- | register `xmm0`
- |
-help: use `lateout` instead of `out` to avoid conflict
- --> $DIR/bad-reg.rs:64:18
- |
-LL | asm!("", in("xmm0") foo, out("ymm0") bar);
- | ^^^^^^^^^^^^^^
-
-error: aborting due to 23 previous errors
-
--- /dev/null
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:31:15
+ |
+LL | asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:33:15
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:33:21
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:36:15
+ |
+LL | asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:38:15
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^ --------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:41:15
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:41:21
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:48:15
+ |
+LL | asm!("{}", in("x0") foo);
+ | ^^ ------------ explicit register argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+ --> $DIR/bad-template.rs:48:20
+ |
+LL | asm!("{}", in("x0") foo);
+ | ^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:50:17
+ |
+LL | asm!("{:foo}", in(reg) foo);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:52:18
+ |
+LL | asm!("", in(reg) 0, in(reg) 1);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:58:14
+ |
+LL | global_asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:60:14
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:60:20
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:63:14
+ |
+LL | global_asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:65:14
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^ ------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:68:14
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:68:20
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:71:16
+ |
+LL | global_asm!("{:foo}", const FOO);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:73:17
+ |
+LL | global_asm!("", const FOO, const FOO);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
--- /dev/null
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:31:15
+ |
+LL | asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:33:15
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:33:21
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:36:15
+ |
+LL | asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:38:15
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^ --------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:41:15
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:41:21
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:48:15
+ |
+LL | asm!("{}", in("x0") foo);
+ | ^^ ------------ explicit register argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+ --> $DIR/bad-template.rs:48:20
+ |
+LL | asm!("{}", in("x0") foo);
+ | ^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:50:17
+ |
+LL | asm!("{:foo}", in(reg) foo);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:52:18
+ |
+LL | asm!("", in(reg) 0, in(reg) 1);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:58:14
+ |
+LL | global_asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:60:14
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:60:20
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:63:14
+ |
+LL | global_asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:65:14
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^ ------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:68:14
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:68:20
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:71:16
+ |
+LL | global_asm!("{:foo}", const FOO);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:73:17
+ |
+LL | global_asm!("", const FOO, const FOO);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
+++ /dev/null
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:10:15
- |
-LL | asm!("{}");
- | ^^ from here
- |
- = note: no arguments were given
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:12:15
- |
-LL | asm!("{1}", in(reg) foo);
- | ^^^ from here
- |
- = note: there is 1 argument
-
-error: argument never used
- --> $DIR/bad-template.rs:12:21
- |
-LL | asm!("{1}", in(reg) foo);
- | ^^^^^^^^^^^ argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
- --> $DIR/bad-template.rs:15:15
- |
-LL | asm!("{a}");
- | ^^^
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:17:15
- |
-LL | asm!("{}", a = in(reg) foo);
- | ^^ --------------- named argument
- | |
- | from here
- |
- = note: no positional arguments were given
-note: named arguments cannot be referenced by position
- --> $DIR/bad-template.rs:17:20
- |
-LL | asm!("{}", a = in(reg) foo);
- | ^^^^^^^^^^^^^^^
-
-error: named argument never used
- --> $DIR/bad-template.rs:17:20
- |
-LL | asm!("{}", a = in(reg) foo);
- | ^^^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:20:15
- |
-LL | asm!("{1}", a = in(reg) foo);
- | ^^^ from here
- |
- = note: no positional arguments were given
-
-error: named argument never used
- --> $DIR/bad-template.rs:20:21
- |
-LL | asm!("{1}", a = in(reg) foo);
- | ^^^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:23:15
- |
-LL | asm!("{}", in("eax") foo);
- | ^^ ------------- explicit register argument
- | |
- | from here
- |
- = note: no positional arguments were given
-note: explicit register arguments cannot be used in the asm template
- --> $DIR/bad-template.rs:23:20
- |
-LL | asm!("{}", in("eax") foo);
- | ^^^^^^^^^^^^^
-
-error: asm template modifier must be a single character
- --> $DIR/bad-template.rs:25:17
- |
-LL | asm!("{:foo}", in(reg) foo);
- | ^^^
-
-error: multiple unused asm arguments
- --> $DIR/bad-template.rs:27:18
- |
-LL | asm!("", in(reg) 0, in(reg) 1);
- | ^^^^^^^^^ ^^^^^^^^^ argument never used
- | |
- | argument never used
- |
- = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:33:14
- |
-LL | global_asm!("{}");
- | ^^ from here
- |
- = note: no arguments were given
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:35:14
- |
-LL | global_asm!("{1}", const FOO);
- | ^^^ from here
- |
- = note: there is 1 argument
-
-error: argument never used
- --> $DIR/bad-template.rs:35:20
- |
-LL | global_asm!("{1}", const FOO);
- | ^^^^^^^^^ argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
- --> $DIR/bad-template.rs:38:14
- |
-LL | global_asm!("{a}");
- | ^^^
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:40:14
- |
-LL | global_asm!("{}", a = const FOO);
- | ^^ ------------- named argument
- | |
- | from here
- |
- = note: no positional arguments were given
-note: named arguments cannot be referenced by position
- --> $DIR/bad-template.rs:40:19
- |
-LL | global_asm!("{}", a = const FOO);
- | ^^^^^^^^^^^^^
-
-error: named argument never used
- --> $DIR/bad-template.rs:40:19
- |
-LL | global_asm!("{}", a = const FOO);
- | ^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:43:14
- |
-LL | global_asm!("{1}", a = const FOO);
- | ^^^ from here
- |
- = note: no positional arguments were given
-
-error: named argument never used
- --> $DIR/bad-template.rs:43:20
- |
-LL | global_asm!("{1}", a = const FOO);
- | ^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: asm template modifier must be a single character
- --> $DIR/bad-template.rs:46:16
- |
-LL | global_asm!("{:foo}", const FOO);
- | ^^^
-
-error: multiple unused asm arguments
- --> $DIR/bad-template.rs:48:17
- |
-LL | global_asm!("", const FOO, const FOO);
- | ^^^^^^^^^ ^^^^^^^^^ argument never used
- | |
- | argument never used
- |
- = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: aborting due to 21 previous errors
-
-// only-x86_64
-// revisions: mirunsafeck thirunsafeck
-// [thirunsafeck]compile-flags: -Z thir-unsafeck
+// revisions: x86_64_mirunsafeck aarch64_mirunsafeck x86_64_thirunsafeck aarch64_thirunsafeck
-#![feature(asm, global_asm)]
+// [x86_64_thirunsafeck] compile-flags: -Z thir-unsafeck --target x86_64-unknown-linux-gnu
+// [aarch64_thirunsafeck] compile-flags: -Z thir-unsafeck --target aarch64-unknown-linux-gnu
+// [x86_64_mirunsafeck] compile-flags: --target x86_64-unknown-linux-gnu
+// [aarch64_mirunsafeck] compile-flags: --target aarch64-unknown-linux-gnu
+
+// [x86_64_thirunsafeck] needs-llvm-components: x86
+// [x86_64_mirunsafeck] needs-llvm-components: x86
+// [aarch64_thirunsafeck] needs-llvm-components: aarch64
+// [aarch64_mirunsafeck] needs-llvm-components: aarch64
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! global_asm {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
fn main() {
let mut foo = 0;
asm!("{1}", a = in(reg) foo);
//~^ ERROR invalid reference to argument at index 1
//~^^ ERROR named argument never used
+ #[cfg(any(x86_64_thirunsafeck, x86_64_mirunsafeck))]
asm!("{}", in("eax") foo);
- //~^ ERROR invalid reference to argument at index 0
+ //[x86_64_thirunsafeck,x86_64_mirunsafeck]~^ ERROR invalid reference to argument at index 0
+ #[cfg(any(aarch64_thirunsafeck, aarch64_mirunsafeck))]
+ asm!("{}", in("x0") foo);
+ //[aarch64_thirunsafeck,aarch64_mirunsafeck]~^ ERROR invalid reference to argument at index 0
asm!("{:foo}", in(reg) foo);
//~^ ERROR asm template modifier must be a single character
asm!("", in(reg) 0, in(reg) 1);
+++ /dev/null
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:10:15
- |
-LL | asm!("{}");
- | ^^ from here
- |
- = note: no arguments were given
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:12:15
- |
-LL | asm!("{1}", in(reg) foo);
- | ^^^ from here
- |
- = note: there is 1 argument
-
-error: argument never used
- --> $DIR/bad-template.rs:12:21
- |
-LL | asm!("{1}", in(reg) foo);
- | ^^^^^^^^^^^ argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
- --> $DIR/bad-template.rs:15:15
- |
-LL | asm!("{a}");
- | ^^^
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:17:15
- |
-LL | asm!("{}", a = in(reg) foo);
- | ^^ --------------- named argument
- | |
- | from here
- |
- = note: no positional arguments were given
-note: named arguments cannot be referenced by position
- --> $DIR/bad-template.rs:17:20
- |
-LL | asm!("{}", a = in(reg) foo);
- | ^^^^^^^^^^^^^^^
-
-error: named argument never used
- --> $DIR/bad-template.rs:17:20
- |
-LL | asm!("{}", a = in(reg) foo);
- | ^^^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:20:15
- |
-LL | asm!("{1}", a = in(reg) foo);
- | ^^^ from here
- |
- = note: no positional arguments were given
-
-error: named argument never used
- --> $DIR/bad-template.rs:20:21
- |
-LL | asm!("{1}", a = in(reg) foo);
- | ^^^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:23:15
- |
-LL | asm!("{}", in("eax") foo);
- | ^^ ------------- explicit register argument
- | |
- | from here
- |
- = note: no positional arguments were given
-note: explicit register arguments cannot be used in the asm template
- --> $DIR/bad-template.rs:23:20
- |
-LL | asm!("{}", in("eax") foo);
- | ^^^^^^^^^^^^^
-
-error: asm template modifier must be a single character
- --> $DIR/bad-template.rs:25:17
- |
-LL | asm!("{:foo}", in(reg) foo);
- | ^^^
-
-error: multiple unused asm arguments
- --> $DIR/bad-template.rs:27:18
- |
-LL | asm!("", in(reg) 0, in(reg) 1);
- | ^^^^^^^^^ ^^^^^^^^^ argument never used
- | |
- | argument never used
- |
- = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:33:14
- |
-LL | global_asm!("{}");
- | ^^ from here
- |
- = note: no arguments were given
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:35:14
- |
-LL | global_asm!("{1}", const FOO);
- | ^^^ from here
- |
- = note: there is 1 argument
-
-error: argument never used
- --> $DIR/bad-template.rs:35:20
- |
-LL | global_asm!("{1}", const FOO);
- | ^^^^^^^^^ argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
- --> $DIR/bad-template.rs:38:14
- |
-LL | global_asm!("{a}");
- | ^^^
-
-error: invalid reference to argument at index 0
- --> $DIR/bad-template.rs:40:14
- |
-LL | global_asm!("{}", a = const FOO);
- | ^^ ------------- named argument
- | |
- | from here
- |
- = note: no positional arguments were given
-note: named arguments cannot be referenced by position
- --> $DIR/bad-template.rs:40:19
- |
-LL | global_asm!("{}", a = const FOO);
- | ^^^^^^^^^^^^^
-
-error: named argument never used
- --> $DIR/bad-template.rs:40:19
- |
-LL | global_asm!("{}", a = const FOO);
- | ^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
- --> $DIR/bad-template.rs:43:14
- |
-LL | global_asm!("{1}", a = const FOO);
- | ^^^ from here
- |
- = note: no positional arguments were given
-
-error: named argument never used
- --> $DIR/bad-template.rs:43:20
- |
-LL | global_asm!("{1}", a = const FOO);
- | ^^^^^^^^^^^^^ named argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: asm template modifier must be a single character
- --> $DIR/bad-template.rs:46:16
- |
-LL | global_asm!("{:foo}", const FOO);
- | ^^^
-
-error: multiple unused asm arguments
- --> $DIR/bad-template.rs:48:17
- |
-LL | global_asm!("", const FOO, const FOO);
- | ^^^^^^^^^ ^^^^^^^^^ argument never used
- | |
- | argument never used
- |
- = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: aborting due to 21 previous errors
-
--- /dev/null
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:31:15
+ |
+LL | asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:33:15
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:33:21
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:36:15
+ |
+LL | asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:38:15
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^ --------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:41:15
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:41:21
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:45:15
+ |
+LL | asm!("{}", in("eax") foo);
+ | ^^ ------------- explicit register argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+ --> $DIR/bad-template.rs:45:20
+ |
+LL | asm!("{}", in("eax") foo);
+ | ^^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:50:17
+ |
+LL | asm!("{:foo}", in(reg) foo);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:52:18
+ |
+LL | asm!("", in(reg) 0, in(reg) 1);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:58:14
+ |
+LL | global_asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:60:14
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:60:20
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:63:14
+ |
+LL | global_asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:65:14
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^ ------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:68:14
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:68:20
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:71:16
+ |
+LL | global_asm!("{:foo}", const FOO);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:73:17
+ |
+LL | global_asm!("", const FOO, const FOO);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
--- /dev/null
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:31:15
+ |
+LL | asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:33:15
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:33:21
+ |
+LL | asm!("{1}", in(reg) foo);
+ | ^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:36:15
+ |
+LL | asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:38:15
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^ --------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:38:20
+ |
+LL | asm!("{}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:41:15
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:41:21
+ |
+LL | asm!("{1}", a = in(reg) foo);
+ | ^^^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:45:15
+ |
+LL | asm!("{}", in("eax") foo);
+ | ^^ ------------- explicit register argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+ --> $DIR/bad-template.rs:45:20
+ |
+LL | asm!("{}", in("eax") foo);
+ | ^^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:50:17
+ |
+LL | asm!("{:foo}", in(reg) foo);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:52:18
+ |
+LL | asm!("", in(reg) 0, in(reg) 1);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:58:14
+ |
+LL | global_asm!("{}");
+ | ^^ from here
+ |
+ = note: no arguments were given
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:60:14
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^ from here
+ |
+ = note: there is 1 argument
+
+error: argument never used
+ --> $DIR/bad-template.rs:60:20
+ |
+LL | global_asm!("{1}", const FOO);
+ | ^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+ --> $DIR/bad-template.rs:63:14
+ |
+LL | global_asm!("{a}");
+ | ^^^
+
+error: invalid reference to argument at index 0
+ --> $DIR/bad-template.rs:65:14
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^ ------------- named argument
+ | |
+ | from here
+ |
+ = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^
+
+error: named argument never used
+ --> $DIR/bad-template.rs:65:19
+ |
+LL | global_asm!("{}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+ --> $DIR/bad-template.rs:68:14
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^ from here
+ |
+ = note: no positional arguments were given
+
+error: named argument never used
+ --> $DIR/bad-template.rs:68:20
+ |
+LL | global_asm!("{1}", a = const FOO);
+ | ^^^^^^^^^^^^^ named argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+ --> $DIR/bad-template.rs:71:16
+ |
+LL | global_asm!("{:foo}", const FOO);
+ | ^^^
+
+error: multiple unused asm arguments
+ --> $DIR/bad-template.rs:73:17
+ |
+LL | global_asm!("", const FOO, const FOO);
+ | ^^^^^^^^^ ^^^^^^^^^ argument never used
+ | |
+ | argument never used
+ |
+ = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
+++ /dev/null
-// min-llvm-version: 10.0.1
-// only-x86_64
-// run-pass
-// revisions: mirunsafeck thirunsafeck
-// [thirunsafeck]compile-flags: -Z thir-unsafeck
-
-#![feature(asm, global_asm)]
-
-fn const_generic<const X: usize>() -> usize {
- unsafe {
- let a: usize;
- asm!("mov {}, {}", out(reg) a, const X);
- a
- }
-}
-
-const fn constfn(x: usize) -> usize {
- x
-}
-
-fn main() {
- unsafe {
- let a: usize;
- asm!("mov {}, {}", out(reg) a, const 5);
- assert_eq!(a, 5);
-
- let b: usize;
- asm!("mov {}, {}", out(reg) b, const constfn(5));
- assert_eq!(b, 5);
-
- let c: usize;
- asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
- assert_eq!(c, 10);
- }
-
- let d = const_generic::<5>();
- assert_eq!(d, 5);
-}
-
-global_asm!("mov eax, {}", const 5);
-global_asm!("mov eax, {}", const constfn(5));
-global_asm!("mov eax, {}", const constfn(5) + constfn(5));
+++ /dev/null
-// only-x86_64
-// run-rustfix
-
-#![feature(asm, global_asm)]
-
-fn main() {
- unsafe {
- asm!("", options(nomem, ));
- //~^ ERROR the `nomem` option was already provided
- asm!("", options(att_syntax, ));
- //~^ ERROR the `att_syntax` option was already provided
- asm!("", options(nostack, att_syntax), options());
- //~^ ERROR the `nostack` option was already provided
- asm!("", options(nostack, ), options(), options());
- //~^ ERROR the `nostack` option was already provided
- //~| ERROR the `nostack` option was already provided
- //~| ERROR the `nostack` option was already provided
- asm!(
- "",
- options(nomem, noreturn),
- options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
- options( nostack), //~ ERROR the `nomem` option was already provided
- options(), //~ ERROR the `noreturn` option was already provided
- );
- }
-}
-
-global_asm!("", options(att_syntax, ));
-//~^ ERROR the `att_syntax` option was already provided
+++ /dev/null
-// only-x86_64
-// run-rustfix
-
-#![feature(asm, global_asm)]
-
-fn main() {
- unsafe {
- asm!("", options(nomem, nomem));
- //~^ ERROR the `nomem` option was already provided
- asm!("", options(att_syntax, att_syntax));
- //~^ ERROR the `att_syntax` option was already provided
- asm!("", options(nostack, att_syntax), options(nostack));
- //~^ ERROR the `nostack` option was already provided
- asm!("", options(nostack, nostack), options(nostack), options(nostack));
- //~^ ERROR the `nostack` option was already provided
- //~| ERROR the `nostack` option was already provided
- //~| ERROR the `nostack` option was already provided
- asm!(
- "",
- options(nomem, noreturn),
- options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
- options(nomem, nostack), //~ ERROR the `nomem` option was already provided
- options(noreturn), //~ ERROR the `noreturn` option was already provided
- );
- }
-}
-
-global_asm!("", options(att_syntax, att_syntax));
-//~^ ERROR the `att_syntax` option was already provided
+++ /dev/null
-error: the `nomem` option was already provided
- --> $DIR/duplicate-options.rs:8:33
- |
-LL | asm!("", options(nomem, nomem));
- | ^^^^^ this option was already provided
-
-error: the `att_syntax` option was already provided
- --> $DIR/duplicate-options.rs:10:38
- |
-LL | asm!("", options(att_syntax, att_syntax));
- | ^^^^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
- --> $DIR/duplicate-options.rs:12:56
- |
-LL | asm!("", options(nostack, att_syntax), options(nostack));
- | ^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
- --> $DIR/duplicate-options.rs:14:35
- |
-LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
- | ^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
- --> $DIR/duplicate-options.rs:14:53
- |
-LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
- | ^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
- --> $DIR/duplicate-options.rs:14:71
- |
-LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
- | ^^^^^^^ this option was already provided
-
-error: the `noreturn` option was already provided
- --> $DIR/duplicate-options.rs:21:33
- |
-LL | options(att_syntax, noreturn),
- | ^^^^^^^^ this option was already provided
-
-error: the `nomem` option was already provided
- --> $DIR/duplicate-options.rs:22:21
- |
-LL | options(nomem, nostack),
- | ^^^^^ this option was already provided
-
-error: the `noreturn` option was already provided
- --> $DIR/duplicate-options.rs:23:21
- |
-LL | options(noreturn),
- | ^^^^^^^^ this option was already provided
-
-error: the `att_syntax` option was already provided
- --> $DIR/duplicate-options.rs:28:37
- |
-LL | global_asm!("", options(att_syntax, att_syntax));
- | ^^^^^^^^^^ this option was already provided
-
-error: aborting due to 10 previous errors
-
+++ /dev/null
-// only-x86_64
-
-#![feature(asm)]
-
-macro_rules! m {
- ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
- $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
- $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
- unsafe {
- asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
- //~^ ERROR asm outputs are not allowed with the `noreturn` option
- const x, sym x,
- $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
- //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
- //~| ERROR the `pure` and `noreturn` options are mutually exclusive
- }
- };
-}
-
-fn main() {
- m!(in out lateout inout inlateout const sym
- pure nomem readonly preserves_flags
- noreturn nostack att_syntax options);
-}
+++ /dev/null
-error: the `nomem` and `readonly` options are mutually exclusive
- --> $DIR/interpolated-idents.rs:13:13
- |
-LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | / m!(in out lateout inout inlateout const sym
-LL | | pure nomem readonly preserves_flags
-LL | | noreturn nostack att_syntax options);
- | |____________________________________________- in this macro invocation
- |
- = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: the `pure` and `noreturn` options are mutually exclusive
- --> $DIR/interpolated-idents.rs:13:13
- |
-LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | / m!(in out lateout inout inlateout const sym
-LL | | pure nomem readonly preserves_flags
-LL | | noreturn nostack att_syntax options);
- | |____________________________________________- in this macro invocation
- |
- = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm outputs are not allowed with the `noreturn` option
- --> $DIR/interpolated-idents.rs:10:32
- |
-LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
- | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
-...
-LL | m!(in out lateout inout inlateout const sym
- | _____-
- | |_____|
- | |_____|
- | |_____|
- | |
-LL | | pure nomem readonly preserves_flags
-LL | | noreturn nostack att_syntax options);
- | | -
- | |____________________________________________|
- | |____________________________________________in this macro invocation
- | |____________________________________________in this macro invocation
- | |____________________________________________in this macro invocation
- | in this macro invocation
- |
- = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
// compile-flags: -Zsave-analysis
-// only-x86_64
+// needs-asm-support
// Also test for #72960
#![feature(asm)]
+++ /dev/null
-// only-x86_64
-// Make sure rustc doesn't ICE on asm! for a foreign architecture.
-
-#![feature(asm)]
-#![crate_type = "rlib"]
-
-pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
- let c;
- asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
- || {};
- b
- });
- //~^^^^ invalid register class
- //~^^^^^ invalid register class
- //~^^^^^^ invalid register
- c
-}
-
-pub unsafe fn x86(a: f64, b: f64) -> f64 {
- let c;
- asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b);
- c
-}
+++ /dev/null
-error: invalid register class `vreg`: unknown register class
- --> $DIR/issue-82869.rs:9:32
- |
-LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
- | ^^^^^^^^^^^
-
-error: invalid register class `vreg`: unknown register class
- --> $DIR/issue-82869.rs:9:45
- |
-LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
- | ^^^^^^^^^^
-
-error: invalid register `d0`: unknown register
- --> $DIR/issue-82869.rs:9:57
- |
-LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
- | _________________________________________________________^
-LL | | || {};
-LL | | b
-LL | | });
- | |_____^
-
-error: aborting due to 3 previous errors
-
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
// Make sure rustc doesn't ICE on asm! when output type is !.
#![feature(asm)]
error: cannot use value of type `!` for inline assembly
- --> $DIR/issue-87802.rs:9:36
+ --> $DIR/issue-87802.rs:12:36
|
LL | asm!("/* {0} */", out(reg) x);
| ^
// check-pass
-// only-x86_64
+// needs-asm-support
#![feature(asm)]
#![feature(naked_functions)]
#![crate_type = "lib"]
--- /dev/null
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:15:32
+ |
+LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: the lint level is defined here
+ --> $DIR/naked-functions-unused.rs:4:9
+ |
+LL | #![deny(unused)]
+ | ^^^^^^
+ = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:15:42
+ |
+LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:24:38
+ |
+LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:24:48
+ |
+LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:30:41
+ |
+LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:30:51
+ |
+LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:38:40
+ |
+LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:38:50
+ |
+LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:44:43
+ |
+LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:44:53
+ |
+LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: aborting due to 10 previous errors
+
-// only-x86_64
+// revisions: x86_64 aarch64
+//[x86_64] only-x86_64
+//[aarch64] only-aarch64
#![deny(unused)]
#![feature(asm)]
#![feature(naked_functions)]
#![crate_type = "lib"]
pub trait Trait {
- extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize;
- extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize;
+ extern "C" fn trait_associated(a: usize, b: usize) -> usize;
+ extern "C" fn trait_method(&self, a: usize, b: usize) -> usize;
}
pub mod normal {
- pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+ pub extern "C" fn function(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); }
pub struct Normal;
impl Normal {
- pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+ pub extern "C" fn associated(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); }
}
- pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+ pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); }
}
impl super::Trait for Normal {
- extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+ extern "C" fn trait_associated(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); }
}
- extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+ extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); }
pub mod naked {
#[naked]
- pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+ pub extern "C" fn function(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); }
}
impl Naked {
#[naked]
- pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+ pub extern "C" fn associated(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); }
}
#[naked]
- pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+ pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); }
}
}
impl super::Trait for Naked {
#[naked]
- extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+ extern "C" fn trait_associated(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); }
}
#[naked]
- extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+ extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); }
}
}
+++ /dev/null
-error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:13:37
- |
-LL | pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_a`
- |
-note: the lint level is defined here
- --> $DIR/naked-functions-unused.rs:2:9
- |
-LL | #![deny(unused)]
- | ^^^^^^
- = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
-
-error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:13:47
- |
-LL | pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:22:43
- |
-LL | pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:22:53
- |
-LL | pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:28:46
- |
-LL | pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:28:56
- |
-LL | pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:36:45
- |
-LL | extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:36:55
- |
-LL | extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:42:48
- |
-LL | extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:42:58
- |
-LL | extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: aborting due to 10 previous errors
-
--- /dev/null
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:15:32
+ |
+LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: the lint level is defined here
+ --> $DIR/naked-functions-unused.rs:4:9
+ |
+LL | #![deny(unused)]
+ | ^^^^^^
+ = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:15:42
+ |
+LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:24:38
+ |
+LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:24:48
+ |
+LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:30:41
+ |
+LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:30:51
+ |
+LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:38:40
+ |
+LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:38:50
+ |
+LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/naked-functions-unused.rs:44:43
+ |
+LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/naked-functions-unused.rs:44:53
+ |
+LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: aborting due to 10 previous errors
+
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
+
#![feature(asm)]
#![feature(llvm_asm)]
#![feature(naked_functions)]
error: asm with the `pure` option must have at least one output
- --> $DIR/naked-functions.rs:127:14
+ --> $DIR/naked-functions.rs:131:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:14:5
+ --> $DIR/naked-functions.rs:18:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:16:5
+ --> $DIR/naked-functions.rs:20:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:18:6
+ --> $DIR/naked-functions.rs:22:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:20:5
+ --> $DIR/naked-functions.rs:24:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:30:5
+ --> $DIR/naked-functions.rs:34:5
|
LL | a + 1
| ^
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:27:1
+ --> $DIR/naked-functions.rs:31:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:36:31
+ --> $DIR/naked-functions.rs:40:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
= help: follow the calling convention in asm block to use parameters
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:36:23
+ --> $DIR/naked-functions.rs:40:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:43:1
+ --> $DIR/naked-functions.rs:47:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:63:10
+ --> $DIR/naked-functions.rs:67:10
|
LL | in(reg) a,
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:60:5
+ --> $DIR/naked-functions.rs:64:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:50:1
+ --> $DIR/naked-functions.rs:54:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:76:1
+ --> $DIR/naked-functions.rs:80:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:85:5
+ --> $DIR/naked-functions.rs:89:5
|
LL | asm!("");
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:88:5
+ --> $DIR/naked-functions.rs:92:5
|
LL | asm!("");
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:91:5
+ --> $DIR/naked-functions.rs:95:5
|
LL | asm!("");
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:82:1
+ --> $DIR/naked-functions.rs:86:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:102:11
+ --> $DIR/naked-functions.rs:106:11
|
LL | *&y
| ^
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:99:5
+ --> $DIR/naked-functions.rs:103:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: the LLVM-style inline assembly is unsupported in naked functions
- --> $DIR/naked-functions.rs:112:5
+ --> $DIR/naked-functions.rs:116:5
|
LL | llvm_asm!("");
| ^^^^^^^^^^^^^^
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:109:1
+ --> $DIR/naked-functions.rs:113:1
|
LL | / unsafe extern "C" fn llvm() -> ! {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
- --> $DIR/naked-functions.rs:120:5
+ --> $DIR/naked-functions.rs:124:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
- --> $DIR/naked-functions.rs:127:5
+ --> $DIR/naked-functions.rs:131:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:127:5
+ --> $DIR/naked-functions.rs:131:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:136:15
+ --> $DIR/naked-functions.rs:140:15
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
= note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:142:29
+ --> $DIR/naked-functions.rs:146:29
|
LL | pub unsafe extern "Rust" fn rust_abi() {
| ^^^^^^^^
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:176:1
+ --> $DIR/naked-functions.rs:180:1
|
LL | #[inline]
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:184:1
+ --> $DIR/naked-functions.rs:188:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:192:1
+ --> $DIR/naked-functions.rs:196:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:200:1
+ --> $DIR/naked-functions.rs:204:1
|
LL | #[inline]
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:203:1
+ --> $DIR/naked-functions.rs:207:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:206:1
+ --> $DIR/naked-functions.rs:210:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
// Tests that the use of named labels in the `asm!` macro are linted against
// except for in `#[naked]` fns.
asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); //~ ERROR avoid using named labels
// Non-label colons - should pass
- // (most of these are stolen from other places)
- asm!("{:l}", in(reg) 0i64);
- asm!("{:e}", in(reg) 0f32);
asm!("mov rax, qword ptr fs:[0]");
// Comments
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:19:15
+ --> $DIR/named-asm-labels.rs:22:15
|
LL | asm!("bar: nop");
| ^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:22:15
+ --> $DIR/named-asm-labels.rs:25:15
|
LL | asm!("abcd:");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:25:15
+ --> $DIR/named-asm-labels.rs:28:15
|
LL | asm!("foo: bar1: nop");
| ^^^ ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:29:15
+ --> $DIR/named-asm-labels.rs:32:15
|
LL | asm!("foo1: nop", "nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:30:15
+ --> $DIR/named-asm-labels.rs:33:15
|
LL | asm!("foo2: foo3: nop", "nop");
| ^^^^ ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:32:22
+ --> $DIR/named-asm-labels.rs:35:22
|
LL | asm!("nop", "foo4: nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:33:15
+ --> $DIR/named-asm-labels.rs:36:15
|
LL | asm!("foo5: nop", "foo6: nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:33:28
+ --> $DIR/named-asm-labels.rs:36:28
|
LL | asm!("foo5: nop", "foo6: nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:38:15
+ --> $DIR/named-asm-labels.rs:41:15
|
LL | asm!("foo7: nop; foo8: nop");
| ^^^^ ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:40:15
+ --> $DIR/named-asm-labels.rs:43:15
|
LL | asm!("foo9: nop; nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:41:20
+ --> $DIR/named-asm-labels.rs:44:20
|
LL | asm!("nop; foo10: nop");
| ^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:44:15
+ --> $DIR/named-asm-labels.rs:47:15
|
LL | asm!("bar2: nop\n bar3: nop");
| ^^^^ ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:46:15
+ --> $DIR/named-asm-labels.rs:49:15
|
LL | asm!("bar4: nop\n nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:47:21
+ --> $DIR/named-asm-labels.rs:50:21
|
LL | asm!("nop\n bar5: nop");
| ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:48:21
+ --> $DIR/named-asm-labels.rs:51:21
|
LL | asm!("nop\n bar6: bar7: nop");
| ^^^^ ^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:54:13
+ --> $DIR/named-asm-labels.rs:57:13
|
LL | blah2: nop
| ^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:63:19
+ --> $DIR/named-asm-labels.rs:66:19
|
LL | nop ; blah4: nop
| ^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:77:15
+ --> $DIR/named-asm-labels.rs:80:15
|
LL | asm!("blah1: 2bar: nop");
| ^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:80:15
+ --> $DIR/named-asm-labels.rs:83:15
|
LL | asm!("def: def: nop");
| ^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:81:15
+ --> $DIR/named-asm-labels.rs:84:15
|
LL | asm!("def: nop\ndef: nop");
| ^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:82:15
+ --> $DIR/named-asm-labels.rs:85:15
|
LL | asm!("def: nop; def: nop");
| ^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:90:15
+ --> $DIR/named-asm-labels.rs:93:15
|
LL | asm!("fooo\u{003A} nop");
| ^^^^^^^^^^^^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:91:15
+ --> $DIR/named-asm-labels.rs:94:15
|
LL | asm!("foooo\x3A nop");
| ^^^^^^^^^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:94:15
+ --> $DIR/named-asm-labels.rs:97:15
|
LL | asm!("fooooo:\u{000A} nop");
| ^^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:95:15
+ --> $DIR/named-asm-labels.rs:98:15
|
LL | asm!("foooooo:\x0A nop");
| ^^^^^^^
= note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:99:14
+ --> $DIR/named-asm-labels.rs:102:14
|
LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-// only-x86_64
+// needs-asm-support
// check-pass
#![feature(asm, never_type)]
+++ /dev/null
-// only-x86_64
-
-#![feature(asm, global_asm)]
-
-fn main() {
- let mut foo = 0;
- let mut bar = 0;
- unsafe {
- asm!();
- //~^ ERROR requires at least a template string argument
- asm!(foo);
- //~^ ERROR asm template must be a string literal
- asm!("{}" foo);
- //~^ ERROR expected token: `,`
- asm!("{}", foo);
- //~^ ERROR expected operand, clobber_abi, options, or additional template string
- asm!("{}", in foo);
- //~^ ERROR expected `(`, found `foo`
- asm!("{}", in(reg foo));
- //~^ ERROR expected `)`, found `foo`
- asm!("{}", in(reg));
- //~^ ERROR expected expression, found end of macro arguments
- asm!("{}", inout(=) foo => bar);
- //~^ ERROR expected register class or explicit register
- asm!("{}", inout(reg) foo =>);
- //~^ ERROR expected expression, found end of macro arguments
- asm!("{}", in(reg) foo => bar);
- //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
- asm!("{}", sym foo + bar);
- //~^ ERROR argument to `sym` must be a path expression
- asm!("", options(foo));
- //~^ ERROR expected one of
- asm!("", options(nomem foo));
- //~^ ERROR expected one of
- asm!("", options(nomem, foo));
- //~^ ERROR expected one of
- asm!("{}", options(), const foo);
- //~^ ERROR arguments are not allowed after options
- //~^^ ERROR attempt to use a non-constant value in a constant
- asm!("", clobber_abi(foo));
- //~^ ERROR expected string literal
- asm!("", clobber_abi("C" foo));
- //~^ ERROR expected `)`, found `foo`
- asm!("", clobber_abi("C", foo));
- //~^ ERROR expected `)`, found `,`
- asm!("{}", clobber_abi("C"), const foo);
- //~^ ERROR arguments are not allowed after clobber_abi
- //~^^ ERROR attempt to use a non-constant value in a constant
- asm!("", options(), clobber_abi("C"));
- //~^ ERROR clobber_abi is not allowed after options
- asm!("{}", options(), clobber_abi("C"), const foo);
- //~^ ERROR clobber_abi is not allowed after options
- asm!("", clobber_abi("C"), clobber_abi("C"));
- //~^ ERROR clobber_abi specified multiple times
- asm!("{a}", a = const foo, a = const bar);
- //~^ ERROR duplicate argument named `a`
- //~^^ ERROR argument never used
- //~^^^ ERROR attempt to use a non-constant value in a constant
- //~^^^^ ERROR attempt to use a non-constant value in a constant
- asm!("", a = in("eax") foo);
- //~^ ERROR explicit register arguments cannot have names
- asm!("{a}", in("eax") foo, a = const bar);
- //~^ ERROR named arguments cannot follow explicit register arguments
- //~^^ ERROR attempt to use a non-constant value in a constant
- asm!("{a}", in("eax") foo, a = const bar);
- //~^ ERROR named arguments cannot follow explicit register arguments
- //~^^ ERROR attempt to use a non-constant value in a constant
- asm!("{1}", in("eax") foo, const bar);
- //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
- //~^^ ERROR attempt to use a non-constant value in a constant
- asm!("", options(), "");
- //~^ ERROR expected one of
- asm!("{}", in(reg) foo, "{}", out(reg) foo);
- //~^ ERROR expected one of
- asm!(format!("{{{}}}", 0), in(reg) foo);
- //~^ ERROR asm template must be a string literal
- asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
- //~^ ERROR asm template must be a string literal
- asm!("{}", in(reg) _);
- //~^ ERROR _ cannot be used for input operands
- asm!("{}", inout(reg) _);
- //~^ ERROR _ cannot be used for input operands
- asm!("{}", inlateout(reg) _);
- //~^ ERROR _ cannot be used for input operands
- }
-}
-
-const FOO: i32 = 1;
-const BAR: i32 = 2;
-global_asm!();
-//~^ ERROR requires at least a template string argument
-global_asm!(FOO);
-//~^ ERROR asm template must be a string literal
-global_asm!("{}" FOO);
-//~^ ERROR expected token: `,`
-global_asm!("{}", FOO);
-//~^ ERROR expected operand, options, or additional template string
-global_asm!("{}", const);
-//~^ ERROR expected expression, found end of macro arguments
-global_asm!("{}", const(reg) FOO);
-//~^ ERROR expected one of
-global_asm!("", options(FOO));
-//~^ ERROR expected one of
-global_asm!("", options(nomem FOO));
-//~^ ERROR expected one of
-global_asm!("", options(nomem, FOO));
-//~^ ERROR expected one of
-global_asm!("{}", options(), const FOO);
-//~^ ERROR arguments are not allowed after options
-global_asm!("", clobber_abi(FOO));
-//~^ ERROR expected string literal
-global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected `)`, found `FOO`
-global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected `)`, found `,`
-global_asm!("{}", clobber_abi("C"), const FOO);
-//~^ ERROR arguments are not allowed after clobber_abi
-//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
-global_asm!("", options(), clobber_abi("C"));
-//~^ ERROR clobber_abi is not allowed after options
-global_asm!("{}", options(), clobber_abi("C"), const FOO);
-//~^ ERROR clobber_abi is not allowed after options
-global_asm!("", clobber_abi("C"), clobber_abi("C"));
-//~^ ERROR clobber_abi specified multiple times
-global_asm!("{a}", a = const FOO, a = const BAR);
-//~^ ERROR duplicate argument named `a`
-//~^^ ERROR argument never used
-global_asm!("", options(), "");
-//~^ ERROR expected one of
-global_asm!("{}", const FOO, "{}", const FOO);
-//~^ ERROR expected one of
-global_asm!(format!("{{{}}}", 0), const FOO);
-//~^ ERROR asm template must be a string literal
-global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
-//~^ ERROR asm template must be a string literal
+++ /dev/null
-error: requires at least a template string argument
- --> $DIR/parse-error.rs:9:9
- |
-LL | asm!();
- | ^^^^^^^
-
-error: asm template must be a string literal
- --> $DIR/parse-error.rs:11:14
- |
-LL | asm!(foo);
- | ^^^
-
-error: expected token: `,`
- --> $DIR/parse-error.rs:13:19
- |
-LL | asm!("{}" foo);
- | ^^^ expected `,`
-
-error: expected operand, clobber_abi, options, or additional template string
- --> $DIR/parse-error.rs:15:20
- |
-LL | asm!("{}", foo);
- | ^^^ expected operand, clobber_abi, options, or additional template string
-
-error: expected `(`, found `foo`
- --> $DIR/parse-error.rs:17:23
- |
-LL | asm!("{}", in foo);
- | ^^^ expected `(`
-
-error: expected `)`, found `foo`
- --> $DIR/parse-error.rs:19:27
- |
-LL | asm!("{}", in(reg foo));
- | ^^^ expected `)`
-
-error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:21:27
- |
-LL | asm!("{}", in(reg));
- | ^ expected expression
-
-error: expected register class or explicit register
- --> $DIR/parse-error.rs:23:26
- |
-LL | asm!("{}", inout(=) foo => bar);
- | ^
-
-error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:25:37
- |
-LL | asm!("{}", inout(reg) foo =>);
- | ^ expected expression
-
-error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
- --> $DIR/parse-error.rs:27:32
- |
-LL | asm!("{}", in(reg) foo => bar);
- | ^^ expected one of 7 possible tokens
-
-error: argument to `sym` must be a path expression
- --> $DIR/parse-error.rs:29:24
- |
-LL | asm!("{}", sym foo + bar);
- | ^^^^^^^^^
-
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
- --> $DIR/parse-error.rs:31:26
- |
-LL | asm!("", options(foo));
- | ^^^ expected one of 9 possible tokens
-
-error: expected one of `)` or `,`, found `foo`
- --> $DIR/parse-error.rs:33:32
- |
-LL | asm!("", options(nomem foo));
- | ^^^ expected one of `)` or `,`
-
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
- --> $DIR/parse-error.rs:35:33
- |
-LL | asm!("", options(nomem, foo));
- | ^^^ expected one of 9 possible tokens
-
-error: arguments are not allowed after options
- --> $DIR/parse-error.rs:37:31
- |
-LL | asm!("{}", options(), const foo);
- | --------- ^^^^^^^^^ argument
- | |
- | previous options
-
-error: expected string literal
- --> $DIR/parse-error.rs:40:30
- |
-LL | asm!("", clobber_abi(foo));
- | ^^^ not a string literal
-
-error: expected `)`, found `foo`
- --> $DIR/parse-error.rs:42:34
- |
-LL | asm!("", clobber_abi("C" foo));
- | ^^^ expected `)`
-
-error: expected `)`, found `,`
- --> $DIR/parse-error.rs:44:33
- |
-LL | asm!("", clobber_abi("C", foo));
- | ^ expected `)`
-
-error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:46:38
- |
-LL | asm!("{}", clobber_abi("C"), const foo);
- | ---------------- ^^^^^^^^^ argument
- | |
- | clobber_abi
-
-error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:49:29
- |
-LL | asm!("", options(), clobber_abi("C"));
- | --------- ^^^^^^^^^^^^^^^^
- | |
- | options
-
-error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:51:31
- |
-LL | asm!("{}", options(), clobber_abi("C"), const foo);
- | --------- ^^^^^^^^^^^^^^^^
- | |
- | options
-
-error: clobber_abi specified multiple times
- --> $DIR/parse-error.rs:53:36
- |
-LL | asm!("", clobber_abi("C"), clobber_abi("C"));
- | ---------------- ^^^^^^^^^^^^^^^^
- | |
- | clobber_abi previously specified here
-
-error: duplicate argument named `a`
- --> $DIR/parse-error.rs:55:36
- |
-LL | asm!("{a}", a = const foo, a = const bar);
- | ------------- ^^^^^^^^^^^^^ duplicate argument
- | |
- | previously here
-
-error: argument never used
- --> $DIR/parse-error.rs:55:36
- |
-LL | asm!("{a}", a = const foo, a = const bar);
- | ^^^^^^^^^^^^^ argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
-
-error: explicit register arguments cannot have names
- --> $DIR/parse-error.rs:60:18
- |
-LL | asm!("", a = in("eax") foo);
- | ^^^^^^^^^^^^^^^^^
-
-error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:62:36
- |
-LL | asm!("{a}", in("eax") foo, a = const bar);
- | ------------- ^^^^^^^^^^^^^ named argument
- | |
- | explicit register argument
-
-error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:65:36
- |
-LL | asm!("{a}", in("eax") foo, a = const bar);
- | ------------- ^^^^^^^^^^^^^ named argument
- | |
- | explicit register argument
-
-error: positional arguments cannot follow named arguments or explicit register arguments
- --> $DIR/parse-error.rs:68:36
- |
-LL | asm!("{1}", in("eax") foo, const bar);
- | ------------- ^^^^^^^^^ positional argument
- | |
- | explicit register argument
-
-error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
- --> $DIR/parse-error.rs:71:29
- |
-LL | asm!("", options(), "");
- | ^^ expected one of 9 possible tokens
-
-error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
- --> $DIR/parse-error.rs:73:33
- |
-LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
- | ^^^^ expected one of 9 possible tokens
-
-error: asm template must be a string literal
- --> $DIR/parse-error.rs:75:14
- |
-LL | asm!(format!("{{{}}}", 0), in(reg) foo);
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm template must be a string literal
- --> $DIR/parse-error.rs:77:21
- |
-LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:79:28
- |
-LL | asm!("{}", in(reg) _);
- | ^
-
-error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:81:31
- |
-LL | asm!("{}", inout(reg) _);
- | ^
-
-error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:83:35
- |
-LL | asm!("{}", inlateout(reg) _);
- | ^
-
-error: requires at least a template string argument
- --> $DIR/parse-error.rs:90:1
- |
-LL | global_asm!();
- | ^^^^^^^^^^^^^^
-
-error: asm template must be a string literal
- --> $DIR/parse-error.rs:92:13
- |
-LL | global_asm!(FOO);
- | ^^^
-
-error: expected token: `,`
- --> $DIR/parse-error.rs:94:18
- |
-LL | global_asm!("{}" FOO);
- | ^^^ expected `,`
-
-error: expected operand, options, or additional template string
- --> $DIR/parse-error.rs:96:19
- |
-LL | global_asm!("{}", FOO);
- | ^^^ expected operand, options, or additional template string
-
-error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:98:24
- |
-LL | global_asm!("{}", const);
- | ^ expected expression
-
-error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
- --> $DIR/parse-error.rs:100:30
- |
-LL | global_asm!("{}", const(reg) FOO);
- | ^^^ expected one of `,`, `.`, `?`, or an operator
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
- --> $DIR/parse-error.rs:102:25
- |
-LL | global_asm!("", options(FOO));
- | ^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:104:25
- |
-LL | global_asm!("", options(nomem FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:106:25
- |
-LL | global_asm!("", options(nomem, FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: arguments are not allowed after options
- --> $DIR/parse-error.rs:108:30
- |
-LL | global_asm!("{}", options(), const FOO);
- | --------- ^^^^^^^^^ argument
- | |
- | previous options
-
-error: expected string literal
- --> $DIR/parse-error.rs:110:29
- |
-LL | global_asm!("", clobber_abi(FOO));
- | ^^^ not a string literal
-
-error: expected `)`, found `FOO`
- --> $DIR/parse-error.rs:112:33
- |
-LL | global_asm!("", clobber_abi("C" FOO));
- | ^^^ expected `)`
-
-error: expected `)`, found `,`
- --> $DIR/parse-error.rs:114:32
- |
-LL | global_asm!("", clobber_abi("C", FOO));
- | ^ expected `)`
-
-error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:116:37
- |
-LL | global_asm!("{}", clobber_abi("C"), const FOO);
- | ---------------- ^^^^^^^^^ argument
- | |
- | clobber_abi
-
-error: `clobber_abi` cannot be used with `global_asm!`
- --> $DIR/parse-error.rs:116:19
- |
-LL | global_asm!("{}", clobber_abi("C"), const FOO);
- | ^^^^^^^^^^^^^^^^
-
-error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:119:28
- |
-LL | global_asm!("", options(), clobber_abi("C"));
- | --------- ^^^^^^^^^^^^^^^^
- | |
- | options
-
-error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:121:30
- |
-LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
- | --------- ^^^^^^^^^^^^^^^^
- | |
- | options
-
-error: clobber_abi specified multiple times
- --> $DIR/parse-error.rs:123:35
- |
-LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
- | ---------------- ^^^^^^^^^^^^^^^^
- | |
- | clobber_abi previously specified here
-
-error: duplicate argument named `a`
- --> $DIR/parse-error.rs:125:35
- |
-LL | global_asm!("{a}", a = const FOO, a = const BAR);
- | ------------- ^^^^^^^^^^^^^ duplicate argument
- | |
- | previously here
-
-error: argument never used
- --> $DIR/parse-error.rs:125:35
- |
-LL | global_asm!("{a}", a = const FOO, a = const BAR);
- | ^^^^^^^^^^^^^ argument never used
- |
- = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
-
-error: expected one of `clobber_abi`, `const`, or `options`, found `""`
- --> $DIR/parse-error.rs:128:28
- |
-LL | global_asm!("", options(), "");
- | ^^ expected one of `clobber_abi`, `const`, or `options`
-
-error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
- --> $DIR/parse-error.rs:130:30
- |
-LL | global_asm!("{}", const FOO, "{}", const FOO);
- | ^^^^ expected one of `clobber_abi`, `const`, or `options`
-
-error: asm template must be a string literal
- --> $DIR/parse-error.rs:132:13
- |
-LL | global_asm!(format!("{{{}}}", 0), const FOO);
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm template must be a string literal
- --> $DIR/parse-error.rs:134:20
- |
-LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:37:37
- |
-LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
-...
-LL | asm!("{}", options(), const foo);
- | ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:46:44
- |
-LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
-...
-LL | asm!("{}", clobber_abi("C"), const foo);
- | ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:55:31
- |
-LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
-...
-LL | asm!("{a}", a = const foo, a = const bar);
- | ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:55:46
- |
-LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL | asm!("{a}", a = const foo, a = const bar);
- | ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:62:46
- |
-LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL | asm!("{a}", in("eax") foo, a = const bar);
- | ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:65:46
- |
-LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL | asm!("{a}", in("eax") foo, a = const bar);
- | ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:68:42
- |
-LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL | asm!("{1}", in("eax") foo, const bar);
- | ^^^ non-constant value
-
-error: aborting due to 66 previous errors
-
-For more information about this error, try `rustc --explain E0435`.
// run-rustfix
-// only-x86_64
+// needs-asm-support
#![feature(asm, llvm_asm)]
#![allow(deprecated)] // llvm_asm!
// run-rustfix
-// only-x86_64
+// needs-asm-support
#![feature(asm, llvm_asm)]
#![allow(deprecated)] // llvm_asm!
+++ /dev/null
-// min-llvm-version: 10.0.1
-// only-x86_64
-// build-fail
-// compile-flags: -Ccodegen-units=1
-#![feature(asm)]
-
-// Checks that inline asm errors are mapped to the correct line in the source code.
-
-fn main() {
- unsafe {
- asm!("invalid_instruction");
- //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!("
- invalid_instruction
- ");
- //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(r#"
- invalid_instruction
- "#);
- //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!("
- mov eax, eax
- invalid_instruction
- mov eax, eax
- ");
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(r#"
- mov eax, eax
- invalid_instruction
- mov eax, eax
- "#);
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(concat!("invalid", "_", "instruction"));
- //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
- //~^ WARN: scale factor without index register is ignored
-
- asm!(
- "invalid_instruction",
- );
- //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(
- "mov eax, eax",
- "invalid_instruction",
- "mov eax, eax",
- );
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(
- "mov eax, eax\n",
- "invalid_instruction",
- "mov eax, eax",
- );
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(
- "mov eax, eax",
- concat!("invalid", "_", "instruction"),
- "mov eax, eax",
- );
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- asm!(
- concat!("mov eax", ", ", "eax"),
- concat!("invalid", "_", "instruction"),
- concat!("mov eax", ", ", "eax"),
- );
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
- // Make sure template strings get separated
- asm!(
- "invalid_instruction1",
- "invalid_instruction2",
- );
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
- //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
-
- asm!(
- concat!(
- "invalid", "_", "instruction1", "\n",
- "invalid", "_", "instruction2",
- ),
- );
- //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
- //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
-
- asm!(
- concat!(
- "invalid", "_", "instruction1", "\n",
- "invalid", "_", "instruction2",
- ),
- concat!(
- "invalid", "_", "instruction3", "\n",
- "invalid", "_", "instruction4",
- ),
- );
- //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
- //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
- //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
- //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
-
- asm!(
- concat!(
- "invalid", "_", "instruction1", "\n",
- "invalid", "_", "instruction2", "\n",
- ),
- concat!(
- "invalid", "_", "instruction3", "\n",
- "invalid", "_", "instruction4", "\n",
- ),
- );
- //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
- //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
- //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
- //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
- }
-}
+++ /dev/null
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:11:15
- |
-LL | asm!("invalid_instruction");
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:15:13
- |
-LL | invalid_instruction
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:13
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:20:13
- |
-LL | invalid_instruction
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:13
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:26:13
- |
-LL | invalid_instruction
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:4:13
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:33:13
- |
-LL | invalid_instruction
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:4:13
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:38:14
- |
-LL | asm!(concat!("invalid", "_", "instruction"));
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-warning: scale factor without index register is ignored
- --> $DIR/srcloc.rs:41:15
- |
-LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:1:23
- |
-LL | movaps %xmm3, (%esi, 2)
- | ^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:45:14
- |
-LL | "invalid_instruction",
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:51:14
- |
-LL | "invalid_instruction",
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:58:14
- |
-LL | "invalid_instruction",
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:4:1
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:65:13
- |
-LL | concat!("invalid", "_", "instruction"),
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:72:13
- |
-LL | concat!("invalid", "_", "instruction"),
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction
- | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:79:14
- |
-LL | "invalid_instruction1",
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction1
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:80:14
- |
-LL | "invalid_instruction2",
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction2
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:86:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction1
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:86:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction2
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:95:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction1
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:95:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction2
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:99:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:4:1
- |
-LL | invalid_instruction3
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:99:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:5:1
- |
-LL | invalid_instruction4
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:110:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:2:2
- |
-LL | invalid_instruction1
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:110:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:3:1
- |
-LL | invalid_instruction2
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:114:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:5:1
- |
-LL | invalid_instruction3
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:114:13
- |
-LL | concat!(
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:6:1
- |
-LL | invalid_instruction4
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 23 previous errors; 1 warning emitted
-
+++ /dev/null
-// min-llvm-version: 10.0.1
-// only-x86_64
-// only-linux
-// run-pass
-
-#![feature(asm, thread_local)]
-
-extern "C" fn f1() -> i32 {
- 111
-}
-
-// The compiler will generate a shim to hide the caller location parameter.
-#[track_caller]
-fn f2() -> i32 {
- 222
-}
-
-macro_rules! call {
- ($func:path) => {
- unsafe {
- let result: i32;
- asm!("call {}", sym $func,
- out("rax") result,
- out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
- out("r8") _, out("r9") _, out("r10") _, out("r11") _,
- out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
- out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
- out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
- out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
- );
- result
- }
- }
-}
-
-macro_rules! static_addr {
- ($s:expr) => {
- unsafe {
- let result: *const u32;
- // LEA performs a RIP-relative address calculation and returns the address
- asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
- result
- }
- }
-}
-macro_rules! static_tls_addr {
- ($s:expr) => {
- unsafe {
- let result: *const u32;
- asm!(
- "
- # Load TLS base address
- mov {out}, qword ptr fs:[0]
- # Calculate the address of sym in the TLS block. The @tpoff
- # relocation gives the offset of the symbol from the start
- # of the TLS block.
- lea {out}, [{out} + {sym}@tpoff]
- ",
- out = out(reg) result,
- sym = sym $s
- );
- result
- }
- }
-}
-
-static S1: u32 = 111;
-#[thread_local]
-static S2: u32 = 222;
-
-fn main() {
- assert_eq!(call!(f1), 111);
- assert_eq!(call!(f2), 222);
- assert_eq!(static_addr!(S1), &S1 as *const u32);
- assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
- std::thread::spawn(|| {
- assert_eq!(static_addr!(S1), &S1 as *const u32);
- assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
- }).join().unwrap();
-}
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
#![feature(asm, global_asm)]
//~^ ERROR mismatched types
asm!("{}", const 0 as *mut u8);
//~^ ERROR mismatched types
+ asm!("{}", const &0);
+ //~^ ERROR mismatched types
}
}
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/type-check-1.rs:34:26
+ --> $DIR/type-check-1.rs:37:26
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
| ^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/type-check-1.rs:37:36
+ --> $DIR/type-check-1.rs:40:36
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
| ^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/type-check-1.rs:40:36
+ --> $DIR/type-check-1.rs:43:36
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
| ^ non-constant value
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:48:26
+ --> $DIR/type-check-1.rs:51:26
|
LL | asm!("{}", const 0f32);
| ^^^^ expected integer, found `f32`
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:50:26
+ --> $DIR/type-check-1.rs:53:26
|
LL | asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^ expected integer, found *-ptr
= note: expected type `{integer}`
found raw pointer `*mut u8`
+error[E0308]: mismatched types
+ --> $DIR/type-check-1.rs:55:26
+ |
+LL | asm!("{}", const &0);
+ | ^^ expected integer, found `&{integer}`
+ |
+help: consider removing the borrow
+ |
+LL - asm!("{}", const &0);
+LL + asm!("{}", const 0);
+ |
+
error: invalid asm output
- --> $DIR/type-check-1.rs:10:29
+ --> $DIR/type-check-1.rs:13:29
|
LL | asm!("{}", out(reg) 1 + 2);
| ^^^^^ cannot assign to this expression
error: invalid asm output
- --> $DIR/type-check-1.rs:12:31
+ --> $DIR/type-check-1.rs:15:31
|
LL | asm!("{}", inout(reg) 1 + 2);
| ^^^^^ cannot assign to this expression
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
- --> $DIR/type-check-1.rs:18:28
+ --> $DIR/type-check-1.rs:21:28
|
LL | asm!("{}", in(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
= note: all inline asm arguments must have a statically known size
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
- --> $DIR/type-check-1.rs:20:29
+ --> $DIR/type-check-1.rs:23:29
|
LL | asm!("{}", out(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
= note: all inline asm arguments must have a statically known size
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
- --> $DIR/type-check-1.rs:22:31
+ --> $DIR/type-check-1.rs:25:31
|
LL | asm!("{}", inout(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
= note: all inline asm arguments must have a statically known size
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:60:25
+ --> $DIR/type-check-1.rs:65:25
|
LL | global_asm!("{}", const 0f32);
| ^^^^ expected integer, found `f32`
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:62:25
+ --> $DIR/type-check-1.rs:67:25
|
LL | global_asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^ expected integer, found *-ptr
= note: expected type `{integer}`
found raw pointer `*mut u8`
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
Some errors have detailed explanations: E0277, E0308, E0435.
For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-// only-x86_64
-
-#![feature(asm, repr_simd, never_type)]
-
-#[repr(simd)]
-struct SimdNonCopy(f32, f32, f32, f32);
-
-fn main() {
- unsafe {
- // Inputs must be initialized
-
- let x: u64;
- asm!("{}", in(reg) x);
- //~^ ERROR use of possibly-uninitialized variable: `x`
- let mut y: u64;
- asm!("{}", inout(reg) y);
- //~^ ERROR use of possibly-uninitialized variable: `y`
- let _ = y;
-
- // Outputs require mutable places
-
- let v: Vec<u64> = vec![0, 1, 2];
- asm!("{}", in(reg) v[0]);
- asm!("{}", out(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
- asm!("{}", inout(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
-
- // This currently causes an ICE: https://github.com/rust-lang/rust/issues/81857
- // asm!("{}", const &0);
- // ERROR asm `const` arguments must be integer or floating-point values
-
- // Sym operands must point to a function or static
-
- const C: i32 = 0;
- static S: i32 = 0;
- asm!("{}", sym S);
- asm!("{}", sym main);
- asm!("{}", sym C);
- //~^ ERROR asm `sym` operand must point to a fn or static
- asm!("{}", sym x);
- //~^ ERROR asm `sym` operand must point to a fn or static
-
- // Register operands must be Copy
-
- asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
- //~^ ERROR arguments for inline assembly must be copyable
-
- // Register operands must be integers, floats, SIMD vectors, pointers or
- // function pointers.
-
- asm!("{}", in(reg) 0i64);
- asm!("{}", in(reg) 0f64);
- asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps());
- asm!("{}", in(reg) 0 as *const u8);
- asm!("{}", in(reg) 0 as *mut u8);
- asm!("{}", in(reg) main as fn());
- asm!("{}", in(reg) |x: i32| x);
- //~^ ERROR cannot use value of type
- asm!("{}", in(reg) vec![0]);
- //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly
- asm!("{}", in(reg) (1, 2, 3));
- //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly
- asm!("{}", in(reg) [1, 2, 3]);
- //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly
-
- // Register inputs (but not outputs) allow references and function types
-
- let mut f = main;
- let mut r = &mut 0;
- asm!("{}", in(reg) f);
- asm!("{}", inout(reg) f);
- //~^ ERROR cannot use value of type `fn() {main}` for inline assembly
- asm!("{}", in(reg) r);
- asm!("{}", inout(reg) r);
- //~^ ERROR cannot use value of type `&mut i32` for inline assembly
- let _ = (f, r);
-
- // Type checks ignore never type
-
- let u: ! = unreachable!();
- asm!("{}", in(reg) u);
- }
-}
+++ /dev/null
-error: arguments for inline assembly must be copyable
- --> $DIR/type-check-2.rs:46:32
- |
-LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `SimdNonCopy` does not implement the Copy trait
-
-error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly
- --> $DIR/type-check-2.rs:58:28
- |
-LL | asm!("{}", in(reg) |x: i32| x);
- | ^^^^^^^^^^
- |
- = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `Vec<i32>` for inline assembly
- --> $DIR/type-check-2.rs:60:28
- |
-LL | asm!("{}", in(reg) vec![0]);
- | ^^^^^^^
- |
- = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
- = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: cannot use value of type `(i32, i32, i32)` for inline assembly
- --> $DIR/type-check-2.rs:62:28
- |
-LL | asm!("{}", in(reg) (1, 2, 3));
- | ^^^^^^^^^
- |
- = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `[i32; 3]` for inline assembly
- --> $DIR/type-check-2.rs:64:28
- |
-LL | asm!("{}", in(reg) [1, 2, 3]);
- | ^^^^^^^^^
- |
- = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `fn() {main}` for inline assembly
- --> $DIR/type-check-2.rs:72:31
- |
-LL | asm!("{}", inout(reg) f);
- | ^
- |
- = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `&mut i32` for inline assembly
- --> $DIR/type-check-2.rs:75:31
- |
-LL | asm!("{}", inout(reg) r);
- | ^
- |
- = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: asm `sym` operand must point to a fn or static
- --> $DIR/type-check-2.rs:39:24
- |
-LL | asm!("{}", sym C);
- | ^
-
-error: asm `sym` operand must point to a fn or static
- --> $DIR/type-check-2.rs:41:24
- |
-LL | asm!("{}", sym x);
- | ^
-
-error[E0381]: use of possibly-uninitialized variable: `x`
- --> $DIR/type-check-2.rs:13:28
- |
-LL | asm!("{}", in(reg) x);
- | ^ use of possibly-uninitialized `x`
-
-error[E0381]: use of possibly-uninitialized variable: `y`
- --> $DIR/type-check-2.rs:16:9
- |
-LL | asm!("{}", inout(reg) y);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2.rs:24:29
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-LL | asm!("{}", in(reg) v[0]);
-LL | asm!("{}", out(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2.rs:26:31
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-...
-LL | asm!("{}", inout(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error: aborting due to 13 previous errors
-
-Some errors have detailed explanations: E0381, E0596.
-For more information about an error, try `rustc --explain E0381`.
+++ /dev/null
-// only-x86_64
-// compile-flags: -C target-feature=+avx512f
-
-#![feature(asm, global_asm)]
-
-use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
-
-fn main() {
- unsafe {
- // Types must be listed in the register class.
-
- asm!("{}", in(reg) 0i128);
- //~^ ERROR type `i128` cannot be used with this register class
- asm!("{}", in(reg) _mm_setzero_ps());
- //~^ ERROR type `__m128` cannot be used with this register class
- asm!("{}", in(reg) _mm256_setzero_ps());
- //~^ ERROR type `__m256` cannot be used with this register class
- asm!("{}", in(xmm_reg) 0u8);
- //~^ ERROR type `u8` cannot be used with this register class
- asm!("{:e}", in(reg) 0i32);
- asm!("{}", in(xmm_reg) 0i32);
- asm!("{:e}", in(reg) 0f32);
- asm!("{}", in(xmm_reg) 0f32);
- asm!("{}", in(xmm_reg) _mm_setzero_ps());
- asm!("{:x}", in(ymm_reg) _mm_setzero_ps());
- asm!("{}", in(kreg) 0u16);
- asm!("{}", in(kreg) 0u64);
- //~^ ERROR `avx512bw` target feature is not enabled
-
- // Template modifier suggestions for sub-registers
-
- asm!("{0} {0}", in(reg) 0i16);
- //~^ WARN formatting may not be suitable for sub-register argument
- asm!("{0} {0:x}", in(reg) 0i16);
- //~^ WARN formatting may not be suitable for sub-register argument
- asm!("{}", in(reg) 0i32);
- //~^ WARN formatting may not be suitable for sub-register argument
- asm!("{}", in(reg) 0i64);
- asm!("{}", in(ymm_reg) 0i64);
- //~^ WARN formatting may not be suitable for sub-register argument
- asm!("{}", in(ymm_reg) _mm256_setzero_ps());
- asm!("{:l}", in(reg) 0i16);
- asm!("{:l}", in(reg) 0i32);
- asm!("{:l}", in(reg) 0i64);
- asm!("{:x}", in(ymm_reg) 0i64);
- asm!("{:x}", in(ymm_reg) _mm256_setzero_ps());
-
- // Suggest different register class for type
-
- asm!("{}", in(reg) 0i8);
- //~^ ERROR type `i8` cannot be used with this register class
- asm!("{}", in(reg_byte) 0i8);
-
- // Split inout operands must have compatible types
-
- let mut val_i16: i16;
- let mut val_f32: f32;
- let mut val_u32: u32;
- let mut val_u64: u64;
- let mut val_ptr: *mut u8;
- asm!("{:r}", inout(reg) 0u16 => val_i16);
- asm!("{:r}", inout(reg) 0u32 => val_f32);
- //~^ ERROR incompatible types for asm inout argument
- asm!("{:r}", inout(reg) 0u32 => val_ptr);
- //~^ ERROR incompatible types for asm inout argument
- asm!("{:r}", inout(reg) main => val_u32);
- //~^ ERROR incompatible types for asm inout argument
- asm!("{:r}", inout(reg) 0u64 => val_ptr);
- asm!("{:r}", inout(reg) main => val_u64);
- }
-}
-
-// Constants must be... constant
-
-static S: i32 = 1;
-const fn const_foo(x: i32) -> i32 {
- x
-}
-const fn const_bar<T>(x: T) -> T {
- x
-}
-global_asm!("{}", const S);
-//~^ ERROR constants cannot refer to statics
-global_asm!("{}", const const_foo(0));
-global_asm!("{}", const const_foo(S));
-//~^ ERROR constants cannot refer to statics
-global_asm!("{}", const const_bar(0));
-global_asm!("{}", const const_bar(S));
-//~^ ERROR constants cannot refer to statics
+++ /dev/null
-error: type `i128` cannot be used with this register class
- --> $DIR/type-check-3.rs:12:28
- |
-LL | asm!("{}", in(reg) 0i128);
- | ^^^^^
- |
- = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-
-error: type `__m128` cannot be used with this register class
- --> $DIR/type-check-3.rs:14:28
- |
-LL | asm!("{}", in(reg) _mm_setzero_ps());
- | ^^^^^^^^^^^^^^^^
- |
- = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-
-error: type `__m256` cannot be used with this register class
- --> $DIR/type-check-3.rs:16:28
- |
-LL | asm!("{}", in(reg) _mm256_setzero_ps());
- | ^^^^^^^^^^^^^^^^^^^
- |
- = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-
-error: type `u8` cannot be used with this register class
- --> $DIR/type-check-3.rs:18:32
- |
-LL | asm!("{}", in(xmm_reg) 0u8);
- | ^^^
- |
- = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
-
-error: `avx512bw` target feature is not enabled
- --> $DIR/type-check-3.rs:27:29
- |
-LL | asm!("{}", in(kreg) 0u64);
- | ^^^^
- |
- = note: this is required to use type `u64` with register class `kreg`
-
-warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:32:15
- |
-LL | asm!("{0} {0}", in(reg) 0i16);
- | ^^^ ^^^ ---- for this argument
- |
- = note: `#[warn(asm_sub_register)]` on by default
- = help: use the `x` modifier to have the register formatted as `ax`
- = help: or use the `r` modifier to keep the default formatting of `rax`
-
-warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:34:15
- |
-LL | asm!("{0} {0:x}", in(reg) 0i16);
- | ^^^ ---- for this argument
- |
- = help: use the `x` modifier to have the register formatted as `ax`
- = help: or use the `r` modifier to keep the default formatting of `rax`
-
-warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:36:15
- |
-LL | asm!("{}", in(reg) 0i32);
- | ^^ ---- for this argument
- |
- = help: use the `e` modifier to have the register formatted as `eax`
- = help: or use the `r` modifier to keep the default formatting of `rax`
-
-warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:39:15
- |
-LL | asm!("{}", in(ymm_reg) 0i64);
- | ^^ ---- for this argument
- |
- = help: use the `x` modifier to have the register formatted as `xmm0`
- = help: or use the `y` modifier to keep the default formatting of `ymm0`
-
-error: type `i8` cannot be used with this register class
- --> $DIR/type-check-3.rs:50:28
- |
-LL | asm!("{}", in(reg) 0i8);
- | ^^^
- |
- = note: register class `reg` supports these types: i16, i32, i64, f32, f64
- = help: consider using the `reg_byte` register class instead
-
-error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:62:33
- |
-LL | asm!("{:r}", inout(reg) 0u32 => val_f32);
- | ^^^^ ^^^^^^^ type `f32`
- | |
- | type `u32`
- |
- = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
-
-error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:64:33
- |
-LL | asm!("{:r}", inout(reg) 0u32 => val_ptr);
- | ^^^^ ^^^^^^^ type `*mut u8`
- | |
- | type `u32`
- |
- = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
-
-error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:66:33
- |
-LL | asm!("{:r}", inout(reg) main => val_u32);
- | ^^^^ ^^^^^^^ type `u32`
- | |
- | type `fn()`
- |
- = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
-
-error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:82:25
- |
-LL | global_asm!("{}", const S);
- | ^
- |
- = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:85:35
- |
-LL | global_asm!("{}", const const_foo(S));
- | ^
- |
- = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:88:35
- |
-LL | global_asm!("{}", const const_bar(S));
- | ^
- |
- = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error: aborting due to 12 previous errors; 4 warnings emitted
-
-For more information about this error, try `rustc --explain E0013`.
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
#![feature(asm)]
error[E0506]: cannot assign to `a` because it is borrowed
- --> $DIR/type-check-4.rs:11:9
+ --> $DIR/type-check-4.rs:14:9
|
LL | let p = &a;
| -- borrow of `a` occurs here
| - borrow later used here
error[E0503]: cannot use `a` because it was mutably borrowed
- --> $DIR/type-check-4.rs:19:28
+ --> $DIR/type-check-4.rs:22:28
|
LL | let p = &mut a;
| ------ borrow of `a` occurs here
--- /dev/null
+// only-x86_64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ let mut foo = 0;
+ unsafe {
+ asm!("", options(nomem, readonly));
+ //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+ asm!("", options(pure, nomem, noreturn));
+ //~^ ERROR the `pure` and `noreturn` options are mutually exclusive
+ //~^^ ERROR asm with the `pure` option must have at least one output
+ asm!("{}", in(reg) foo, options(pure, nomem));
+ //~^ ERROR asm with the `pure` option must have at least one output
+ asm!("{}", out(reg) foo, options(noreturn));
+ //~^ ERROR asm outputs are not allowed with the `noreturn` option
+ }
+
+ unsafe {
+ asm!("", clobber_abi("foo"));
+ //~^ ERROR invalid ABI for `clobber_abi`
+ asm!("{}", out(reg) foo, clobber_abi("C"));
+ //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+ asm!("", out("eax") foo, clobber_abi("C"));
+ }
+}
+
+global_asm!("", options(nomem));
+//~^ ERROR expected one of
+global_asm!("", options(readonly));
+//~^ ERROR expected one of
+global_asm!("", options(noreturn));
+//~^ ERROR expected one of
+global_asm!("", options(pure));
+//~^ ERROR expected one of
+global_asm!("", options(nostack));
+//~^ ERROR expected one of
+global_asm!("", options(preserves_flags));
+//~^ ERROR expected one of
--- /dev/null
+error: the `nomem` and `readonly` options are mutually exclusive
+ --> $DIR/bad-options.rs:8:18
+ |
+LL | asm!("", options(nomem, readonly));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the `pure` and `noreturn` options are mutually exclusive
+ --> $DIR/bad-options.rs:10:18
+ |
+LL | asm!("", options(pure, nomem, noreturn));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+ --> $DIR/bad-options.rs:10:18
+ |
+LL | asm!("", options(pure, nomem, noreturn));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+ --> $DIR/bad-options.rs:13:33
+ |
+LL | asm!("{}", in(reg) foo, options(pure, nomem));
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: asm outputs are not allowed with the `noreturn` option
+ --> $DIR/bad-options.rs:15:20
+ |
+LL | asm!("{}", out(reg) foo, options(noreturn));
+ | ^^^^^^^^^^^^
+
+error: asm with `clobber_abi` must specify explicit registers for outputs
+ --> $DIR/bad-options.rs:22:20
+ |
+LL | asm!("{}", out(reg) foo, clobber_abi("C"));
+ | ^^^^^^^^^^^^ ---------------- clobber_abi
+ | |
+ | generic outputs
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+ --> $DIR/bad-options.rs:28:25
+ |
+LL | global_asm!("", options(nomem));
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+ --> $DIR/bad-options.rs:30:25
+ |
+LL | global_asm!("", options(readonly));
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+ --> $DIR/bad-options.rs:32:25
+ |
+LL | global_asm!("", options(noreturn));
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+ --> $DIR/bad-options.rs:34:25
+ |
+LL | global_asm!("", options(pure));
+ | ^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+ --> $DIR/bad-options.rs:36:25
+ |
+LL | global_asm!("", options(nostack));
+ | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+ --> $DIR/bad-options.rs:38:25
+ |
+LL | global_asm!("", options(preserves_flags));
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: invalid ABI for `clobber_abi`
+ --> $DIR/bad-options.rs:20:18
+ |
+LL | asm!("", clobber_abi("foo"));
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: aborting due to 13 previous errors
+
--- /dev/null
+// only-x86_64
+// compile-flags: -C target-feature=+avx2
+
+#![feature(asm)]
+
+fn main() {
+ let mut foo = 0;
+ let mut bar = 0;
+ unsafe {
+ // Bad register/register class
+
+ asm!("{}", in(foo) foo);
+ //~^ ERROR invalid register class `foo`: unknown register class
+ asm!("", in("foo") foo);
+ //~^ ERROR invalid register `foo`: unknown register
+ asm!("{:z}", in(reg) foo);
+ //~^ ERROR invalid asm template modifier for this register class
+ asm!("{:r}", in(xmm_reg) foo);
+ //~^ ERROR invalid asm template modifier for this register class
+ asm!("{:a}", const 0);
+ //~^ ERROR asm template modifiers are not allowed for `const` arguments
+ asm!("{:a}", sym main);
+ //~^ ERROR asm template modifiers are not allowed for `sym` arguments
+ asm!("{}", in(zmm_reg) foo);
+ //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
+ asm!("", in("zmm0") foo);
+ //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
+ asm!("", in("ebp") foo);
+ //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand
+ asm!("", in("rsp") foo);
+ //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
+ asm!("", in("ip") foo);
+ //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
+ asm!("", in("k0") foo);
+ //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
+ asm!("", in("ah") foo);
+ //~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
+
+ asm!("", in("st(2)") foo);
+ //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
+ asm!("", in("mm0") foo);
+ //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+ asm!("", out("st(2)") _);
+ asm!("", out("mm0") _);
+ asm!("{}", in(x87_reg) foo);
+ //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
+ asm!("{}", in(mmx_reg) foo);
+ //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+ asm!("{}", out(x87_reg) _);
+ //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
+ asm!("{}", out(mmx_reg) _);
+ //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+
+ // Explicit register conflicts
+ // (except in/lateout which don't conflict)
+
+ asm!("", in("eax") foo, in("al") bar);
+ //~^ ERROR register `al` conflicts with register `ax`
+ asm!("", in("rax") foo, out("rax") bar);
+ //~^ ERROR register `ax` conflicts with register `ax`
+ asm!("", in("al") foo, lateout("al") bar);
+ asm!("", in("xmm0") foo, in("ymm0") bar);
+ //~^ ERROR register `ymm0` conflicts with register `xmm0`
+ asm!("", in("xmm0") foo, out("ymm0") bar);
+ //~^ ERROR register `ymm0` conflicts with register `xmm0`
+ asm!("", in("xmm0") foo, lateout("ymm0") bar);
+ }
+}
--- /dev/null
+error: invalid register class `foo`: unknown register class
+ --> $DIR/bad-reg.rs:12:20
+ |
+LL | asm!("{}", in(foo) foo);
+ | ^^^^^^^^^^^
+
+error: invalid register `foo`: unknown register
+ --> $DIR/bad-reg.rs:14:18
+ |
+LL | asm!("", in("foo") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid asm template modifier for this register class
+ --> $DIR/bad-reg.rs:16:15
+ |
+LL | asm!("{:z}", in(reg) foo);
+ | ^^^^ ----------- argument
+ | |
+ | template modifier
+ |
+ = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r`
+
+error: invalid asm template modifier for this register class
+ --> $DIR/bad-reg.rs:18:15
+ |
+LL | asm!("{:r}", in(xmm_reg) foo);
+ | ^^^^ --------------- argument
+ | |
+ | template modifier
+ |
+ = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z`
+
+error: asm template modifiers are not allowed for `const` arguments
+ --> $DIR/bad-reg.rs:20:15
+ |
+LL | asm!("{:a}", const 0);
+ | ^^^^ ------- argument
+ | |
+ | template modifier
+
+error: asm template modifiers are not allowed for `sym` arguments
+ --> $DIR/bad-reg.rs:22:15
+ |
+LL | asm!("{:a}", sym main);
+ | ^^^^ -------- argument
+ | |
+ | template modifier
+
+error: register class `zmm_reg` requires the `avx512f` target feature
+ --> $DIR/bad-reg.rs:24:20
+ |
+LL | asm!("{}", in(zmm_reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: register class `zmm_reg` requires the `avx512f` target feature
+ --> $DIR/bad-reg.rs:26:18
+ |
+LL | asm!("", in("zmm0") foo);
+ | ^^^^^^^^^^^^^^
+
+error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:28:18
+ |
+LL | asm!("", in("ebp") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:30:18
+ |
+LL | asm!("", in("rsp") foo);
+ | ^^^^^^^^^^^^^
+
+error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:32:18
+ |
+LL | asm!("", in("ip") foo);
+ | ^^^^^^^^^^^^
+
+error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
+ --> $DIR/bad-reg.rs:34:18
+ |
+LL | asm!("", in("k0") foo);
+ | ^^^^^^^^^^^^
+
+error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
+ --> $DIR/bad-reg.rs:36:18
+ |
+LL | asm!("", in("ah") foo);
+ | ^^^^^^^^^^^^
+
+error: register class `x87_reg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:39:18
+ |
+LL | asm!("", in("st(2)") foo);
+ | ^^^^^^^^^^^^^^^
+
+error: register class `mmx_reg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:41:18
+ |
+LL | asm!("", in("mm0") foo);
+ | ^^^^^^^^^^^^^
+
+error: register class `x87_reg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:45:20
+ |
+LL | asm!("{}", in(x87_reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: register class `mmx_reg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:47:20
+ |
+LL | asm!("{}", in(mmx_reg) foo);
+ | ^^^^^^^^^^^^^^^
+
+error: register class `x87_reg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:49:20
+ |
+LL | asm!("{}", out(x87_reg) _);
+ | ^^^^^^^^^^^^^^
+
+error: register class `mmx_reg` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:51:20
+ |
+LL | asm!("{}", out(mmx_reg) _);
+ | ^^^^^^^^^^^^^^
+
+error: register `al` conflicts with register `ax`
+ --> $DIR/bad-reg.rs:57:33
+ |
+LL | asm!("", in("eax") foo, in("al") bar);
+ | ------------- ^^^^^^^^^^^^ register `al`
+ | |
+ | register `ax`
+
+error: register `ax` conflicts with register `ax`
+ --> $DIR/bad-reg.rs:59:33
+ |
+LL | asm!("", in("rax") foo, out("rax") bar);
+ | ------------- ^^^^^^^^^^^^^^ register `ax`
+ | |
+ | register `ax`
+ |
+help: use `lateout` instead of `out` to avoid conflict
+ --> $DIR/bad-reg.rs:59:18
+ |
+LL | asm!("", in("rax") foo, out("rax") bar);
+ | ^^^^^^^^^^^^^
+
+error: register `ymm0` conflicts with register `xmm0`
+ --> $DIR/bad-reg.rs:62:34
+ |
+LL | asm!("", in("xmm0") foo, in("ymm0") bar);
+ | -------------- ^^^^^^^^^^^^^^ register `ymm0`
+ | |
+ | register `xmm0`
+
+error: register `ymm0` conflicts with register `xmm0`
+ --> $DIR/bad-reg.rs:64:34
+ |
+LL | asm!("", in("xmm0") foo, out("ymm0") bar);
+ | -------------- ^^^^^^^^^^^^^^^ register `ymm0`
+ | |
+ | register `xmm0`
+ |
+help: use `lateout` instead of `out` to avoid conflict
+ --> $DIR/bad-reg.rs:64:18
+ |
+LL | asm!("", in("xmm0") foo, out("ymm0") bar);
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors
+
--- /dev/null
+// min-llvm-version: 10.0.1
+// only-x86_64
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![feature(asm, global_asm)]
+
+fn const_generic<const X: usize>() -> usize {
+ unsafe {
+ let a: usize;
+ asm!("mov {}, {}", out(reg) a, const X);
+ a
+ }
+}
+
+const fn constfn(x: usize) -> usize {
+ x
+}
+
+fn main() {
+ unsafe {
+ let a: usize;
+ asm!("mov {}, {}", out(reg) a, const 5);
+ assert_eq!(a, 5);
+
+ let b: usize;
+ asm!("mov {}, {}", out(reg) b, const constfn(5));
+ assert_eq!(b, 5);
+
+ let c: usize;
+ asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
+ assert_eq!(c, 10);
+ }
+
+ let d = const_generic::<5>();
+ assert_eq!(d, 5);
+}
+
+global_asm!("mov eax, {}", const 5);
+global_asm!("mov eax, {}", const constfn(5));
+global_asm!("mov eax, {}", const constfn(5) + constfn(5));
--- /dev/null
+// only-x86_64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(nomem, ));
+ //~^ ERROR the `nomem` option was already provided
+ asm!("", options(att_syntax, ));
+ //~^ ERROR the `att_syntax` option was already provided
+ asm!("", options(nostack, att_syntax), options());
+ //~^ ERROR the `nostack` option was already provided
+ asm!("", options(nostack, ), options(), options());
+ //~^ ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ asm!(
+ "",
+ options(nomem, noreturn),
+ options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
+ options( nostack), //~ ERROR the `nomem` option was already provided
+ options(), //~ ERROR the `noreturn` option was already provided
+ );
+ }
+}
+
+global_asm!("", options(att_syntax, ));
+//~^ ERROR the `att_syntax` option was already provided
--- /dev/null
+// only-x86_64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ unsafe {
+ asm!("", options(nomem, nomem));
+ //~^ ERROR the `nomem` option was already provided
+ asm!("", options(att_syntax, att_syntax));
+ //~^ ERROR the `att_syntax` option was already provided
+ asm!("", options(nostack, att_syntax), options(nostack));
+ //~^ ERROR the `nostack` option was already provided
+ asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ //~^ ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ //~| ERROR the `nostack` option was already provided
+ asm!(
+ "",
+ options(nomem, noreturn),
+ options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
+ options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+ options(noreturn), //~ ERROR the `noreturn` option was already provided
+ );
+ }
+}
+
+global_asm!("", options(att_syntax, att_syntax));
+//~^ ERROR the `att_syntax` option was already provided
--- /dev/null
+error: the `nomem` option was already provided
+ --> $DIR/duplicate-options.rs:8:33
+ |
+LL | asm!("", options(nomem, nomem));
+ | ^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+ --> $DIR/duplicate-options.rs:10:38
+ |
+LL | asm!("", options(att_syntax, att_syntax));
+ | ^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:12:56
+ |
+LL | asm!("", options(nostack, att_syntax), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:35
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:53
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+ --> $DIR/duplicate-options.rs:14:71
+ |
+LL | asm!("", options(nostack, nostack), options(nostack), options(nostack));
+ | ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+ --> $DIR/duplicate-options.rs:21:33
+ |
+LL | options(att_syntax, noreturn),
+ | ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+ --> $DIR/duplicate-options.rs:22:21
+ |
+LL | options(nomem, nostack),
+ | ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+ --> $DIR/duplicate-options.rs:23:21
+ |
+LL | options(noreturn),
+ | ^^^^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+ --> $DIR/duplicate-options.rs:28:37
+ |
+LL | global_asm!("", options(att_syntax, att_syntax));
+ | ^^^^^^^^^^ this option was already provided
+
+error: aborting due to 10 previous errors
+
--- /dev/null
+// only-x86_64
+
+#![feature(asm)]
+
+macro_rules! m {
+ ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
+ $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
+ $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
+ unsafe {
+ asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+ //~^ ERROR asm outputs are not allowed with the `noreturn` option
+ const x, sym x,
+ $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+ //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+ //~| ERROR the `pure` and `noreturn` options are mutually exclusive
+ }
+ };
+}
+
+fn main() {
+ m!(in out lateout inout inlateout const sym
+ pure nomem readonly preserves_flags
+ noreturn nostack att_syntax options);
+}
--- /dev/null
+error: the `nomem` and `readonly` options are mutually exclusive
+ --> $DIR/interpolated-idents.rs:13:13
+ |
+LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / m!(in out lateout inout inlateout const sym
+LL | | pure nomem readonly preserves_flags
+LL | | noreturn nostack att_syntax options);
+ | |____________________________________________- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `pure` and `noreturn` options are mutually exclusive
+ --> $DIR/interpolated-idents.rs:13:13
+ |
+LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / m!(in out lateout inout inlateout const sym
+LL | | pure nomem readonly preserves_flags
+LL | | noreturn nostack att_syntax options);
+ | |____________________________________________- in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm outputs are not allowed with the `noreturn` option
+ --> $DIR/interpolated-idents.rs:10:32
+ |
+LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+ | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
+...
+LL | m!(in out lateout inout inlateout const sym
+ | _____-
+ | |_____|
+ | |_____|
+ | |_____|
+ | |
+LL | | pure nomem readonly preserves_flags
+LL | | noreturn nostack att_syntax options);
+ | | -
+ | |____________________________________________|
+ | |____________________________________________in this macro invocation
+ | |____________________________________________in this macro invocation
+ | |____________________________________________in this macro invocation
+ | in this macro invocation
+ |
+ = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// only-x86_64
+// Make sure rustc doesn't ICE on asm! for a foreign architecture.
+
+#![feature(asm)]
+#![crate_type = "rlib"]
+
+pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
+ let c;
+ asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+ || {};
+ b
+ });
+ //~^^^^ invalid register class
+ //~^^^^^ invalid register class
+ //~^^^^^^ invalid register
+ c
+}
+
+pub unsafe fn x86(a: f64, b: f64) -> f64 {
+ let c;
+ asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b);
+ c
+}
--- /dev/null
+error: invalid register class `vreg`: unknown register class
+ --> $DIR/issue-82869.rs:9:32
+ |
+LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+ | ^^^^^^^^^^^
+
+error: invalid register class `vreg`: unknown register class
+ --> $DIR/issue-82869.rs:9:45
+ |
+LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+ | ^^^^^^^^^^
+
+error: invalid register `d0`: unknown register
+ --> $DIR/issue-82869.rs:9:57
+ |
+LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+ | _________________________________________________________^
+LL | | || {};
+LL | | b
+LL | | });
+ | |_____^
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// only-x86_64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+ let mut foo = 0;
+ let mut bar = 0;
+ unsafe {
+ asm!();
+ //~^ ERROR requires at least a template string argument
+ asm!(foo);
+ //~^ ERROR asm template must be a string literal
+ asm!("{}" foo);
+ //~^ ERROR expected token: `,`
+ asm!("{}", foo);
+ //~^ ERROR expected operand, clobber_abi, options, or additional template string
+ asm!("{}", in foo);
+ //~^ ERROR expected `(`, found `foo`
+ asm!("{}", in(reg foo));
+ //~^ ERROR expected `)`, found `foo`
+ asm!("{}", in(reg));
+ //~^ ERROR expected expression, found end of macro arguments
+ asm!("{}", inout(=) foo => bar);
+ //~^ ERROR expected register class or explicit register
+ asm!("{}", inout(reg) foo =>);
+ //~^ ERROR expected expression, found end of macro arguments
+ asm!("{}", in(reg) foo => bar);
+ //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+ asm!("{}", sym foo + bar);
+ //~^ ERROR argument to `sym` must be a path expression
+ asm!("", options(foo));
+ //~^ ERROR expected one of
+ asm!("", options(nomem foo));
+ //~^ ERROR expected one of
+ asm!("", options(nomem, foo));
+ //~^ ERROR expected one of
+ asm!("{}", options(), const foo);
+ //~^ ERROR arguments are not allowed after options
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", clobber_abi(foo));
+ //~^ ERROR expected string literal
+ asm!("", clobber_abi("C" foo));
+ //~^ ERROR expected `)`, found `foo`
+ asm!("", clobber_abi("C", foo));
+ //~^ ERROR expected `)`, found `,`
+ asm!("{}", clobber_abi("C"), const foo);
+ //~^ ERROR arguments are not allowed after clobber_abi
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", options(), clobber_abi("C"));
+ //~^ ERROR clobber_abi is not allowed after options
+ asm!("{}", options(), clobber_abi("C"), const foo);
+ //~^ ERROR clobber_abi is not allowed after options
+ asm!("", clobber_abi("C"), clobber_abi("C"));
+ //~^ ERROR clobber_abi specified multiple times
+ asm!("{a}", a = const foo, a = const bar);
+ //~^ ERROR duplicate argument named `a`
+ //~^^ ERROR argument never used
+ //~^^^ ERROR attempt to use a non-constant value in a constant
+ //~^^^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", a = in("eax") foo);
+ //~^ ERROR explicit register arguments cannot have names
+ asm!("{a}", in("eax") foo, a = const bar);
+ //~^ ERROR named arguments cannot follow explicit register arguments
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("{a}", in("eax") foo, a = const bar);
+ //~^ ERROR named arguments cannot follow explicit register arguments
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("{1}", in("eax") foo, const bar);
+ //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+ //~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", options(), "");
+ //~^ ERROR expected one of
+ asm!("{}", in(reg) foo, "{}", out(reg) foo);
+ //~^ ERROR expected one of
+ asm!(format!("{{{}}}", 0), in(reg) foo);
+ //~^ ERROR asm template must be a string literal
+ asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+ //~^ ERROR asm template must be a string literal
+ asm!("{}", in(reg) _);
+ //~^ ERROR _ cannot be used for input operands
+ asm!("{}", inout(reg) _);
+ //~^ ERROR _ cannot be used for input operands
+ asm!("{}", inlateout(reg) _);
+ //~^ ERROR _ cannot be used for input operands
+ }
+}
+
+const FOO: i32 = 1;
+const BAR: i32 = 2;
+global_asm!();
+//~^ ERROR requires at least a template string argument
+global_asm!(FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{}" FOO);
+//~^ ERROR expected token: `,`
+global_asm!("{}", FOO);
+//~^ ERROR expected operand, options, or additional template string
+global_asm!("{}", const);
+//~^ ERROR expected expression, found end of macro arguments
+global_asm!("{}", const(reg) FOO);
+//~^ ERROR expected one of
+global_asm!("", options(FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem, FOO));
+//~^ ERROR expected one of
+global_asm!("{}", options(), const FOO);
+//~^ ERROR arguments are not allowed after options
+global_asm!("", clobber_abi(FOO));
+//~^ ERROR expected string literal
+global_asm!("", clobber_abi("C" FOO));
+//~^ ERROR expected `)`, found `FOO`
+global_asm!("", clobber_abi("C", FOO));
+//~^ ERROR expected `)`, found `,`
+global_asm!("{}", clobber_abi("C"), const FOO);
+//~^ ERROR arguments are not allowed after clobber_abi
+//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
+global_asm!("", options(), clobber_abi("C"));
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("{}", options(), clobber_abi("C"), const FOO);
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("", clobber_abi("C"), clobber_abi("C"));
+//~^ ERROR clobber_abi specified multiple times
+global_asm!("{a}", a = const FOO, a = const BAR);
+//~^ ERROR duplicate argument named `a`
+//~^^ ERROR argument never used
+global_asm!("", options(), "");
+//~^ ERROR expected one of
+global_asm!("{}", const FOO, "{}", const FOO);
+//~^ ERROR expected one of
+global_asm!(format!("{{{}}}", 0), const FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+//~^ ERROR asm template must be a string literal
--- /dev/null
+error: requires at least a template string argument
+ --> $DIR/parse-error.rs:9:9
+ |
+LL | asm!();
+ | ^^^^^^^
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:11:14
+ |
+LL | asm!(foo);
+ | ^^^
+
+error: expected token: `,`
+ --> $DIR/parse-error.rs:13:19
+ |
+LL | asm!("{}" foo);
+ | ^^^ expected `,`
+
+error: expected operand, clobber_abi, options, or additional template string
+ --> $DIR/parse-error.rs:15:20
+ |
+LL | asm!("{}", foo);
+ | ^^^ expected operand, clobber_abi, options, or additional template string
+
+error: expected `(`, found `foo`
+ --> $DIR/parse-error.rs:17:23
+ |
+LL | asm!("{}", in foo);
+ | ^^^ expected `(`
+
+error: expected `)`, found `foo`
+ --> $DIR/parse-error.rs:19:27
+ |
+LL | asm!("{}", in(reg foo));
+ | ^^^ expected `)`
+
+error: expected expression, found end of macro arguments
+ --> $DIR/parse-error.rs:21:27
+ |
+LL | asm!("{}", in(reg));
+ | ^ expected expression
+
+error: expected register class or explicit register
+ --> $DIR/parse-error.rs:23:26
+ |
+LL | asm!("{}", inout(=) foo => bar);
+ | ^
+
+error: expected expression, found end of macro arguments
+ --> $DIR/parse-error.rs:25:37
+ |
+LL | asm!("{}", inout(reg) foo =>);
+ | ^ expected expression
+
+error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+ --> $DIR/parse-error.rs:27:32
+ |
+LL | asm!("{}", in(reg) foo => bar);
+ | ^^ expected one of 7 possible tokens
+
+error: argument to `sym` must be a path expression
+ --> $DIR/parse-error.rs:29:24
+ |
+LL | asm!("{}", sym foo + bar);
+ | ^^^^^^^^^
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:31:26
+ |
+LL | asm!("", options(foo));
+ | ^^^ expected one of 9 possible tokens
+
+error: expected one of `)` or `,`, found `foo`
+ --> $DIR/parse-error.rs:33:32
+ |
+LL | asm!("", options(nomem foo));
+ | ^^^ expected one of `)` or `,`
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:35:33
+ |
+LL | asm!("", options(nomem, foo));
+ | ^^^ expected one of 9 possible tokens
+
+error: arguments are not allowed after options
+ --> $DIR/parse-error.rs:37:31
+ |
+LL | asm!("{}", options(), const foo);
+ | --------- ^^^^^^^^^ argument
+ | |
+ | previous options
+
+error: expected string literal
+ --> $DIR/parse-error.rs:40:30
+ |
+LL | asm!("", clobber_abi(foo));
+ | ^^^ not a string literal
+
+error: expected `)`, found `foo`
+ --> $DIR/parse-error.rs:42:34
+ |
+LL | asm!("", clobber_abi("C" foo));
+ | ^^^ expected `)`
+
+error: expected `)`, found `,`
+ --> $DIR/parse-error.rs:44:33
+ |
+LL | asm!("", clobber_abi("C", foo));
+ | ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+ --> $DIR/parse-error.rs:46:38
+ |
+LL | asm!("{}", clobber_abi("C"), const foo);
+ | ---------------- ^^^^^^^^^ argument
+ | |
+ | clobber_abi
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:49:29
+ |
+LL | asm!("", options(), clobber_abi("C"));
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:51:31
+ |
+LL | asm!("{}", options(), clobber_abi("C"), const foo);
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi specified multiple times
+ --> $DIR/parse-error.rs:53:36
+ |
+LL | asm!("", clobber_abi("C"), clobber_abi("C"));
+ | ---------------- ^^^^^^^^^^^^^^^^
+ | |
+ | clobber_abi previously specified here
+
+error: duplicate argument named `a`
+ --> $DIR/parse-error.rs:55:36
+ |
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ------------- ^^^^^^^^^^^^^ duplicate argument
+ | |
+ | previously here
+
+error: argument never used
+ --> $DIR/parse-error.rs:55:36
+ |
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ^^^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: explicit register arguments cannot have names
+ --> $DIR/parse-error.rs:60:18
+ |
+LL | asm!("", a = in("eax") foo);
+ | ^^^^^^^^^^^^^^^^^
+
+error: named arguments cannot follow explicit register arguments
+ --> $DIR/parse-error.rs:62:36
+ |
+LL | asm!("{a}", in("eax") foo, a = const bar);
+ | ------------- ^^^^^^^^^^^^^ named argument
+ | |
+ | explicit register argument
+
+error: named arguments cannot follow explicit register arguments
+ --> $DIR/parse-error.rs:65:36
+ |
+LL | asm!("{a}", in("eax") foo, a = const bar);
+ | ------------- ^^^^^^^^^^^^^ named argument
+ | |
+ | explicit register argument
+
+error: positional arguments cannot follow named arguments or explicit register arguments
+ --> $DIR/parse-error.rs:68:36
+ |
+LL | asm!("{1}", in("eax") foo, const bar);
+ | ------------- ^^^^^^^^^ positional argument
+ | |
+ | explicit register argument
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
+ --> $DIR/parse-error.rs:71:29
+ |
+LL | asm!("", options(), "");
+ | ^^ expected one of 9 possible tokens
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
+ --> $DIR/parse-error.rs:73:33
+ |
+LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
+ | ^^^^ expected one of 9 possible tokens
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:75:14
+ |
+LL | asm!(format!("{{{}}}", 0), in(reg) foo);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:77:21
+ |
+LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: _ cannot be used for input operands
+ --> $DIR/parse-error.rs:79:28
+ |
+LL | asm!("{}", in(reg) _);
+ | ^
+
+error: _ cannot be used for input operands
+ --> $DIR/parse-error.rs:81:31
+ |
+LL | asm!("{}", inout(reg) _);
+ | ^
+
+error: _ cannot be used for input operands
+ --> $DIR/parse-error.rs:83:35
+ |
+LL | asm!("{}", inlateout(reg) _);
+ | ^
+
+error: requires at least a template string argument
+ --> $DIR/parse-error.rs:90:1
+ |
+LL | global_asm!();
+ | ^^^^^^^^^^^^^^
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:92:13
+ |
+LL | global_asm!(FOO);
+ | ^^^
+
+error: expected token: `,`
+ --> $DIR/parse-error.rs:94:18
+ |
+LL | global_asm!("{}" FOO);
+ | ^^^ expected `,`
+
+error: expected operand, options, or additional template string
+ --> $DIR/parse-error.rs:96:19
+ |
+LL | global_asm!("{}", FOO);
+ | ^^^ expected operand, options, or additional template string
+
+error: expected expression, found end of macro arguments
+ --> $DIR/parse-error.rs:98:24
+ |
+LL | global_asm!("{}", const);
+ | ^ expected expression
+
+error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
+ --> $DIR/parse-error.rs:100:30
+ |
+LL | global_asm!("{}", const(reg) FOO);
+ | ^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+ --> $DIR/parse-error.rs:102:25
+ |
+LL | global_asm!("", options(FOO));
+ | ^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:104:25
+ |
+LL | global_asm!("", options(nomem FOO));
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:106:25
+ |
+LL | global_asm!("", options(nomem, FOO));
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: arguments are not allowed after options
+ --> $DIR/parse-error.rs:108:30
+ |
+LL | global_asm!("{}", options(), const FOO);
+ | --------- ^^^^^^^^^ argument
+ | |
+ | previous options
+
+error: expected string literal
+ --> $DIR/parse-error.rs:110:29
+ |
+LL | global_asm!("", clobber_abi(FOO));
+ | ^^^ not a string literal
+
+error: expected `)`, found `FOO`
+ --> $DIR/parse-error.rs:112:33
+ |
+LL | global_asm!("", clobber_abi("C" FOO));
+ | ^^^ expected `)`
+
+error: expected `)`, found `,`
+ --> $DIR/parse-error.rs:114:32
+ |
+LL | global_asm!("", clobber_abi("C", FOO));
+ | ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+ --> $DIR/parse-error.rs:116:37
+ |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+ | ---------------- ^^^^^^^^^ argument
+ | |
+ | clobber_abi
+
+error: `clobber_abi` cannot be used with `global_asm!`
+ --> $DIR/parse-error.rs:116:19
+ |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+ | ^^^^^^^^^^^^^^^^
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:119:28
+ |
+LL | global_asm!("", options(), clobber_abi("C"));
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi is not allowed after options
+ --> $DIR/parse-error.rs:121:30
+ |
+LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
+ | --------- ^^^^^^^^^^^^^^^^
+ | |
+ | options
+
+error: clobber_abi specified multiple times
+ --> $DIR/parse-error.rs:123:35
+ |
+LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
+ | ---------------- ^^^^^^^^^^^^^^^^
+ | |
+ | clobber_abi previously specified here
+
+error: duplicate argument named `a`
+ --> $DIR/parse-error.rs:125:35
+ |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+ | ------------- ^^^^^^^^^^^^^ duplicate argument
+ | |
+ | previously here
+
+error: argument never used
+ --> $DIR/parse-error.rs:125:35
+ |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+ | ^^^^^^^^^^^^^ argument never used
+ |
+ = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `""`
+ --> $DIR/parse-error.rs:128:28
+ |
+LL | global_asm!("", options(), "");
+ | ^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
+ --> $DIR/parse-error.rs:130:30
+ |
+LL | global_asm!("{}", const FOO, "{}", const FOO);
+ | ^^^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:132:13
+ |
+LL | global_asm!(format!("{{{}}}", 0), const FOO);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+ --> $DIR/parse-error.rs:134:20
+ |
+LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:37:37
+ |
+LL | let mut foo = 0;
+ | ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL | asm!("{}", options(), const foo);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:46:44
+ |
+LL | let mut foo = 0;
+ | ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL | asm!("{}", clobber_abi("C"), const foo);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:55:31
+ |
+LL | let mut foo = 0;
+ | ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:55:46
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{a}", a = const foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:62:46
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{a}", in("eax") foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:65:46
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{a}", in("eax") foo, a = const bar);
+ | ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/parse-error.rs:68:42
+ |
+LL | let mut bar = 0;
+ | ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL | asm!("{1}", in("eax") foo, const bar);
+ | ^^^ non-constant value
+
+error: aborting due to 66 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
--- /dev/null
+// min-llvm-version: 10.0.1
+// only-x86_64
+// build-fail
+// compile-flags: -Ccodegen-units=1
+#![feature(asm)]
+
+// Checks that inline asm errors are mapped to the correct line in the source code.
+
+fn main() {
+ unsafe {
+ asm!("invalid_instruction");
+ //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!("
+ invalid_instruction
+ ");
+ //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(r#"
+ invalid_instruction
+ "#);
+ //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!("
+ mov eax, eax
+ invalid_instruction
+ mov eax, eax
+ ");
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(r#"
+ mov eax, eax
+ invalid_instruction
+ mov eax, eax
+ "#);
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(concat!("invalid", "_", "instruction"));
+ //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
+ //~^ WARN: scale factor without index register is ignored
+
+ asm!(
+ "invalid_instruction",
+ );
+ //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ "mov eax, eax",
+ "invalid_instruction",
+ "mov eax, eax",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ "mov eax, eax\n",
+ "invalid_instruction",
+ "mov eax, eax",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ "mov eax, eax",
+ concat!("invalid", "_", "instruction"),
+ "mov eax, eax",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ asm!(
+ concat!("mov eax", ", ", "eax"),
+ concat!("invalid", "_", "instruction"),
+ concat!("mov eax", ", ", "eax"),
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+ // Make sure template strings get separated
+ asm!(
+ "invalid_instruction1",
+ "invalid_instruction2",
+ );
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2",
+ ),
+ );
+ //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2",
+ ),
+ concat!(
+ "invalid", "_", "instruction3", "\n",
+ "invalid", "_", "instruction4",
+ ),
+ );
+ //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+ //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+ //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+
+ asm!(
+ concat!(
+ "invalid", "_", "instruction1", "\n",
+ "invalid", "_", "instruction2", "\n",
+ ),
+ concat!(
+ "invalid", "_", "instruction3", "\n",
+ "invalid", "_", "instruction4", "\n",
+ ),
+ );
+ //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+ //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+ //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+ //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+ }
+}
--- /dev/null
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:11:15
+ |
+LL | asm!("invalid_instruction");
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:15:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:13
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:20:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:13
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:26:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:13
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:33:13
+ |
+LL | invalid_instruction
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:13
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:38:14
+ |
+LL | asm!(concat!("invalid", "_", "instruction"));
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+warning: scale factor without index register is ignored
+ --> $DIR/srcloc.rs:41:15
+ |
+LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:23
+ |
+LL | movaps %xmm3, (%esi, 2)
+ | ^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:45:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:51:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:58:14
+ |
+LL | "invalid_instruction",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:65:13
+ |
+LL | concat!("invalid", "_", "instruction"),
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+ --> $DIR/srcloc.rs:72:13
+ |
+LL | concat!("invalid", "_", "instruction"),
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:79:14
+ |
+LL | "invalid_instruction1",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:80:14
+ |
+LL | "invalid_instruction2",
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:86:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:86:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:95:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:95:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+ --> $DIR/srcloc.rs:99:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:4:1
+ |
+LL | invalid_instruction3
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+ --> $DIR/srcloc.rs:99:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:5:1
+ |
+LL | invalid_instruction4
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+ --> $DIR/srcloc.rs:110:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:2:2
+ |
+LL | invalid_instruction1
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+ --> $DIR/srcloc.rs:110:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:3:1
+ |
+LL | invalid_instruction2
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+ --> $DIR/srcloc.rs:114:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:5:1
+ |
+LL | invalid_instruction3
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+ --> $DIR/srcloc.rs:114:13
+ |
+LL | concat!(
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:6:1
+ |
+LL | invalid_instruction4
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors; 1 warning emitted
+
--- /dev/null
+// min-llvm-version: 10.0.1
+// only-x86_64
+// only-linux
+// run-pass
+
+#![feature(asm, thread_local)]
+
+extern "C" fn f1() -> i32 {
+ 111
+}
+
+// The compiler will generate a shim to hide the caller location parameter.
+#[track_caller]
+fn f2() -> i32 {
+ 222
+}
+
+macro_rules! call {
+ ($func:path) => {
+ unsafe {
+ let result: i32;
+ asm!("call {}", sym $func,
+ out("rax") result,
+ out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
+ out("r8") _, out("r9") _, out("r10") _, out("r11") _,
+ out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
+ out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
+ out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
+ out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
+ );
+ result
+ }
+ }
+}
+
+macro_rules! static_addr {
+ ($s:expr) => {
+ unsafe {
+ let result: *const u32;
+ // LEA performs a RIP-relative address calculation and returns the address
+ asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
+ result
+ }
+ }
+}
+macro_rules! static_tls_addr {
+ ($s:expr) => {
+ unsafe {
+ let result: *const u32;
+ asm!(
+ "
+ # Load TLS base address
+ mov {out}, qword ptr fs:[0]
+ # Calculate the address of sym in the TLS block. The @tpoff
+ # relocation gives the offset of the symbol from the start
+ # of the TLS block.
+ lea {out}, [{out} + {sym}@tpoff]
+ ",
+ out = out(reg) result,
+ sym = sym $s
+ );
+ result
+ }
+ }
+}
+
+static S1: u32 = 111;
+#[thread_local]
+static S2: u32 = 222;
+
+fn main() {
+ assert_eq!(call!(f1), 111);
+ assert_eq!(call!(f2), 222);
+ assert_eq!(static_addr!(S1), &S1 as *const u32);
+ assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+ std::thread::spawn(|| {
+ assert_eq!(static_addr!(S1), &S1 as *const u32);
+ assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+ }).join().unwrap();
+}
--- /dev/null
+// only-x86_64
+
+#![feature(asm, repr_simd, never_type)]
+
+#[repr(simd)]
+struct SimdNonCopy(f32, f32, f32, f32);
+
+fn main() {
+ unsafe {
+ // Inputs must be initialized
+
+ let x: u64;
+ asm!("{}", in(reg) x);
+ //~^ ERROR use of possibly-uninitialized variable: `x`
+ let mut y: u64;
+ asm!("{}", inout(reg) y);
+ //~^ ERROR use of possibly-uninitialized variable: `y`
+ let _ = y;
+
+ // Outputs require mutable places
+
+ let v: Vec<u64> = vec![0, 1, 2];
+ asm!("{}", in(reg) v[0]);
+ asm!("{}", out(reg) v[0]);
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+ asm!("{}", inout(reg) v[0]);
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+
+ // Sym operands must point to a function or static
+
+ const C: i32 = 0;
+ static S: i32 = 0;
+ asm!("{}", sym S);
+ asm!("{}", sym main);
+ asm!("{}", sym C);
+ //~^ ERROR asm `sym` operand must point to a fn or static
+ asm!("{}", sym x);
+ //~^ ERROR asm `sym` operand must point to a fn or static
+
+ // Register operands must be Copy
+
+ asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+ //~^ ERROR arguments for inline assembly must be copyable
+
+ // Register operands must be integers, floats, SIMD vectors, pointers or
+ // function pointers.
+
+ asm!("{}", in(reg) 0i64);
+ asm!("{}", in(reg) 0f64);
+ asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps());
+ asm!("{}", in(reg) 0 as *const u8);
+ asm!("{}", in(reg) 0 as *mut u8);
+ asm!("{}", in(reg) main as fn());
+ asm!("{}", in(reg) |x: i32| x);
+ //~^ ERROR cannot use value of type
+ asm!("{}", in(reg) vec![0]);
+ //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly
+ asm!("{}", in(reg) (1, 2, 3));
+ //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly
+ asm!("{}", in(reg) [1, 2, 3]);
+ //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly
+
+ // Register inputs (but not outputs) allow references and function types
+
+ let mut f = main;
+ let mut r = &mut 0;
+ asm!("{}", in(reg) f);
+ asm!("{}", inout(reg) f);
+ //~^ ERROR cannot use value of type `fn() {main}` for inline assembly
+ asm!("{}", in(reg) r);
+ asm!("{}", inout(reg) r);
+ //~^ ERROR cannot use value of type `&mut i32` for inline assembly
+ let _ = (f, r);
+
+ // Type checks ignore never type
+
+ let u: ! = unreachable!();
+ asm!("{}", in(reg) u);
+ }
+}
--- /dev/null
+error: arguments for inline assembly must be copyable
+ --> $DIR/type-check-2.rs:42:32
+ |
+LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `SimdNonCopy` does not implement the Copy trait
+
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly
+ --> $DIR/type-check-2.rs:54:28
+ |
+LL | asm!("{}", in(reg) |x: i32| x);
+ | ^^^^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `Vec<i32>` for inline assembly
+ --> $DIR/type-check-2.rs:56:28
+ |
+LL | asm!("{}", in(reg) vec![0]);
+ | ^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+ = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot use value of type `(i32, i32, i32)` for inline assembly
+ --> $DIR/type-check-2.rs:58:28
+ |
+LL | asm!("{}", in(reg) (1, 2, 3));
+ | ^^^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `[i32; 3]` for inline assembly
+ --> $DIR/type-check-2.rs:60:28
+ |
+LL | asm!("{}", in(reg) [1, 2, 3]);
+ | ^^^^^^^^^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `fn() {main}` for inline assembly
+ --> $DIR/type-check-2.rs:68:31
+ |
+LL | asm!("{}", inout(reg) f);
+ | ^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `&mut i32` for inline assembly
+ --> $DIR/type-check-2.rs:71:31
+ |
+LL | asm!("{}", inout(reg) r);
+ | ^
+ |
+ = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: asm `sym` operand must point to a fn or static
+ --> $DIR/type-check-2.rs:35:24
+ |
+LL | asm!("{}", sym C);
+ | ^
+
+error: asm `sym` operand must point to a fn or static
+ --> $DIR/type-check-2.rs:37:24
+ |
+LL | asm!("{}", sym x);
+ | ^
+
+error[E0381]: use of possibly-uninitialized variable: `x`
+ --> $DIR/type-check-2.rs:13:28
+ |
+LL | asm!("{}", in(reg) x);
+ | ^ use of possibly-uninitialized `x`
+
+error[E0381]: use of possibly-uninitialized variable: `y`
+ --> $DIR/type-check-2.rs:16:9
+ |
+LL | asm!("{}", inout(reg) y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/type-check-2.rs:24:29
+ |
+LL | let v: Vec<u64> = vec![0, 1, 2];
+ | - help: consider changing this to be mutable: `mut v`
+LL | asm!("{}", in(reg) v[0]);
+LL | asm!("{}", out(reg) v[0]);
+ | ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/type-check-2.rs:26:31
+ |
+LL | let v: Vec<u64> = vec![0, 1, 2];
+ | - help: consider changing this to be mutable: `mut v`
+...
+LL | asm!("{}", inout(reg) v[0]);
+ | ^ cannot borrow as mutable
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0381, E0596.
+For more information about an error, try `rustc --explain E0381`.
--- /dev/null
+// only-x86_64
+// compile-flags: -C target-feature=+avx512f
+
+#![feature(asm, global_asm)]
+
+use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
+
+fn main() {
+ unsafe {
+ // Types must be listed in the register class.
+
+ asm!("{}", in(reg) 0i128);
+ //~^ ERROR type `i128` cannot be used with this register class
+ asm!("{}", in(reg) _mm_setzero_ps());
+ //~^ ERROR type `__m128` cannot be used with this register class
+ asm!("{}", in(reg) _mm256_setzero_ps());
+ //~^ ERROR type `__m256` cannot be used with this register class
+ asm!("{}", in(xmm_reg) 0u8);
+ //~^ ERROR type `u8` cannot be used with this register class
+ asm!("{:e}", in(reg) 0i32);
+ asm!("{}", in(xmm_reg) 0i32);
+ asm!("{:e}", in(reg) 0f32);
+ asm!("{}", in(xmm_reg) 0f32);
+ asm!("{}", in(xmm_reg) _mm_setzero_ps());
+ asm!("{:x}", in(ymm_reg) _mm_setzero_ps());
+ asm!("{}", in(kreg) 0u16);
+ asm!("{}", in(kreg) 0u64);
+ //~^ ERROR `avx512bw` target feature is not enabled
+
+ // Template modifier suggestions for sub-registers
+
+ asm!("{0} {0}", in(reg) 0i16);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{0} {0:x}", in(reg) 0i16);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(reg) 0i32);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(reg) 0i64);
+ asm!("{}", in(ymm_reg) 0i64);
+ //~^ WARN formatting may not be suitable for sub-register argument
+ asm!("{}", in(ymm_reg) _mm256_setzero_ps());
+ asm!("{:l}", in(reg) 0i16);
+ asm!("{:l}", in(reg) 0i32);
+ asm!("{:l}", in(reg) 0i64);
+ asm!("{:x}", in(ymm_reg) 0i64);
+ asm!("{:x}", in(ymm_reg) _mm256_setzero_ps());
+
+ // Suggest different register class for type
+
+ asm!("{}", in(reg) 0i8);
+ //~^ ERROR type `i8` cannot be used with this register class
+ asm!("{}", in(reg_byte) 0i8);
+
+ // Split inout operands must have compatible types
+
+ let mut val_i16: i16;
+ let mut val_f32: f32;
+ let mut val_u32: u32;
+ let mut val_u64: u64;
+ let mut val_ptr: *mut u8;
+ asm!("{:r}", inout(reg) 0u16 => val_i16);
+ asm!("{:r}", inout(reg) 0u32 => val_f32);
+ //~^ ERROR incompatible types for asm inout argument
+ asm!("{:r}", inout(reg) 0u32 => val_ptr);
+ //~^ ERROR incompatible types for asm inout argument
+ asm!("{:r}", inout(reg) main => val_u32);
+ //~^ ERROR incompatible types for asm inout argument
+ asm!("{:r}", inout(reg) 0u64 => val_ptr);
+ asm!("{:r}", inout(reg) main => val_u64);
+ }
+}
+
+// Constants must be... constant
+
+static S: i32 = 1;
+const fn const_foo(x: i32) -> i32 {
+ x
+}
+const fn const_bar<T>(x: T) -> T {
+ x
+}
+global_asm!("{}", const S);
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_foo(0));
+global_asm!("{}", const const_foo(S));
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_bar(0));
+global_asm!("{}", const const_bar(S));
+//~^ ERROR constants cannot refer to statics
--- /dev/null
+error: type `i128` cannot be used with this register class
+ --> $DIR/type-check-3.rs:12:28
+ |
+LL | asm!("{}", in(reg) 0i128);
+ | ^^^^^
+ |
+ = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+
+error: type `__m128` cannot be used with this register class
+ --> $DIR/type-check-3.rs:14:28
+ |
+LL | asm!("{}", in(reg) _mm_setzero_ps());
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+
+error: type `__m256` cannot be used with this register class
+ --> $DIR/type-check-3.rs:16:28
+ |
+LL | asm!("{}", in(reg) _mm256_setzero_ps());
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+
+error: type `u8` cannot be used with this register class
+ --> $DIR/type-check-3.rs:18:32
+ |
+LL | asm!("{}", in(xmm_reg) 0u8);
+ | ^^^
+ |
+ = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: `avx512bw` target feature is not enabled
+ --> $DIR/type-check-3.rs:27:29
+ |
+LL | asm!("{}", in(kreg) 0u64);
+ | ^^^^
+ |
+ = note: this is required to use type `u64` with register class `kreg`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:32:15
+ |
+LL | asm!("{0} {0}", in(reg) 0i16);
+ | ^^^ ^^^ ---- for this argument
+ |
+ = note: `#[warn(asm_sub_register)]` on by default
+ = help: use the `x` modifier to have the register formatted as `ax`
+ = help: or use the `r` modifier to keep the default formatting of `rax`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:34:15
+ |
+LL | asm!("{0} {0:x}", in(reg) 0i16);
+ | ^^^ ---- for this argument
+ |
+ = help: use the `x` modifier to have the register formatted as `ax`
+ = help: or use the `r` modifier to keep the default formatting of `rax`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:36:15
+ |
+LL | asm!("{}", in(reg) 0i32);
+ | ^^ ---- for this argument
+ |
+ = help: use the `e` modifier to have the register formatted as `eax`
+ = help: or use the `r` modifier to keep the default formatting of `rax`
+
+warning: formatting may not be suitable for sub-register argument
+ --> $DIR/type-check-3.rs:39:15
+ |
+LL | asm!("{}", in(ymm_reg) 0i64);
+ | ^^ ---- for this argument
+ |
+ = help: use the `x` modifier to have the register formatted as `xmm0`
+ = help: or use the `y` modifier to keep the default formatting of `ymm0`
+
+error: type `i8` cannot be used with this register class
+ --> $DIR/type-check-3.rs:50:28
+ |
+LL | asm!("{}", in(reg) 0i8);
+ | ^^^
+ |
+ = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+ = help: consider using the `reg_byte` register class instead
+
+error: incompatible types for asm inout argument
+ --> $DIR/type-check-3.rs:62:33
+ |
+LL | asm!("{:r}", inout(reg) 0u32 => val_f32);
+ | ^^^^ ^^^^^^^ type `f32`
+ | |
+ | type `u32`
+ |
+ = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+ --> $DIR/type-check-3.rs:64:33
+ |
+LL | asm!("{:r}", inout(reg) 0u32 => val_ptr);
+ | ^^^^ ^^^^^^^ type `*mut u8`
+ | |
+ | type `u32`
+ |
+ = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+ --> $DIR/type-check-3.rs:66:33
+ |
+LL | asm!("{:r}", inout(reg) main => val_u32);
+ | ^^^^ ^^^^^^^ type `u32`
+ | |
+ | type `fn()`
+ |
+ = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/type-check-3.rs:82:25
+ |
+LL | global_asm!("{}", const S);
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/type-check-3.rs:85:35
+ |
+LL | global_asm!("{}", const const_foo(S));
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+ --> $DIR/type-check-3.rs:88:35
+ |
+LL | global_asm!("{}", const const_bar(S));
+ | ^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to 12 previous errors; 4 warnings emitted
+
+For more information about this error, try `rustc --explain E0013`.
// check-pass
-// compile-flags:-Cincremental=tmp/traits-assoc-type-macros
+// incremental
// This test case makes sure that we can compile with incremental compilation
// enabled when there are macros, traits, inheritance and associated types involved.
// run-pass
-#![feature(box_syntax)]
fn pairwise_sub(mut t: Box<dyn DoubleEndedIterator<Item=isize>>) -> isize {
let mut result = 0;
|
= note: expected reference `&'a ()`
found reference `&()`
+note: the lifetime requirement is introduced here
+ --> $DIR/higher-ranked-projection.rs:15:33
+ |
+LL | where for<'a> &'a T: Mirror<Image=U>
+ | ^^^^^^^
error: aborting due to previous error
// edition:2018
-// compile-flags:-Cincremental=tmp/issue-72442
+// incremental
use std::fs::File;
use std::future::Future;
// check-pass
-// compile-flags: -Z query-dep-graph -C incremental=tmp/issue-64964
+// incremental
+// compile-flags: -Z query-dep-graph
// edition:2018
// Regression test for ICE related to `await`ing in a method + incr. comp. (#64964)
--> $DIR/register-attr-tool-fail.rs:4:1
|
LL | #![register_attr]
- | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_attr(attr1, attr2, ...)]`
+ | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_attr(attr1, attr2, ...)]`
error: malformed `register_tool` attribute input
--> $DIR/register-attr-tool-fail.rs:5:1
|
LL | #![register_tool]
- | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_tool(tool1, tool2, ...)]`
+ | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_tool(tool1, tool2, ...)]`
error: aborting due to 6 previous errors
-#![feature(box_syntax)]
-
struct Clam {
x: Box<isize>,
y: Box<isize>,
}
+
+
struct Fish {
a: Box<isize>,
}
fn main() {
- let a: Clam = Clam{x: box 1, y: box 2};
- let b: Clam = Clam{x: box 10, y: box 20};
+ let a: Clam = Clam{ x: Box::new(1), y: Box::new(2) };
+ let b: Clam = Clam{ x: Box::new(10), y: Box::new(20) };
let z: isize = a.x + b.y;
//~^ ERROR cannot add `Box<isize>` to `Box<isize>`
println!("{}", z);
assert_eq!(z, 21);
- let forty: Fish = Fish{a: box 40};
- let two: Fish = Fish{a: box 2};
+ let forty: Fish = Fish{ a: Box::new(40) };
+ let two: Fish = Fish{ a: Box::new(2) };
let answer: isize = forty.a + two.a;
//~^ ERROR cannot add `Box<isize>` to `Box<isize>`
println!("{}", answer);
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
trait double {
fn double(self: Box<Self>) -> usize;
}
pub fn main() {
- let x: Box<_> = box (box 3usize as Box<dyn double>);
+ let x: Box<_> = Box::new(Box::new(3usize) as Box<dyn double>);
assert_eq!(x.double(), 6);
}
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
trait double {
fn double(self) -> usize;
}
pub fn main() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
assert_eq!(x.double(), 6);
}
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
trait double {
fn double(self: Box<Self>) -> usize;
}
pub fn main() {
- let x: Box<Box<Box<Box<Box<_>>>>> = box box box box box 3;
+ let x: Box<Box<Box<Box<Box<_>>>>> = Box::new(Box::new(Box::new(Box::new(Box::new(3)))));
assert_eq!(x.double(), 6);
}
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
trait double {
fn double(self: Box<Self>) -> usize;
}
pub fn main() {
- let x: Box<Box<_>> = box box 3;
+ let x: Box<Box<_>> = Box::new(Box::new(3));
assert_eq!(x.double(), 6);
}
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
trait double {
fn double(self: Box<Self>) -> usize;
}
pub fn main() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
assert_eq!(x.double(), 6);
}
// run-pass
-#![feature(box_syntax)]
trait Foo {
fn foo(&self) -> String;
}
pub fn main() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
assert_eq!(x.foo(), "box 3".to_string());
}
// run-pass
-#![feature(box_syntax)]
fn test_generic<T: Clone, F>(expected: Box<T>, eq: F) where F: FnOnce(Box<T>, Box<T>) -> bool {
let actual: Box<T> = match true {
fn compare_box(b1: Box<bool>, b2: Box<bool>) -> bool {
return *b1 == *b2;
}
- test_generic::<bool, _>(box true, compare_box);
+ test_generic::<bool, _>(Box::new(true), compare_box);
}
pub fn main() { test_box(); }
// run-pass
-#![feature(box_syntax)]
fn test_generic<T: Clone, F>(expected: T, eq: F) where F: FnOnce(T, T) -> bool {
let actual: T = match true {
fn test_vec() {
fn compare_box(v1: Box<isize>, v2: Box<isize>) -> bool { return v1 == v2; }
- test_generic::<Box<isize>, _>(box 1, compare_box);
+ test_generic::<Box<isize>, _>(Box::new(1), compare_box);
}
pub fn main() { test_vec(); }
// run-pass
-#![feature(box_syntax)]
// Tests for match as expressions resulting in boxed types
fn test_box() {
- let res: Box<_> = match true { true => { box 100 }, _ => panic!() };
+ let res: Box<_> = match true { true => { Box::new(100) }, _ => panic!() };
assert_eq!(*res, 100);
}
// Test that we do not leak when the arg pattern must drop part of the
// argument (in this case, the `y` field).
-#![feature(box_syntax)]
-
struct Foo {
x: Box<usize>,
y: Box<usize>,
}
pub fn main() {
- let obj: Box<_> = box 1;
+ let obj: Box<_> = Box::new(1);
let objptr: *const usize = &*obj;
- let f = Foo {x: obj, y: box 2};
+ let f = Foo { x: obj, y: Box::new(2) };
let xptr = foo(f);
assert_eq!(objptr, xptr);
}
// pattern.
#![feature(box_patterns)]
-#![feature(box_syntax)]
fn getaddr(box ref x: Box<usize>) -> *const usize {
let addr: *const usize = &*x;
}
pub fn main() {
- let obj: Box<_> = box 1;
+ let obj: Box<_> = Box::new(1);
let objptr: *const usize = &*obj;
let xptr = getaddr(obj);
assert_eq!(objptr, xptr);
- let obj = box 22;
+ let obj = Box::new(22);
assert_eq!(checkval(obj), 22);
}
// run-pass
-#![feature(box_syntax)]
fn f() {
- let a: Box<_> = box 1;
+ let a: Box<_> = Box::new(1);
let b: &isize = &*a;
println!("{}", b);
}
// run-pass
#![allow(non_shorthand_field_patterns)]
-#![feature(box_syntax)]
struct Pair { a: Box<isize>, b: Box<isize> }
pub fn main() {
- let mut x: Box<_> = box Pair {a: box 10, b: box 20};
+ let mut x: Box<_> = Box::new(Pair { a: Box::new(10), b: Box::new(20) });
let x_internal = &mut *x;
match *x_internal {
Pair {a: ref mut a, b: ref mut _b} => {
assert_eq!(**a, 10);
- *a = box 30;
+ *a = Box::new(30);
assert_eq!(**a, 30);
}
}
// run-pass
#![feature(box_patterns)]
-#![feature(box_syntax)]
pub fn main() {
- match box 100 {
+ match Box::new(100) {
box x => {
println!("{}", x);
assert_eq!(x, 100);
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
fn foo(x: Option<Box<isize>>, b: bool) -> isize {
match x {
None => { 1 }
}
pub fn main() {
- foo(Some(box 22), true);
- foo(Some(box 22), false);
+ foo(Some(Box::new(22)), true);
+ foo(Some(Box::new(22)), false);
foo(None, true);
foo(None, false);
}
-#![feature(box_syntax)]
+struct Foo(Box<isize>, isize);
+
+struct Bar(isize, isize);
-struct Foo(Box<isize>, isize);
-struct Bar(isize, isize);
fn main() {
- let x: (Box<_>, _) = (box 1, 2);
+ let x: (Box<_>, _) = (Box::new(1), 2);
let r = &x.0;
let y = x; //~ ERROR cannot move out of `x` because it is borrowed
let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
a.use_ref();
- let x = Foo(box 1, 2);
+ let x = Foo(Box::new(1), 2);
let r = &x.0;
let y = x; //~ ERROR cannot move out of `x` because it is borrowed
r.use_ref();
// Test that we detect nested calls that could free pointers evaluated
// for earlier arguments.
-#![feature(box_syntax)]
+
fn rewrite(v: &mut Box<usize>) -> usize {
- *v = box 22;
+ *v = Box::new(22);
**v
}
}
fn implicit() {
- let mut a: Box<_> = box 1;
+ let mut a: Box<_> = Box::new(1);
// Note the danger here:
//
}
fn explicit() {
- let mut a: Box<_> = box 1;
+ let mut a: Box<_> = Box::new(1);
add(
&*a,
rewrite(&mut a)); //~ ERROR cannot borrow
// Test that we detect nested calls that could free pointers evaluated
// for earlier arguments.
-#![feature(box_syntax)]
+
fn rewrite(v: &mut Box<usize>) -> usize {
- *v = box 22;
+ *v = Box::new(22);
**v
}
}
fn implicit() {
- let mut a: Box<_> = box 1;
+ let mut a: Box<_> = Box::new(1);
// Note the danger here:
//
}
fn explicit() {
- let mut a: Box<_> = box 1;
+ let mut a: Box<_> = Box::new(1);
add(
&*a,
a); //~ ERROR cannot move
// run-pass
-#![feature(box_syntax)]
fn borrow<F>(x: &isize, f: F) where F: FnOnce(&isize) {
f(x)
}
pub fn main() {
- test1(&box 22);
+ test1(&Box::new(22));
}
-#![feature(box_syntax)]
-
struct A;
impl A {
}
}
+
+
pub fn main() {
- let a: Box<_> = box A;
+ let a: Box<_> = Box::new(A);
a.foo();
//~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596]
}
error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
--> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
|
-LL | let a: Box<_> = box A;
+LL | let a: Box<_> = Box::new(A);
| - help: consider changing this to be mutable: `mut a`
LL | a.foo();
| ^ cannot borrow as mutable
-//buggy.rs
+use std::collections::HashMap;
+
+
-#![feature(box_syntax)]
-use std::collections::HashMap;
fn main() {
let tmp: Box<_>;
buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed
// but it is ok if we use a temporary
- tmp = box 2;
+ tmp = Box::new(2);
buggy_map.insert(43, &*tmp);
}
// run-pass
-#![feature(box_syntax)]
-
struct A {
x: Box<isize>,
y: isize,
}
fn copy_after_move() {
- let a: Box<_> = box A { x: box 0, y: 1 };
+ let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
let _x = a.x;
let _y = a.y;
}
fn move_after_move() {
- let a: Box<_> = box B { x: box 0, y: box 1 };
+ let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
let _x = a.x;
let _y = a.y;
}
fn borrow_after_move() {
- let a: Box<_> = box A { x: box 0, y: 1 };
+ let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
let _x = a.x;
let _y = &a.y;
}
fn move_after_borrow() {
- let a: Box<_> = box B { x: box 0, y: box 1 };
+ let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
let _x = &a.x;
let _y = a.y;
use_imm(_x);
}
fn copy_after_mut_borrow() {
- let mut a: Box<_> = box A { x: box 0, y: 1 };
+ let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
let _x = &mut a.x;
let _y = a.y;
use_mut(_x);
}
fn move_after_mut_borrow() {
- let mut a: Box<_> = box B { x: box 0, y: box 1 };
+ let mut a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
let _x = &mut a.x;
let _y = a.y;
use_mut(_x);
}
fn borrow_after_mut_borrow() {
- let mut a: Box<_> = box A { x: box 0, y: 1 };
+ let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
let _x = &mut a.x;
let _y = &a.y;
use_mut(_x);
}
fn mut_borrow_after_borrow() {
- let mut a: Box<_> = box A { x: box 0, y: 1 };
+ let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
let _x = &a.x;
let _y = &mut a.y;
use_imm(_x);
}
fn copy_after_move_nested() {
- let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+ let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
let _x = a.x.x;
let _y = a.y;
}
fn move_after_move_nested() {
- let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
+ let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
let _x = a.x.x;
let _y = a.y;
}
fn borrow_after_move_nested() {
- let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+ let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
let _x = a.x.x;
let _y = &a.y;
}
fn move_after_borrow_nested() {
- let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
+ let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
let _x = &a.x.x;
let _y = a.y;
use_imm(_x);
}
fn copy_after_mut_borrow_nested() {
- let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+ let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
let _x = &mut a.x.x;
let _y = a.y;
use_mut(_x);
}
fn move_after_mut_borrow_nested() {
- let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
+ let mut a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
let _x = &mut a.x.x;
let _y = a.y;
use_mut(_x);
}
fn borrow_after_mut_borrow_nested() {
- let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+ let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
let _x = &mut a.x.x;
let _y = &a.y;
use_mut(_x);
}
fn mut_borrow_after_borrow_nested() {
- let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+ let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
let _x = &a.x.x;
let _y = &mut a.y;
use_imm(_x);
// Tests that two closures cannot simultaneously have mutable
// and immutable access to the variable. Issue #6801.
-#![feature(box_syntax)]
-
fn get(x: &isize) -> isize {
*x
}
*x = 4;
}
+
+
fn a() {
let mut x = 3;
let c1 = || x = 4;
}
fn f() {
- let mut x: Box<_> = box 3;
+ let mut x: Box<_> = Box::new(3);
let c1 = || get(&*x);
*x = 5;
//~^ ERROR cannot assign to `*x` because it is borrowed
f: Box<isize>
}
- let mut x: Box<_> = box Foo { f: box 3 };
+ let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
let c1 = || get(&*x.f);
*x.f = 5;
//~^ ERROR cannot assign to `*x.f` because it is borrowed
f: Box<isize>
}
- let mut x: Box<_> = box Foo { f: box 3 };
+ let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
let c1 = || get(&*x.f);
let c2 = || *x.f = 5;
//~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
// access to the variable, whether that mutable access be used
// for direct assignment or for taking mutable ref. Issue #6801.
-#![feature(box_syntax)]
+
f: Box<isize>
}
- let mut x: Box<_> = box Foo { f: box 3 };
+ let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
let c1 = to_fn_mut(|| set(&mut *x.f));
let c2 = to_fn_mut(|| set(&mut *x.f));
//~^ ERROR cannot borrow `x` as mutable more than once
// access to the variable, whether that mutable access be used
// for direct assignment or for taking mutable ref. Issue #6801.
-#![feature(box_syntax)]
+
fn to_fn_mut<F: FnMut()>(f: F) -> F { f }
f: Box<isize>
}
- let mut x: Box<_> = box Foo { f: box 3 };
+ let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
let c1 = to_fn_mut(|| set(&mut *x.f));
let c2 = to_fn_mut(|| set(&mut *x.f));
//~^ ERROR cannot borrow `x` as mutable more than once
// cannot also be supplied a borrowed version of that
// variable's contents. Issue #11192.
-#![feature(box_syntax)]
-
struct Foo {
x: isize
}
}
}
+
+
fn main() {
- let mut ptr: Box<_> = box Foo { x: 0 };
+ let mut ptr: Box<_> = Box::new(Foo { x: 0 });
let mut test = |foo: &Foo| {
- ptr = box Foo { x: ptr.x + 1 };
+ ptr = Box::new(Foo { x: ptr.x + 1 });
};
test(&*ptr); //~ ERROR cannot borrow `*ptr`
}
|
LL | let mut test = |foo: &Foo| {
| ----------- mutable borrow occurs here
-LL | ptr = box Foo { x: ptr.x + 1 };
+LL | ptr = Box::new(Foo { x: ptr.x + 1 });
| --- first borrow occurs due to use of `ptr` in closure
LL | };
LL | test(&*ptr);
#![allow(unused_variables)]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
struct A { a: isize, b: Box<isize> }
struct B { a: Box<isize>, b: Box<isize> }
fn move_after_copy() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.a);
drop(x.b);
}
fn move_after_fu_copy() {
- let x = A { a: 1, b: box 2 };
- let _y = A { b: box 3, .. x };
+ let x = A { a: 1, b: Box::new(2) };
+ let _y = A { b: Box::new(3), .. x };
drop(x.b);
}
fn fu_move_after_copy() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.a);
let _y = A { a: 3, .. x };
}
fn fu_move_after_fu_copy() {
- let x = A { a: 1, b: box 2 };
- let _y = A { b: box 3, .. x };
+ let x = A { a: 1, b: Box::new(2) };
+ let _y = A { b: Box::new(3), .. x };
let _z = A { a: 4, .. x };
}
fn copy_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
drop(x.a);
}
fn copy_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let y = A { a: 3, .. x };
drop(x.a);
}
fn fu_copy_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
- let _y = A { b: box 3, .. x };
+ let _y = A { b: Box::new(3), .. x };
}
fn fu_copy_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- let _z = A { b: box 3, .. x };
+ let _z = A { b: Box::new(3), .. x };
}
fn borrow_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
let p = &x.a;
drop(*p);
}
fn borrow_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
let p = &x.a;
drop(*p);
}
fn move_after_borrow() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let p = &x.a;
drop(x.b);
drop(*p);
}
fn fu_move_after_borrow() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let p = &x.a;
let _y = A { a: 3, .. x };
drop(*p);
}
fn mut_borrow_after_mut_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.a;
let q = &mut x.b;
drop(*p);
}
fn move_after_move() {
- let x = B { a: box 1, b: box 2 };
+ let x = B { a: Box::new(1), b: Box::new(2) };
drop(x.a);
drop(x.b);
}
fn move_after_fu_move() {
- let x = B { a: box 1, b: box 2 };
- let y = B { a: box 3, .. x };
+ let x = B { a: Box::new(1), b: Box::new(2) };
+ let y = B { a: Box::new(3), .. x };
drop(x.a);
}
fn fu_move_after_move() {
- let x = B { a: box 1, b: box 2 };
+ let x = B { a: Box::new(1), b: Box::new(2) };
drop(x.a);
- let z = B { a: box 3, .. x };
+ let z = B { a: Box::new(3), .. x };
drop(z.b);
}
fn fu_move_after_fu_move() {
- let x = B { a: box 1, b: box 2 };
- let _y = B { b: box 3, .. x };
- let _z = B { a: box 4, .. x };
+ let x = B { a: Box::new(1), b: Box::new(2) };
+ let _y = B { b: Box::new(3), .. x };
+ let _z = B { a: Box::new(4), .. x };
}
fn copy_after_assign_after_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
drop(x.b);
- x = A { a: 3, b: box 4 };
+ x = A { a: 3, b: Box::new(4) };
drop(*x.b);
}
fn copy_after_assign_after_fu_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- x = A { a: 3, b: box 4 };
+ x = A { a: 3, b: Box::new(4) };
drop(*x.b);
}
fn copy_after_field_assign_after_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
drop(x.b);
- x.b = box 3;
+ x.b = Box::new(3);
drop(*x.b);
}
fn copy_after_field_assign_after_fu_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- x.b = box 3;
+ x.b = Box::new(3);
drop(*x.b);
}
fn borrow_after_assign_after_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
drop(x.b);
- x = A { a: 3, b: box 4 };
+ x = A { a: 3, b: Box::new(4) };
let p = &x.b;
drop(**p);
}
fn borrow_after_assign_after_fu_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- x = A { a: 3, b: box 4 };
+ x = A { a: 3, b: Box::new(4) };
let p = &x.b;
drop(**p);
}
fn borrow_after_field_assign_after_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
drop(x.b);
- x.b = box 3;
+ x.b = Box::new(3);
let p = &x.b;
drop(**p);
}
fn borrow_after_field_assign_after_fu_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- x.b = box 3;
+ x.b = Box::new(3);
let p = &x.b;
drop(**p);
}
fn move_after_assign_after_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = x.b;
- x = A { a: 3, b: box 4 };
+ x = A { a: 3, b: Box::new(4) };
drop(x.b);
}
fn move_after_assign_after_fu_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- x = A { a: 3, b: box 4 };
+ x = A { a: 3, b: Box::new(4) };
drop(x.b);
}
fn move_after_field_assign_after_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
drop(x.b);
- x.b = box 3;
+ x.b = Box::new(3);
drop(x.b);
}
fn move_after_field_assign_after_fu_move() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
- x.b = box 3;
+ x.b = Box::new(3);
drop(x.b);
}
fn copy_after_assign_after_uninit() {
let mut x: A;
- x = A { a: 1, b: box 2 };
+ x = A { a: 1, b: Box::new(2) };
drop(x.a);
}
fn borrow_after_assign_after_uninit() {
let mut x: A;
- x = A { a: 1, b: box 2 };
+ x = A { a: 1, b: Box::new(2) };
let p = &x.a;
drop(*p);
}
fn move_after_assign_after_uninit() {
let mut x: A;
- x = A { a: 1, b: box 2 };
+ x = A { a: 1, b: Box::new(2) };
drop(x.b);
}
-#![feature(box_syntax)]
-
struct A { a: isize, b: Box<isize> }
+
+
fn deref_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
drop(*x.b); //~ ERROR use of moved value: `x.b`
}
fn deref_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let y = A { a: 3, .. x };
drop(*x.b); //~ ERROR use of moved value: `x.b`
}
fn borrow_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
let p = &x.b; //~ ERROR borrow of moved value: `x.b`
drop(**p);
}
fn borrow_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
let p = &x.b; //~ ERROR borrow of moved value: `x.b`
drop(**p);
}
fn move_after_borrow() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let p = &x.b;
drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed
drop(**p);
}
fn fu_move_after_borrow() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let p = &x.b;
let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed
drop(**p);
}
fn mut_borrow_after_mut_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.a;
let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time
drop(*p);
}
fn move_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
drop(x.b); //~ ERROR use of moved value: `x.b`
}
fn move_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
drop(x.b); //~ ERROR use of moved value: `x.b`
}
fn fu_move_after_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
drop(x.b);
let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b`
}
fn fu_move_after_fu_move() {
- let x = A { a: 1, b: box 2 };
+ let x = A { a: 1, b: Box::new(2) };
let _y = A { a: 3, .. x };
let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b`
}
fn move_after_field_assign_after_uninit() {
let mut x: A;
- x.b = box 1; //~ ERROR assign to part of possibly-uninitialized variable: `x`
+ x.b = Box::new(1); //~ ERROR assign to part of possibly-uninitialized variable: `x`
drop(x.b);
}
error[E0381]: assign to part of possibly-uninitialized variable: `x`
--> $DIR/borrowck-field-sensitivity.rs:94:5
|
-LL | x.b = box 1;
+LL | x.b = Box::new(1);
| ^^^ use of possibly-uninitialized `x`
error: aborting due to 14 previous errors
// Issue #16205.
-#![feature(box_syntax)]
+
struct Foo {
a: [Box<isize>; 3],
}
let f = Foo {
- a: [box 3, box 4, box 5],
+ a: [Box::new(3), Box::new(4), Box::new(5)],
};
for &a in &f.a { //~ ERROR cannot move out
}
- let x: Option<Box<_>> = Some(box 1);
+ let x: Option<Box<_>> = Some(Box::new(1));
for &a in x.iter() { //~ ERROR cannot move out
}
}
// Also includes tests of the errors reported when the Box in question
// is immutable (#14270).
-#![feature(box_syntax)]
+
struct A { a: isize }
struct B<'a> { a: Box<&'a mut isize> }
fn indirect_write_to_imm_box() {
let mut x: isize = 1;
- let y: Box<_> = box &mut x;
+ let y: Box<_> = Box::new(&mut x);
let p = &y;
***p = 2; //~ ERROR cannot assign to `***p`
drop(p);
fn borrow_in_var_from_var() {
let mut x: isize = 1;
- let mut y: Box<_> = box &mut x;
+ let mut y: Box<_> = Box::new(&mut x);
let p = &y;
let q = &***p;
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
fn borrow_in_var_from_var_via_imm_box() {
let mut x: isize = 1;
- let y: Box<_> = box &mut x;
+ let y: Box<_> = Box::new(&mut x);
let p = &y;
let q = &***p;
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
fn borrow_in_var_from_field() {
let mut x = A { a: 1 };
- let mut y: Box<_> = box &mut x.a;
+ let mut y: Box<_> = Box::new(&mut x.a);
let p = &y;
let q = &***p;
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
fn borrow_in_var_from_field_via_imm_box() {
let mut x = A { a: 1 };
- let y: Box<_> = box &mut x.a;
+ let y: Box<_> = Box::new(&mut x.a);
let p = &y;
let q = &***p;
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
fn borrow_in_field_from_var() {
let mut x: isize = 1;
- let mut y = B { a: box &mut x };
+ let mut y = B { a: Box::new(&mut x) };
let p = &y.a;
let q = &***p;
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
fn borrow_in_field_from_var_via_imm_box() {
let mut x: isize = 1;
- let y = B { a: box &mut x };
+ let y = B { a: Box::new(&mut x) };
let p = &y.a;
let q = &***p;
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
fn borrow_in_field_from_field() {
let mut x = A { a: 1 };
- let mut y = B { a: box &mut x.a };
+ let mut y = B { a: Box::new(&mut x.a) };
let p = &y.a;
let q = &***p;
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
fn borrow_in_field_from_field_via_imm_box() {
let mut x = A { a: 1 };
- let y = B { a: box &mut x.a };
+ let y = B { a: Box::new(&mut x.a) };
let p = &y.a;
let q = &***p;
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
-#![feature(box_syntax)]
-
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } }
+impl<T> Fake for T { }
fn main() {
- let x: Option<Box<_>> = Some(box 1);
+ let x: Option<Box<_>> = Some(Box::new(1));
match x {
Some(ref _y) => {
let _a = x; //~ ERROR cannot move
_ => {}
}
}
-
-trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } }
-impl<T> Fake for T { }
-#![feature(box_syntax)]
-
fn main() {
- let x: Option<Box<_>> = Some(box 1);
+
+ let x: Option<Box<_>> = Some(Box::new(1));
+
match x {
Some(ref y) => {
let _b = *y; //~ ERROR cannot move out
// either genuine or would require more advanced changes. The latter
// cases are noted.
-#![feature(box_syntax)]
+
fn borrow(_v: &isize) {}
fn borrow_mut(_v: &mut isize) {}
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<isize>) {
- *v = box (**v + 1);
+ *v = Box::new(**v + 1);
}
fn pre_freeze_cond() {
// In this instance, the freeze is conditional and starts before
// the mut borrow.
- let u = box 0;
- let mut v: Box<_> = box 3;
+ let u = Box::new(0);
+ let mut v: Box<_> = Box::new(3);
let mut _w = &u;
if cond() {
_w = &v;
// In this instance, the freeze and mut borrow are on separate sides
// of the if.
- let u = box 0;
- let mut v: Box<_> = box 3;
+ let u = Box::new(0);
+ let mut v: Box<_> = Box::new(3);
let mut _w = &u;
if cond() {
_w = &v;
-#![feature(box_syntax)]
-
fn borrow(_v: &isize) {}
fn borrow_mut(_v: &mut isize) {}
fn cond() -> bool { panic!() }
fn produce<T>() -> T { panic!(); }
+
fn inc(v: &mut Box<isize>) {
- *v = box (**v + 1);
+ *v = Box::new(**v + 1);
}
+
fn loop_overarching_alias_mut() {
// In this instance, the borrow ends on the line before the loop
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
let mut x = &mut v;
**x += 1;
loop {
fn block_overarching_alias_mut() {
// In this instance, the borrow encompasses the entire closure call.
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
let mut x = &mut v;
for _ in 0..3 {
borrow(&*v); //~ ERROR cannot borrow
}
- *x = box 5;
+ *x = Box::new(5);
}
fn loop_aliased_mut() {
// In this instance, the borrow ends right after each assignment to _x
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let mut _x = &w;
loop {
borrow_mut(&mut *v); // OK
fn while_aliased_mut() {
// In this instance, the borrow ends right after each assignment to _x
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let mut _x = &w;
while cond() {
borrow_mut(&mut *v); // OK
fn loop_aliased_mut_break() {
// In this instance, the borrow ends right after each assignment to _x
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let mut _x = &w;
loop {
borrow_mut(&mut *v);
fn while_aliased_mut_break() {
// In this instance, the borrow ends right after each assignment to _x
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let mut _x = &w;
while cond() {
borrow_mut(&mut *v);
}
fn while_aliased_mut_cond(cond: bool, cond2: bool) {
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let mut x = &mut w;
while cond {
**x += 1;
LL | borrow(&*v);
| ^^^ immutable borrow occurs here
LL | }
-LL | *x = box 5;
+LL | *x = Box::new(5);
| -- mutable borrow later used here
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
// either genuine or would require more advanced changes. The latter
// cases are noted.
-#![feature(box_syntax)]
+
fn borrow(_v: &isize) {}
fn borrow_mut(_v: &mut isize) {}
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<isize>) {
- *v = box (**v + 1);
+ *v = Box::new(**v + 1);
}
fn pre_freeze() {
// In this instance, the freeze starts before the mut borrow.
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
let _w = &v;
borrow_mut(&mut *v); //~ ERROR cannot borrow
_w.use_ref();
fn post_freeze() {
// In this instance, the const alias starts after the borrow.
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
borrow_mut(&mut *v);
let _w = &v;
}
-#![feature(box_syntax)]
-
use std::thread;
f(v);
}
+
+
fn box_imm() {
- let v: Box<_> = box 3;
+ let v: Box<_> = Box::new(3);
let w = &v;
thread::spawn(move|| {
//~^ ERROR cannot move out of `v` because it is borrowed
}
fn box_imm_explicit() {
- let v: Box<_> = box 3;
+ let v: Box<_> = Box::new(3);
let w = &v;
thread::spawn(move|| {
//~^ ERROR cannot move
-#![feature(box_syntax)]
+fn take(_v: Box<isize>) {
+}
+
-fn take(_v: Box<isize>) {
-}
fn box_imm() {
- let v = box 3;
+ let v = Box::new(3);
let w = &v;
take(v); //~ ERROR cannot move out of `v` because it is borrowed
w.use_ref();
-#![feature(box_syntax)]
-
fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) {
f(v);
}
+
+
fn box_imm() {
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
borrow(&*v,
|w| { //~ ERROR cannot borrow `v` as mutable
- v = box 4;
+ v = Box::new(4);
assert_eq!(*v, 3);
assert_eq!(*w, 4);
})
| immutable borrow later used by call
LL | |w| {
| ^^^ mutable borrow occurs here
-LL | v = box 4;
+LL | v = Box::new(4);
| - second borrow occurs due to use of `v` in closure
error: aborting due to previous error
#![feature(box_patterns)]
-#![feature(box_syntax)]
+
use std::ops::Add;
fn add(self, f: Foo) -> Foo {
let Foo(box i) = self;
let Foo(box j) = f;
- Foo(box (i + j))
+ Foo(Box::new(i + j))
}
}
fn main() {
- let x = Foo(box 3);
+ let x = Foo(Box::new(3));
let _y = {x} + x.clone(); // the `{x}` forces a move to occur
//~^ ERROR borrow of moved value: `x`
}
error[E0382]: borrow of moved value: `x`
--> $DIR/borrowck-loan-in-overloaded-op.rs:21:20
|
-LL | let x = Foo(box 3);
+LL | let x = Foo(Box::new(3));
| - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur
| - ^ value borrowed here after move
// Check that we do not ICE when compiling this
// macro, which reuses the expression `$id`
-
#![feature(box_patterns)]
-#![feature(box_syntax)]
struct Foo {
a: isize
macro_rules! declare {
($id:expr, $rest:expr) => ({
self.check_id($id);
- box Bar::Bar2($id, $rest)
+ Box::new(Bar::Bar2($id, $rest))
})
}
match s {
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let bar: Box<_> = box 3;
+ let bar: Box<_> = Box::new(3);
let h = || -> isize { *bar };
assert_eq!(h(), 3);
}
-#![feature(box_syntax,unboxed_closures)]
+#![feature(unboxed_closures)]
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
pub fn main() {
- let bar: Box<_> = box 3;
+ let bar: Box<_> = Box::new(3);
let _g = to_fn_mut(|| {
let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
});
error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
--> $DIR/borrowck-move-by-capture.rs:9:29
|
-LL | let bar: Box<_> = box 3;
+LL | let bar: Box<_> = Box::new(3);
| --- captured outer variable
LL | let _g = to_fn_mut(|| {
| ________________________-
-#![feature(box_syntax)]
-
enum Foo {
Foo1(Box<u32>, Box<u32>),
Foo2(Box<u32>),
Foo3,
}
+
+
fn blah() {
- let f = &Foo::Foo1(box 1, box 2);
- match *f { //~ ERROR cannot move out of
+ let f = &Foo::Foo1(Box::new(1), Box::new(2));
+ match *f { //~ ERROR cannot move out of
Foo::Foo1(num1,
num2) => (),
Foo::Foo2(num) => (),
fn free<T>(_: T) {}
fn blah2() {
- let a = &A { a: box 1 };
- match a.a { //~ ERROR cannot move out of
+ let a = &A { a: Box::new(1) };
+ match a.a { //~ ERROR cannot move out of
n => {
free(n)
}
-#![feature(box_syntax)]
+
fn main() {
- let a: Box<Box<_>> = box box 2;
+ let a: Box<Box<_>> = Box::new(Box::new(2));
let b = &a;
let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed
-#![feature(box_syntax)]
-
fn call_f<F:FnOnce() -> isize>(f: F) -> isize {
f()
}
+
+
fn main() {
- let t: Box<_> = box 3;
+ let t: Box<_> = Box::new(3);
call_f(move|| { *t + 1 });
call_f(move|| { *t + 1 }); //~ ERROR use of moved value
error[E0382]: use of moved value: `t`
--> $DIR/borrowck-move-moved-value-into-closure.rs:11:12
|
-LL | let t: Box<_> = box 3;
+LL | let t: Box<_> = Box::new(3);
| - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait
LL |
LL | call_f(move|| { *t + 1 });
// Tests that the borrow checker checks all components of a path when moving
// out.
-#![feature(box_syntax)]
+
struct S {
x : Box<isize>
fn f<T>(_: T) {}
fn main() {
- let a : S = S { x : box 1 };
+ let a : S = S { x : Box::new(1) };
let pb = &a;
let S { x: ax } = a; //~ ERROR cannot move out
f(pb);
-#![feature(box_syntax)]
-
use std::thread;
+
fn borrow<T>(_: &T) { }
+
fn different_vars_after_borrows() {
- let x1: Box<_> = box 1;
+ let x1: Box<_> = Box::new(1);
let p1 = &x1;
- let x2: Box<_> = box 2;
+ let x2: Box<_> = Box::new(2);
let p2 = &x2;
thread::spawn(move|| {
//~^ ERROR cannot move out of `x1` because it is borrowed
}
fn different_vars_after_moves() {
- let x1: Box<_> = box 1;
+ let x1: Box<_> = Box::new(1);
drop(x1);
- let x2: Box<_> = box 2;
+ let x2: Box<_> = Box::new(2);
drop(x2);
thread::spawn(move|| {
//~^ ERROR use of moved value: `x1`
}
fn same_var_after_borrow() {
- let x: Box<_> = box 1;
+ let x: Box<_> = Box::new(1);
let p = &x;
thread::spawn(move|| {
//~^ ERROR cannot move out of `x` because it is borrowed
}
fn same_var_after_move() {
- let x: Box<_> = box 1;
+ let x: Box<_> = Box::new(1);
drop(x);
thread::spawn(move|| {
//~^ ERROR use of moved value: `x`
error[E0382]: use of moved value: `x1`
--> $DIR/borrowck-multiple-captures.rs:27:19
|
-LL | let x1: Box<_> = box 1;
+LL | let x1: Box<_> = Box::new(1);
| -- move occurs because `x1` has type `Box<i32>`, which does not implement the `Copy` trait
LL | drop(x1);
| -- value moved here
error[E0382]: use of moved value: `x2`
--> $DIR/borrowck-multiple-captures.rs:27:19
|
-LL | let x2: Box<_> = box 2;
+LL | let x2: Box<_> = Box::new(2);
| -- move occurs because `x2` has type `Box<i32>`, which does not implement the `Copy` trait
LL | drop(x2);
| -- value moved here
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:49:19
|
-LL | let x: Box<_> = box 1;
+LL | let x: Box<_> = Box::new(1);
| - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
LL | drop(x);
| - value moved here
// run-pass
-#![feature(box_syntax)]
use std::mem::swap;
}
pub fn main() {
- let mut ints: Box<_> = box Ints {sum: box 0, values: Vec::new()};
+ let mut ints: Box<_> = Box::new(Ints {sum: Box::new(0), values: Vec::new()});
add_int(&mut *ints, 22);
add_int(&mut *ints, 44);
-#![feature(box_syntax)]
-
struct Node_ {
a: Box<Cycle>
}
Node(Node_),
Empty,
}
+
fn main() {
- let mut x: Box<_> = box Cycle::Node(Node_ {a: box Cycle::Empty});
+ let mut x: Box<_> = Box::new(Cycle::Node(Node_ {a: Box::new(Cycle::Empty)}));
+
// Create a cycle!
match *x {
Cycle::Node(ref mut y) => {
-#![feature(box_syntax)]
-
use std::ops::Index;
struct MyVec<T> {
}
}
+
+
fn main() {
- let v = MyVec::<Box<_>> { data: vec![box 1, box 2, box 3] };
+ let v = MyVec::<Box<_>> { data: vec![Box::new(1), Box::new(2), Box::new(3)] };
let good = &v[0]; // Shouldn't fail here
let bad = v[0];
//~^ ERROR cannot move out of index of `MyVec<Box<i32>>`
-#![feature(box_syntax)]
+fn borrow(_v: &isize) {}
+
-fn borrow(_v: &isize) {}
fn local() {
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
borrow(&*v);
}
fn local_rec() {
struct F { f: Box<isize> }
- let mut v = F {f: box 3};
+ let mut v = F {f: Box::new(3)};
borrow(&*v.f);
}
struct F { f: G }
struct G { g: H }
struct H { h: Box<isize> }
- let mut v = F {f: G {g: H {h: box 3}}};
+ let mut v = F {f: G {g: H {h: Box::new(3)}}};
borrow(&*v.f.g.h);
}
fn aliased_imm() {
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
let w = &v;
borrow(&*v);
w.use_ref();
}
fn aliased_mut() {
- let mut v: Box<_> = box 3;
+ let mut v: Box<_> = Box::new(3);
let w = &mut v;
borrow(&*v); //~ ERROR cannot borrow `*v`
w.use_mut();
}
fn aliased_other() {
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let x = &mut w;
borrow(&*v);
x.use_mut();
}
fn aliased_other_reassign() {
- let mut v: Box<_> = box 3;
- let mut w: Box<_> = box 4;
+ let mut v: Box<_> = Box::new(3);
+ let mut w: Box<_> = Box::new(4);
let mut x = &mut w;
x = &mut v;
borrow(&*v); //~ ERROR cannot borrow `*v`
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
struct A { a: isize, b: Box<isize> }
fn field_copy_after_field_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.b;
drop(x.a);
**p = 3;
}
fn fu_field_copy_after_field_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.b;
- let y = A { b: box 3, .. x };
+ let y = A { b: Box::new(3), .. x };
drop(y);
**p = 4;
}
fn field_deref_after_field_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.a;
drop(*x.b);
*p = 3;
}
fn field_move_after_field_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.a;
drop(x.b);
*p = 3;
}
fn fu_field_move_after_field_borrow() {
- let mut x = A { a: 1, b: box 2 };
+ let mut x = A { a: 1, b: Box::new(2) };
let p = &mut x.a;
let y = A { a: 3, .. x };
drop(y);
-#![feature(box_syntax)]
-
#[derive(Copy, Clone)]
struct A { a: isize, b: isize }
struct B { a: isize, b: Box<isize> }
+
+
fn var_copy_after_var_borrow() {
let mut x: isize = 1;
let p = &mut x;
}
fn var_deref_after_var_borrow() {
- let mut x: Box<isize> = box 1;
+ let mut x: Box<isize> = Box::new(1);
let p = &mut x;
drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed
**p = 2;
}
fn field_deref_after_var_borrow() {
- let mut x = B { a: 1, b: box 2 };
+ let mut x = B { a: 1, b: Box::new(2) };
let p = &mut x;
drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed
p.a = 3;
}
fn field_deref_after_field_borrow() {
- let mut x = B { a: 1, b: box 2 };
+ let mut x = B { a: 1, b: Box::new(2) };
let p = &mut x.b;
drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed
**p = 3;
#![feature(box_patterns)]
-#![feature(box_syntax)]
+
fn a() {
- let mut vec = [box 1, box 2, box 3];
+ let mut vec = [Box::new(1), Box::new(2), Box::new(3)];
match vec {
[box ref _a, _, _] => {
//~^ NOTE borrow of `vec[_]` occurs here
- vec[0] = box 4; //~ ERROR cannot assign
+ vec[0] = Box::new(4); //~ ERROR cannot assign
//~^ NOTE assignment to borrowed `vec[_]` occurs here
_a.use_ref();
//~^ NOTE borrow later used here
}
fn b() {
- let mut vec = vec![box 1, box 2, box 3];
+ let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
let vec: &mut [Box<isize>] = &mut vec;
match vec {
&mut [ref _b @ ..] => {
//~^ borrow of `vec[_]` occurs here
- vec[0] = box 4; //~ ERROR cannot assign
+ vec[0] = Box::new(4); //~ ERROR cannot assign
//~^ NOTE assignment to borrowed `vec[_]` occurs here
_b.use_ref();
//~^ NOTE borrow later used here
}
fn c() {
- let mut vec = vec![box 1, box 2, box 3];
+ let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
let vec: &mut [Box<isize>] = &mut vec;
match vec {
//~^ ERROR cannot move out
}
fn d() {
- let mut vec = vec![box 1, box 2, box 3];
+ let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
let vec: &mut [Box<isize>] = &mut vec;
match vec {
//~^ ERROR cannot move out
}
fn e() {
- let mut vec = vec![box 1, box 2, box 3];
+ let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
let vec: &mut [Box<isize>] = &mut vec;
match vec {
//~^ ERROR cannot move out
LL | [box ref _a, _, _] => {
| ------ borrow of `vec[_]` occurs here
LL |
-LL | vec[0] = box 4;
+LL | vec[0] = Box::new(4);
| ^^^^^^ assignment to borrowed `vec[_]` occurs here
LL |
LL | _a.use_ref();
LL | &mut [ref _b @ ..] => {
| ----------- borrow of `vec[_]` occurs here
LL |
-LL | vec[0] = box 4;
+LL | vec[0] = Box::new(4);
| ^^^^^^ assignment to borrowed `vec[_]` occurs here
LL |
LL | _b.use_ref();
// Issue 4691: Ensure that functional-struct-updates operates
// correctly and moves rather than copy when appropriate.
-#![feature(box_syntax, core)]
+#![feature(core)]
struct ncint { v: isize }
fn ncint(v: isize) -> ncint { ncint { v: v } }
struct MoveFoo { copied: isize, moved: Box<isize>, }
impl MoveFoo {
- fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: box y } }
+ fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: Box::new(y) } }
}
struct DropNoFoo { inner: NoFoo }
// Case 2: Owned
let f = DropMoveFoo::new(5, 6);
- let b = DropMoveFoo { inner: MoveFoo { moved: box 7, ..f.inner }};
- let c = DropMoveFoo { inner: MoveFoo { moved: box 8, ..f.inner }};
+ let b = DropMoveFoo { inner: MoveFoo { moved: Box::new(7), ..f.inner }};
+ let c = DropMoveFoo { inner: MoveFoo { moved: Box::new(8), ..f.inner }};
assert_eq!(f.inner.copied, 5);
assert_eq!(*f.inner.moved, 6);
// copying move-by-default fields from `f`, so it moves:
let f = MoveFoo::new(11, 12);
- let b = MoveFoo {moved: box 13, ..f};
+ let b = MoveFoo {moved: Box::new(13), ..f};
let c = MoveFoo {copied: 14, ..f};
assert_eq!(b.copied, 11);
assert_eq!(*b.moved, 13);
// check-pass
-#![feature(box_syntax)]
-
struct Foo { a: isize, b: isize }
fn main() {
- let mut x: Box<_> = box Foo { a: 1, b: 2 };
+ let mut x: Box<_> = Box::new(Foo { a: 1, b: 2 });
let (a, b) = (&mut x.a, &mut x.b);
- let mut foo: Box<_> = box Foo { a: 1, b: 2 };
+ let mut foo: Box<_> = Box::new(Foo { a: 1, b: 2 });
let (c, d) = (&mut foo.a, &foo.b);
// We explicitly use the references created above to illustrate that the
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
fn foo(x: &mut Box<u8>) {
- *x = box 5;
+ *x = Box::new(5);
}
pub fn main() {
- foo(&mut box 4);
+ foo(&mut Box::new(4));
}
-#![feature(box_syntax)]
-
trait Noisy {
fn speak(&self);
}
}
}
+
+
fn main() {
- let nyan: Box<dyn Noisy> = box cat(0, 2, "nyan".to_string()) as Box<dyn Noisy>;
+ let nyan: Box<dyn Noisy> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn Noisy>;
nyan.eat(); //~ ERROR no method named `eat` found
}
// pretty-expanded FIXME #23616
-#![feature(box_syntax, os)]
+#![feature(os)]
use std::os;
impl Test {
fn get_x(&self) -> Option<Box<isize>> {
- Some(box self.x)
+ Some(Box::new(self.x))
}
}
// lifetime rules.
#![feature(box_patterns)]
-#![feature(box_syntax)]
use std::ops::Drop;
end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
end_of_block!(&AddFlags { bits }, &AddFlags(1));
end_of_block!((_, ref _y), (AddFlags(1), 22));
- end_of_block!(box ref _x, box AddFlags(1));
- end_of_block!(box _x, box AddFlags(1));
+ end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1)));
+ end_of_block!(box _x, std::boxed::Box::new(AddFlags(1)));
end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
end_of_block!(_, &((Box { f: AddFlags(1) }).f));
end_of_block!(_, &(([AddFlags(1)])[0]));
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::thread;
enum Conzabble {
pub fn fails() {
let x = 2;
let mut y: Vec<Box<_>> = Vec::new();
- y.push(box Conzabble::Bickwick(do_it(&get_bar(x))));
+ y.push(Box::new(Conzabble::Bickwick(do_it(&get_bar(x)))));
}
pub fn main() {
#![allow(unused_must_use)]
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::thread;
struct Pair {
}
pub fn main() {
- let z: Box<_> = box Pair { a : 10, b : 12};
+ let z: Box<_> = Box::new(Pair { a : 10, b : 12});
thread::spawn(move|| {
assert_eq!(z.a, 10);
// storing closure data (as we used to do), the u64 would
// overwrite the u16.
-#![feature(box_syntax)]
-
struct Pair<A,B> {
a: A, b: B
}
}
fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> {
- box Invoker {
+ Box::new(Invoker {
a: a,
b: b,
- } as Box<dyn Invokable<A>+'static>
+ }) as Box<dyn Invokable<A>+'static>
}
pub fn main() {
// edition:2021
+
+
// Tests that two closures cannot simultaneously have mutable
// and immutable access to the variable. Issue #6801.
-#![feature(box_syntax)]
-
#[derive(Debug)]
struct Point {
x: i32,
use std::thread;
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
/* Test Send Trait Migration */
struct SendPointer(*mut i32);
unsafe impl Send for SendPointer {}
}
/* Test Clone Trait Migration */
-struct S(String);
+struct S(Foo);
struct T(i32);
struct U(S, T);
impl Clone for U {
fn clone(&self) -> Self {
- U(S(String::from("Hello World")), T(0))
+ U(S(Foo(0)), T(0))
}
}
fn test_clone_trait() {
- let f = U(S(String::from("Hello World")), T(0));
+ let f = U(S(Foo(0)), T(0));
let c = || {
let _ = &f;
//~^ ERROR: `Clone` trait implementation for closure and drop order
use std::thread;
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
/* Test Send Trait Migration */
struct SendPointer(*mut i32);
unsafe impl Send for SendPointer {}
}
/* Test Clone Trait Migration */
-struct S(String);
+struct S(Foo);
struct T(i32);
struct U(S, T);
impl Clone for U {
fn clone(&self) -> Self {
- U(S(String::from("Hello World")), T(0))
+ U(S(Foo(0)), T(0))
}
}
fn test_clone_trait() {
- let f = U(S(String::from("Hello World")), T(0));
+ let f = U(S(Foo(0)), T(0));
let c = || {
//~^ ERROR: `Clone` trait implementation for closure and drop order
//~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure
- --> $DIR/auto_traits.rs:14:19
+ --> $DIR/auto_traits.rs:22:19
|
LL | thread::spawn(move || unsafe {
| ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
...
error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
- --> $DIR/auto_traits.rs:34:19
+ --> $DIR/auto_traits.rs:42:19
|
LL | thread::spawn(move || unsafe {
| ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
...
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/auto_traits.rs:58:13
+ --> $DIR/auto_traits.rs:66:13
|
LL | let c = || {
| ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
// check-pass
#![warn(rust_2021_compatibility)]
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
macro_rules! m {
(@ $body:expr) => {{
let f = || $body;
}
fn main() {
- let a = (1.to_string(), 2.to_string());
+ let a = (Foo(0), Foo(1));
m!({
let _ = &a;
//~^ HELP: add a dummy
let x = a.0;
- println!("{}", x);
+ println!("{:?}", x);
});
}
// check-pass
#![warn(rust_2021_compatibility)]
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
macro_rules! m {
(@ $body:expr) => {{
let f = || $body;
}
fn main() {
- let a = (1.to_string(), 2.to_string());
+ let a = (Foo(0), Foo(1));
m!({
//~^ HELP: add a dummy
let x = a.0;
- println!("{}", x);
+ println!("{:?}", x);
});
}
warning: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/closure-body-macro-fragment.rs:8:17
+ --> $DIR/closure-body-macro-fragment.rs:16:17
|
LL | let f = || $body;
| _________________^
LL | |
LL | | let x = a.0;
| | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
-LL | | println!("{}", x);
+LL | | println!("{:?}", x);
LL | | });
| |_______- in this macro invocation
|
+// run-pass
// run-rustfix
#![deny(rust_2021_incompatible_closure_captures)]
-//~^ NOTE: the lint level is defined here
+#![allow(unused)]
// Test cases for types that implement an insignificant drop (stlib defined)
-// `t` needs Drop because one of its elements needs drop,
-// therefore precise capture might affect drop ordering
-fn test1_all_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let t2 = (String::new(), String::new());
+macro_rules! test_insig_dtor_for_type {
+ ($t: ty, $disambiguator: ident) => {
+ mod $disambiguator {
+ use std::collections::*;
+ use std::rc::Rc;
+ use std::sync::Mutex;
- let c = || {
- let _ = (&t, &t1, &t2);
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+ fn test_for_type(t: $t) {
+ let tup = (Mutex::new(0), t);
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _t1 = t1.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
- let _t2 = t2.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+ let _c = || tup.0;
+ }
+ }
};
-
- c();
}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-
-// String implements drop and therefore should be migrated.
-// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
-fn test2_only_precise_paths_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let t2 = (String::new(), String::new());
-
- let c = || {
- let _ = (&t, &t1);
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _t1 = t1.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
- let _t2 = t2;
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-
-// If a variable would've not been captured by value then it would've not been
-// dropped with the closure and therefore doesn't need migration.
-fn test3_only_by_value_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let c = || {
- let _ = &t;
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- println!("{}", t1.1);
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Copy types get copied into the closure instead of move. Therefore we don't need to
-// migrate then as their drop order isn't tied to the closure.
-fn test4_only_non_copy_types_need_migration() {
- let t = (String::new(), String::new());
-
- // `t1` is Copy because all of its elements are Copy
- let t1 = (0i32, 0i32);
-
- let c = || {
- let _ = &t;
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _t1 = t1.0;
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn test5_only_drop_types_need_migration() {
- struct S(i32, i32);
- let t = (String::new(), String::new());
-
- // `s` doesn't implement Drop or any elements within it, and doesn't need migration
- let s = S(0i32, 0i32);
-
- let c = || {
- let _ = &t;
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _s = s.0;
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Since we are using a move closure here, both `t` and `t1` get moved
-// even though they are being used by ref inside the closure.
-fn test6_move_closures_non_copy_types_might_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let c = move || {
- let _ = (&t1, &t);
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured
- println!("{} {}", t1.1, t.1);
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
- //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
-
-// Test migration analysis in case of Drop + Non Drop aggregates.
-// Note we need migration here only because the non-copy (because Drop type) is captured,
-// otherwise we won't need to, since we can get away with just by ref capture in that case.
-fn test7_drop_non_drop_aggregate_need_migration() {
- let t = (String::new(), String::new(), 0i32);
-
- let c = || {
- let _ = &t;
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn main() {
- test1_all_need_migration();
- test2_only_precise_paths_need_migration();
- test3_only_by_value_need_migration();
- test4_only_non_copy_types_need_migration();
- test5_only_drop_types_need_migration();
- test6_move_closures_non_copy_types_might_need_migration();
- test7_drop_non_drop_aggregate_need_migration();
-}
+test_insig_dtor_for_type!(i32, prim_i32);
+test_insig_dtor_for_type!(Vec<i32>, vec_i32);
+test_insig_dtor_for_type!(String, string);
+test_insig_dtor_for_type!(Vec<String>, vec_string);
+test_insig_dtor_for_type!(HashMap<String, String>, hash_map);
+test_insig_dtor_for_type!(BTreeMap<String, i32>, btree_map);
+test_insig_dtor_for_type!(LinkedList<String>, linked_list);
+test_insig_dtor_for_type!(Rc<i32>, rc_i32);
+test_insig_dtor_for_type!(Rc<String>, rc_string);
+test_insig_dtor_for_type!(std::vec::IntoIter<String>, vec_into_iter);
+test_insig_dtor_for_type!(btree_map::IntoIter<String, String>, btree_map_into_iter);
+test_insig_dtor_for_type!(std::array::IntoIter<String, 5>, array_into_iter);
+
+fn main() {}
+// run-pass
// run-rustfix
#![deny(rust_2021_incompatible_closure_captures)]
-//~^ NOTE: the lint level is defined here
+#![allow(unused)]
// Test cases for types that implement an insignificant drop (stlib defined)
-// `t` needs Drop because one of its elements needs drop,
-// therefore precise capture might affect drop ordering
-fn test1_all_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let t2 = (String::new(), String::new());
+macro_rules! test_insig_dtor_for_type {
+ ($t: ty, $disambiguator: ident) => {
+ mod $disambiguator {
+ use std::collections::*;
+ use std::rc::Rc;
+ use std::sync::Mutex;
- let c = || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+ fn test_for_type(t: $t) {
+ let tup = (Mutex::new(0), t);
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _t1 = t1.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
- let _t2 = t2.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+ let _c = || tup.0;
+ }
+ }
};
-
- c();
}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-
-// String implements drop and therefore should be migrated.
-// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
-fn test2_only_precise_paths_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let t2 = (String::new(), String::new());
-
- let c = || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _t1 = t1.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
- let _t2 = t2;
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-
-// If a variable would've not been captured by value then it would've not been
-// dropped with the closure and therefore doesn't need migration.
-fn test3_only_by_value_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let c = || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- println!("{}", t1.1);
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Copy types get copied into the closure instead of move. Therefore we don't need to
-// migrate then as their drop order isn't tied to the closure.
-fn test4_only_non_copy_types_need_migration() {
- let t = (String::new(), String::new());
-
- // `t1` is Copy because all of its elements are Copy
- let t1 = (0i32, 0i32);
-
- let c = || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _t1 = t1.0;
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn test5_only_drop_types_need_migration() {
- struct S(i32, i32);
- let t = (String::new(), String::new());
-
- // `s` doesn't implement Drop or any elements within it, and doesn't need migration
- let s = S(0i32, 0i32);
-
- let c = || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- let _s = s.0;
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Since we are using a move closure here, both `t` and `t1` get moved
-// even though they are being used by ref inside the closure.
-fn test6_move_closures_non_copy_types_might_need_migration() {
- let t = (String::new(), String::new());
- let t1 = (String::new(), String::new());
- let c = move || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured
- println!("{} {}", t1.1, t.1);
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
- //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
-
-// Test migration analysis in case of Drop + Non Drop aggregates.
-// Note we need migration here only because the non-copy (because Drop type) is captured,
-// otherwise we won't need to, since we can get away with just by ref capture in that case.
-fn test7_drop_non_drop_aggregate_need_migration() {
- let t = (String::new(), String::new(), 0i32);
-
- let c = || {
- //~^ ERROR: drop order
- //~| NOTE: for more information, see
- //~| HELP: add a dummy let to cause `t` to be fully captured
- let _t = t.0;
- //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
- };
-
- c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn main() {
- test1_all_need_migration();
- test2_only_precise_paths_need_migration();
- test3_only_by_value_need_migration();
- test4_only_non_copy_types_need_migration();
- test5_only_drop_types_need_migration();
- test6_move_closures_non_copy_types_might_need_migration();
- test7_drop_non_drop_aggregate_need_migration();
-}
+test_insig_dtor_for_type!(i32, prim_i32);
+test_insig_dtor_for_type!(Vec<i32>, vec_i32);
+test_insig_dtor_for_type!(String, string);
+test_insig_dtor_for_type!(Vec<String>, vec_string);
+test_insig_dtor_for_type!(HashMap<String, String>, hash_map);
+test_insig_dtor_for_type!(BTreeMap<String, i32>, btree_map);
+test_insig_dtor_for_type!(LinkedList<String>, linked_list);
+test_insig_dtor_for_type!(Rc<i32>, rc_i32);
+test_insig_dtor_for_type!(Rc<String>, rc_string);
+test_insig_dtor_for_type!(std::vec::IntoIter<String>, vec_into_iter);
+test_insig_dtor_for_type!(btree_map::IntoIter<String, String>, btree_map_into_iter);
+test_insig_dtor_for_type!(std::array::IntoIter<String, 5>, array_into_iter);
+
+fn main() {}
+++ /dev/null
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:15:13
- |
-LL | let c = || {
- | ^^
-...
-LL | let _t = t.0;
- | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-LL |
-LL | let _t1 = t1.0;
- | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-LL |
-LL | let _t2 = t2.0;
- | ---- in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
-...
-LL | }
- | -
- | |
- | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
- | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
- | in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
- |
-note: the lint level is defined here
- --> $DIR/insignificant_drop.rs:3:9
- |
-LL | #![deny(rust_2021_incompatible_closure_captures)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
- |
-LL ~ let c = || {
-LL + let _ = (&t, &t1, &t2);
- |
-
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:41:13
- |
-LL | let c = || {
- | ^^
-...
-LL | let _t = t.0;
- | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-LL |
-LL | let _t1 = t1.0;
- | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-...
-LL | }
- | -
- | |
- | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
- | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
- |
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t`, `t1` to be fully captured
- |
-LL ~ let c = || {
-LL + let _ = (&t, &t1);
- |
-
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:62:13
- |
-LL | let c = || {
- | ^^
-...
-LL | let _t = t.0;
- | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
- | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
- |
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
- |
-LL ~ let c = || {
-LL + let _ = &t;
- |
-
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:83:13
- |
-LL | let c = || {
- | ^^
-...
-LL | let _t = t.0;
- | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
- | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
- |
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
- |
-LL ~ let c = || {
-LL + let _ = &t;
- |
-
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:104:13
- |
-LL | let c = || {
- | ^^
-...
-LL | let _t = t.0;
- | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
- | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
- |
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
- |
-LL ~ let c = || {
-LL + let _ = &t;
- |
-
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:122:13
- |
-LL | let c = move || {
- | ^^^^^^^
-...
-LL | println!("{} {}", t1.1, t.1);
- | ---- --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
- | |
- | in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
-...
-LL | }
- | -
- | |
- | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
- | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
- |
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t1`, `t` to be fully captured
- |
-LL ~ let c = move || {
-LL + let _ = (&t1, &t);
- |
-
-error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop.rs:142:13
- |
-LL | let c = || {
- | ^^
-...
-LL | let _t = t.0;
- | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
- | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
- |
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
- |
-LL ~ let c = || {
-LL + let _ = &t;
- |
-
-error: aborting due to 7 previous errors
-
#![feature(rustc_attrs)]
#![allow(unused)]
+use std::sync::Mutex;
+
+ #[rustc_insignificant_dtor]
struct InsignificantDropPoint {
x: i32,
- y: i32,
+ y: Mutex<i32>,
}
impl Drop for InsignificantDropPoint {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
fn drop(&mut self) {}
}
+#[rustc_insignificant_dtor]
struct GenericStruct<T>(T, T);
-struct Wrapper<T>(GenericStruct<T>, i32);
-
impl<T> Drop for GenericStruct<T> {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
+struct Wrapper<T>(GenericStruct<T>, i32);
+
// `SigDrop` implements drop and therefore needs to be migrated.
fn significant_drop_needs_migration() {
let t = (SigDrop {}, SigDrop {});
#![feature(rustc_attrs)]
#![allow(unused)]
+use std::sync::Mutex;
+
+ #[rustc_insignificant_dtor]
struct InsignificantDropPoint {
x: i32,
- y: i32,
+ y: Mutex<i32>,
}
impl Drop for InsignificantDropPoint {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
fn drop(&mut self) {}
}
+#[rustc_insignificant_dtor]
struct GenericStruct<T>(T, T);
-struct Wrapper<T>(GenericStruct<T>, i32);
-
impl<T> Drop for GenericStruct<T> {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
+struct Wrapper<T>(GenericStruct<T>, i32);
+
// `SigDrop` implements drop and therefore needs to be migrated.
fn significant_drop_needs_migration() {
let t = (SigDrop {}, SigDrop {});
error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop_attr_migrations.rs:37:13
+ --> $DIR/insignificant_drop_attr_migrations.rs:39:13
|
LL | let c = || {
| ^^
|
error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/insignificant_drop_attr_migrations.rs:57:13
+ --> $DIR/insignificant_drop_attr_migrations.rs:59:13
|
LL | let c = move || {
| ^^^^^^^
#![deny(rust_2021_incompatible_closure_captures)]
#![feature(rustc_attrs)]
#![allow(unused)]
+#[rustc_insignificant_dtor]
struct InsignificantDropPoint {
x: i32,
}
impl Drop for InsignificantDropPoint {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
#![deny(rust_2021_incompatible_closure_captures)]
//~^ NOTE: the lint level is defined here
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
fn main() {
- let a = ("hey".to_string(), "123".to_string());
+ let a = (Foo(0), Foo(1));
let _ = || { let _ = &a; dbg!(a.0) };
//~^ ERROR: drop order
//~| NOTE: will only capture `a.0`
#![deny(rust_2021_incompatible_closure_captures)]
//~^ NOTE: the lint level is defined here
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
fn main() {
- let a = ("hey".to_string(), "123".to_string());
+ let a = (Foo(0), Foo(1));
let _ = || dbg!(a.0);
//~^ ERROR: drop order
//~| NOTE: will only capture `a.0`
error: changes to closure capture in Rust 2021 will affect drop order
- --> $DIR/macro.rs:10:13
+ --> $DIR/macro.rs:19:13
|
LL | let _ = || dbg!(a.0);
| ^^^^^^^^---^
use std::thread;
-struct S(String);
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+impl Foo {
+ fn from(s: &str) -> Self {
+ Self(String::from(s))
+ }
+}
+
+
+struct S(Foo);
#[derive(Clone)]
struct T(i32);
impl Clone for U {
fn clone(&self) -> Self {
- U(S(String::from("Hello World")), T(0))
+ U(S(Foo::from("Hello World")), T(0))
}
}
fn test_multi_issues() {
- let f1 = U(S(String::from("foo")), T(0));
- let f2 = U(S(String::from("bar")), T(0));
+ let f1 = U(S(Foo::from("foo")), T(0));
+ let f2 = U(S(Foo::from("bar")), T(0));
let c = || {
let _ = (&f1, &f2);
//~^ ERROR: `Clone` trait implementation for closure and drop order
//~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
fn test_capturing_all_disjoint_fields_individually() {
- let f1 = U(S(String::from("foo")), T(0));
+ let f1 = U(S(Foo::from("foo")), T(0));
let c = || {
let _ = &f1;
//~^ ERROR: `Clone` trait implementation for closure
impl Clone for U1 {
fn clone(&self) -> Self {
- U1(S(String::from("foo")), T(0), S(String::from("bar")))
+ U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
}
}
fn test_capturing_several_disjoint_fields_individually_1() {
- let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
let _ = &f1;
//~^ ERROR: `Clone` trait implementation for closure
}
fn test_capturing_several_disjoint_fields_individually_2() {
- let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
let _ = &f1;
//~^ ERROR: `Clone` trait implementation for closure and drop order
use std::thread;
-struct S(String);
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+impl Foo {
+ fn from(s: &str) -> Self {
+ Self(String::from(s))
+ }
+}
+
+
+struct S(Foo);
#[derive(Clone)]
struct T(i32);
impl Clone for U {
fn clone(&self) -> Self {
- U(S(String::from("Hello World")), T(0))
+ U(S(Foo::from("Hello World")), T(0))
}
}
fn test_multi_issues() {
- let f1 = U(S(String::from("foo")), T(0));
- let f2 = U(S(String::from("bar")), T(0));
+ let f1 = U(S(Foo::from("foo")), T(0));
+ let f2 = U(S(Foo::from("bar")), T(0));
let c = || {
//~^ ERROR: `Clone` trait implementation for closure and drop order
//~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
//~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
fn test_capturing_all_disjoint_fields_individually() {
- let f1 = U(S(String::from("foo")), T(0));
+ let f1 = U(S(Foo::from("foo")), T(0));
let c = || {
//~^ ERROR: `Clone` trait implementation for closure
//~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
impl Clone for U1 {
fn clone(&self) -> Self {
- U1(S(String::from("foo")), T(0), S(String::from("bar")))
+ U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
}
}
fn test_capturing_several_disjoint_fields_individually_1() {
- let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
//~^ ERROR: `Clone` trait implementation for closure
//~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
}
fn test_capturing_several_disjoint_fields_individually_2() {
- let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
//~^ ERROR: `Clone` trait implementation for closure and drop order
//~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/multi_diagnostics.rs:23:13
+ --> $DIR/multi_diagnostics.rs:38:13
|
LL | let c = || {
| ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
|
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:42:13
+ --> $DIR/multi_diagnostics.rs:57:13
|
LL | let c = || {
| ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
|
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:67:13
+ --> $DIR/multi_diagnostics.rs:82:13
|
LL | let c = || {
| ^^
|
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/multi_diagnostics.rs:86:13
+ --> $DIR/multi_diagnostics.rs:101:13
|
LL | let c = || {
| ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
|
error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:119:19
+ --> $DIR/multi_diagnostics.rs:134:19
|
LL | thread::spawn(move || unsafe {
| ^^^^^^^^^^^^^^
fn test8_drop_order_and_blocks() {
{
let tuple =
- (String::from("foo"), String::from("bar"));
+ (Foo(0), Foo(1));
{
let c = || {
let _ = &tuple;
fn test9_drop_order_and_nested_closures() {
let tuple =
- (String::from("foo"), String::from("bar"));
+ (Foo(0), Foo(1));
let b = || {
let c = || {
let _ = &tuple;
b();
}
+// Test that we migrate if drop order of Vec<T> would be affected if T is a significant drop type
+fn test10_vec_of_significant_drop_type() {
+
+ let tup = (Foo(0), vec![Foo(3)]);
+
+ let _c = || { let _ = &tup; tup.0 };
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tup` to be fully captured
+ //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+}
+//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+
fn main() {
test1_all_need_migration();
test2_only_precise_paths_need_migration();
test7_move_closures_non_copy_types_might_need_migration();
test8_drop_order_and_blocks();
test9_drop_order_and_nested_closures();
+ test10_vec_of_significant_drop_type();
}
fn test8_drop_order_and_blocks() {
{
let tuple =
- (String::from("foo"), String::from("bar"));
+ (Foo(0), Foo(1));
{
let c = || {
//~^ ERROR: drop order
fn test9_drop_order_and_nested_closures() {
let tuple =
- (String::from("foo"), String::from("bar"));
+ (Foo(0), Foo(1));
let b = || {
let c = || {
//~^ ERROR: drop order
b();
}
+// Test that we migrate if drop order of Vec<T> would be affected if T is a significant drop type
+fn test10_vec_of_significant_drop_type() {
+
+ let tup = (Foo(0), vec![Foo(3)]);
+
+ let _c = || tup.0;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tup` to be fully captured
+ //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+}
+//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+
fn main() {
test1_all_need_migration();
test2_only_precise_paths_need_migration();
test7_move_closures_non_copy_types_might_need_migration();
test8_drop_order_and_blocks();
test9_drop_order_and_nested_closures();
+ test10_vec_of_significant_drop_type();
}
LL + let _ = &tuple;
|
-error: aborting due to 9 previous errors
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:201:18
+ |
+LL | let _c = || tup.0;
+ | ^^^-----
+ | |
+ | in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+...
+LL | }
+ | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `tup` to be fully captured
+ |
+LL | let _c = || { let _ = &tup; tup.0 };
+ | +++++++++++++++ +
+
+error: aborting due to 10 previous errors
--- /dev/null
+// edition:2021
+
+// Tests that in cases where we individually capture all the fields of a type,
+// we still drop them in the order they would have been dropped in the 2018 edition.
+
+// NOTE: It is *critical* that the order of the min capture NOTES in the stderr output
+// does *not* change!
+
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct HasDrop;
+impl Drop for HasDrop {
+ fn drop(&mut self) {
+ println!("dropped");
+ }
+}
+
+fn test_one() {
+ let a = (HasDrop, HasDrop);
+ let b = (HasDrop, HasDrop);
+
+ let c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ || {
+ //~^ ERROR: Min Capture analysis includes:
+ //~| ERROR
+ println!("{:?}", a.0);
+ //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow
+ //~| NOTE
+ println!("{:?}", a.1);
+ //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow
+ //~| NOTE
+
+ println!("{:?}", b.0);
+ //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow
+ //~| NOTE
+ println!("{:?}", b.1);
+ //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow
+ //~| NOTE
+ };
+}
+
+fn test_two() {
+ let a = (HasDrop, HasDrop);
+ let b = (HasDrop, HasDrop);
+
+ let c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ || {
+ //~^ ERROR: Min Capture analysis includes:
+ //~| ERROR
+ println!("{:?}", a.1);
+ //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow
+ //~| NOTE
+ println!("{:?}", a.0);
+ //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow
+ //~| NOTE
+
+ println!("{:?}", b.1);
+ //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow
+ //~| NOTE
+ println!("{:?}", b.0);
+ //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow
+ //~| NOTE
+ };
+}
+
+fn test_three() {
+ let a = (HasDrop, HasDrop);
+ let b = (HasDrop, HasDrop);
+
+ let c = #[rustc_capture_analysis]
+ //~^ ERROR: attributes on expressions are experimental
+ //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+ || {
+ //~^ ERROR: Min Capture analysis includes:
+ //~| ERROR
+ println!("{:?}", b.1);
+ //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow
+ //~| NOTE
+ println!("{:?}", a.1);
+ //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow
+ //~| NOTE
+ println!("{:?}", a.0);
+ //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow
+ //~| NOTE
+
+ println!("{:?}", b.0);
+ //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow
+ //~| NOTE
+ };
+}
+
+fn main() {
+ test_one();
+ test_two();
+ test_three();
+}
--- /dev/null
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/preserve_field_drop_order.rs:23:13
+ |
+LL | let c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/preserve_field_drop_order.rs:49:13
+ |
+LL | let c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/preserve_field_drop_order.rs:75:13
+ |
+LL | let c = #[rustc_capture_analysis]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: First Pass analysis includes:
+ --> $DIR/preserve_field_drop_order.rs:26:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | println!("{:?}", a.0);
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing a[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:29:26
+ |
+LL | println!("{:?}", a.0);
+ | ^^^
+note: Capturing a[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:32:26
+ |
+LL | println!("{:?}", a.1);
+ | ^^^
+note: Capturing b[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:36:26
+ |
+LL | println!("{:?}", b.0);
+ | ^^^
+note: Capturing b[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:39:26
+ |
+LL | println!("{:?}", b.1);
+ | ^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/preserve_field_drop_order.rs:26:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | println!("{:?}", a.0);
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Min Capture a[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:29:26
+ |
+LL | println!("{:?}", a.0);
+ | ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:32:26
+ |
+LL | println!("{:?}", a.1);
+ | ^^^
+note: Min Capture b[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:36:26
+ |
+LL | println!("{:?}", b.0);
+ | ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:39:26
+ |
+LL | println!("{:?}", b.1);
+ | ^^^
+
+error: First Pass analysis includes:
+ --> $DIR/preserve_field_drop_order.rs:52:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | println!("{:?}", a.1);
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing a[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:55:26
+ |
+LL | println!("{:?}", a.1);
+ | ^^^
+note: Capturing a[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:58:26
+ |
+LL | println!("{:?}", a.0);
+ | ^^^
+note: Capturing b[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:62:26
+ |
+LL | println!("{:?}", b.1);
+ | ^^^
+note: Capturing b[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:65:26
+ |
+LL | println!("{:?}", b.0);
+ | ^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/preserve_field_drop_order.rs:52:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | println!("{:?}", a.1);
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Min Capture a[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:58:26
+ |
+LL | println!("{:?}", a.0);
+ | ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:55:26
+ |
+LL | println!("{:?}", a.1);
+ | ^^^
+note: Min Capture b[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:65:26
+ |
+LL | println!("{:?}", b.0);
+ | ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:62:26
+ |
+LL | println!("{:?}", b.1);
+ | ^^^
+
+error: First Pass analysis includes:
+ --> $DIR/preserve_field_drop_order.rs:78:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | println!("{:?}", b.1);
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Capturing b[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:81:26
+ |
+LL | println!("{:?}", b.1);
+ | ^^^
+note: Capturing a[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:84:26
+ |
+LL | println!("{:?}", a.1);
+ | ^^^
+note: Capturing a[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:87:26
+ |
+LL | println!("{:?}", a.0);
+ | ^^^
+note: Capturing b[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:91:26
+ |
+LL | println!("{:?}", b.0);
+ | ^^^
+
+error: Min Capture analysis includes:
+ --> $DIR/preserve_field_drop_order.rs:78:5
+ |
+LL | / || {
+LL | |
+LL | |
+LL | | println!("{:?}", b.1);
+... |
+LL | |
+LL | | };
+ | |_____^
+ |
+note: Min Capture b[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:91:26
+ |
+LL | println!("{:?}", b.0);
+ | ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:81:26
+ |
+LL | println!("{:?}", b.1);
+ | ^^^
+note: Min Capture a[(0, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:87:26
+ |
+LL | println!("{:?}", a.0);
+ | ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+ --> $DIR/preserve_field_drop_order.rs:84:26
+ |
+LL | println!("{:?}", a.1);
+ | ^^^
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// run-pass
+// check-run-results
+// revisions: twenty_eighteen twenty_twentyone
+// [twenty_eighteen]compile-flags: --edition 2018
+// [twenty_twentyone]compile-flags: --edition 2021
+
+#[derive(Debug)]
+struct Dropable(&'static str);
+
+impl Drop for Dropable {
+ fn drop(&mut self) {
+ println!("Dropping {}", self.0)
+ }
+}
+
+#[derive(Debug)]
+struct A {
+ x: Dropable,
+ y: Dropable,
+}
+
+#[derive(Debug)]
+struct B {
+ c: A,
+ d: A,
+}
+
+#[derive(Debug)]
+struct R<'a> {
+ c: &'a A,
+ d: &'a A,
+}
+
+fn main() {
+ let a = A { x: Dropable("x"), y: Dropable("y") };
+
+ let c = move || println!("{:?} {:?}", a.y, a.x);
+
+ c();
+
+ let b = B {
+ c: A { x: Dropable("b.c.x"), y: Dropable("b.c.y") },
+ d: A { x: Dropable("b.d.x"), y: Dropable("b.d.y") },
+ };
+
+ let d = move || println!("{:?} {:?} {:?} {:?}", b.d.y, b.d.x, b.c.y, b.c.x);
+
+ d();
+
+ let r = R {
+ c: &A { x: Dropable("r.c.x"), y: Dropable("r.c.y") },
+ d: &A { x: Dropable("r.d.x"), y: Dropable("r.d.y") },
+ };
+
+ let e = move || println!("{:?} {:?} {:?} {:?}", r.d.y, r.d.x, r.c.y, r.c.x);
+
+ e();
+}
--- /dev/null
+Dropable("y") Dropable("x")
+Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x")
+Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x")
+Dropping r.d.x
+Dropping r.d.y
+Dropping r.c.x
+Dropping r.c.y
+Dropping b.c.x
+Dropping b.c.y
+Dropping b.d.x
+Dropping b.d.y
+Dropping x
+Dropping y
--- /dev/null
+Dropable("y") Dropable("x")
+Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x")
+Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x")
+Dropping r.d.x
+Dropping r.d.y
+Dropping r.c.x
+Dropping r.c.y
+Dropping b.c.x
+Dropping b.c.y
+Dropping b.d.x
+Dropping b.d.y
+Dropping x
+Dropping y
// run-pass
#![allow(unused_braces)]
-#![feature(box_syntax)]
use std::cell::RefCell;
use std::fmt::Debug;
static TEST_BAD: &mut i32 = {
&mut *(box 0)
//~^ ERROR could not evaluate static initializer
- //~| NOTE heap allocations
+ //~| NOTE calling non-const function `alloc::alloc::exchange_malloc`
};
--> $DIR/box.rs:10:11
|
LL | &mut *(box 0)
- | ^^^^^^^ "heap allocations via `box` keyword" needs an rfc before being allowed inside constants
+ | ^^^^^^^ calling non-const function `alloc::alloc::exchange_malloc`
warning: skipping const checks
|
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
// This is a regression test that the metadata for the
// name_pool::methods impl in the other crate is reachable from this
// crate.
pub fn main() {
use crate_method_reexport_grrrrrrr2::rust::add;
use crate_method_reexport_grrrrrrr2::rust::cx;
- let x: Box<_> = box ();
+ let x: Box<_> = Box::new(());
x.cx();
let y = ();
y.add("hi".to_string());
-#![feature(box_syntax)]
-
use std::cell::RefCell;
pub struct Entry<A,B> {
fn eq_int(a: isize, b: isize) -> bool { a == b }
return alist {
eq_fn: eq_int,
- data: box RefCell::new(Vec::new()),
+ data: Box::new(RefCell::new(Vec::new())),
};
}
fn eq_int(a: isize, b: isize) -> bool { a == b }
return alist {
eq_fn: eq_int,
- data: box RefCell::new(Vec::new()),
+ data: Box::new(RefCell::new(Vec::new())),
};
}
// run-pass
// aux-build:cci_borrow_lib.rs
-#![feature(box_syntax)]
-
extern crate cci_borrow_lib;
use cci_borrow_lib::foo;
pub fn main() {
- let p: Box<_> = box 22;
+ let p: Box<_> = Box::new(22);
let r = foo(&*p);
println!("r={}", r);
assert_eq!(r, 22);
// Test that when a trait impl changes, fns whose body uses that trait
// must also be recompiled.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-assoc-type-codegen
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(warnings)]
error: OK
- --> $DIR/dep-graph-assoc-type-codegen.rs:28:5
+ --> $DIR/dep-graph-assoc-type-codegen.rs:29:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that immediate callers have to change when callee changes, but
// not callers' callers.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-caller-callee
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(dead_code)]
error: OK
- --> $DIR/dep-graph-caller-callee.rs:20:5
+ --> $DIR/dep-graph-caller-callee.rs:21:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `x` to `typeck`
- --> $DIR/dep-graph-caller-callee.rs:31:5
+ --> $DIR/dep-graph-caller-callee.rs:32:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test cases where a changing struct appears in the signature of fns
// and methods.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-struct-signature
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(dead_code)]
error: no path from `WillChange` to `type_of`
- --> $DIR/dep-graph-struct-signature.rs:27:5
+ --> $DIR/dep-graph-struct-signature.rs:28:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `associated_item`
- --> $DIR/dep-graph-struct-signature.rs:28:5
+ --> $DIR/dep-graph-struct-signature.rs:29:5
|
LL | #[rustc_then_this_would_need(associated_item)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `trait_def`
- --> $DIR/dep-graph-struct-signature.rs:29:5
+ --> $DIR/dep-graph-struct-signature.rs:30:5
|
LL | #[rustc_then_this_would_need(trait_def)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:31:9
+ --> $DIR/dep-graph-struct-signature.rs:32:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:35:5
+ --> $DIR/dep-graph-struct-signature.rs:36:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:36:5
+ --> $DIR/dep-graph-struct-signature.rs:37:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:39:5
+ --> $DIR/dep-graph-struct-signature.rs:40:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:40:5
+ --> $DIR/dep-graph-struct-signature.rs:41:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:45:5
+ --> $DIR/dep-graph-struct-signature.rs:46:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:47:9
+ --> $DIR/dep-graph-struct-signature.rs:48:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:48:9
+ --> $DIR/dep-graph-struct-signature.rs:49:9
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:52:5
+ --> $DIR/dep-graph-struct-signature.rs:53:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:54:9
+ --> $DIR/dep-graph-struct-signature.rs:55:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:55:9
+ --> $DIR/dep-graph-struct-signature.rs:56:9
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:60:9
+ --> $DIR/dep-graph-struct-signature.rs:61:9
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-struct-signature.rs:62:9
+ --> $DIR/dep-graph-struct-signature.rs:63:9
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `type_of`
- --> $DIR/dep-graph-struct-signature.rs:67:5
+ --> $DIR/dep-graph-struct-signature.rs:68:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `type_of`
- --> $DIR/dep-graph-struct-signature.rs:74:5
+ --> $DIR/dep-graph-struct-signature.rs:75:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `fn_sig`
- --> $DIR/dep-graph-struct-signature.rs:76:9
+ --> $DIR/dep-graph-struct-signature.rs:77:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `fn_sig`
- --> $DIR/dep-graph-struct-signature.rs:80:5
+ --> $DIR/dep-graph-struct-signature.rs:81:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `fn_sig`
- --> $DIR/dep-graph-struct-signature.rs:83:5
+ --> $DIR/dep-graph-struct-signature.rs:84:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `typeck`
- --> $DIR/dep-graph-struct-signature.rs:84:5
+ --> $DIR/dep-graph-struct-signature.rs:85:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that adding an impl to a trait `Foo` DOES affect functions
// that only use `Bar` if they have methods in common.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits-same-method
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(dead_code)]
error: OK
- --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5
+ --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:33:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `x::<impl Foo for u32>` to `typeck`
- --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5
+ --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:42:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that adding an impl to a trait `Foo` does not affect functions
// that only use `Bar`, so long as they do not have methods in common.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(warnings)]
error: no path from `x::<impl Foo for char>` to `typeck`
- --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5
+ --> $DIR/dep-graph-trait-impl-two-traits.rs:32:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `x::<impl Foo for char>` to `typeck`
- --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5
+ --> $DIR/dep-graph-trait-impl-two-traits.rs:41:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that when a trait impl changes, fns whose body uses that trait
// must also be recompiled.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(warnings)]
error: OK
- --> $DIR/dep-graph-trait-impl.rs:27:5
+ --> $DIR/dep-graph-trait-impl.rs:28:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-trait-impl.rs:32:5
+ --> $DIR/dep-graph-trait-impl.rs:33:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-trait-impl.rs:37:5
+ --> $DIR/dep-graph-trait-impl.rs:38:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-trait-impl.rs:42:5
+ --> $DIR/dep-graph-trait-impl.rs:43:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `x::<impl Foo for char>` to `typeck`
- --> $DIR/dep-graph-trait-impl.rs:55:5
+ --> $DIR/dep-graph-trait-impl.rs:56:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that changing what a `type` points to does not go unnoticed.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-type-alias
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(dead_code)]
error: no path from `TypeAlias` to `type_of`
- --> $DIR/dep-graph-type-alias.rs:17:1
+ --> $DIR/dep-graph-type-alias.rs:18:1
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:19:5
+ --> $DIR/dep-graph-type-alias.rs:20:5
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `TypeAlias` to `type_of`
- --> $DIR/dep-graph-type-alias.rs:24:1
+ --> $DIR/dep-graph-type-alias.rs:25:1
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:27:9
+ --> $DIR/dep-graph-type-alias.rs:28:9
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `TypeAlias` to `type_of`
- --> $DIR/dep-graph-type-alias.rs:33:1
+ --> $DIR/dep-graph-type-alias.rs:34:1
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:35:5
+ --> $DIR/dep-graph-type-alias.rs:36:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `TypeAlias` to `type_of`
- --> $DIR/dep-graph-type-alias.rs:41:1
+ --> $DIR/dep-graph-type-alias.rs:42:1
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:43:5
+ --> $DIR/dep-graph-type-alias.rs:44:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:44:5
+ --> $DIR/dep-graph-type-alias.rs:45:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:48:1
+ --> $DIR/dep-graph-type-alias.rs:49:1
|
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:51:1
+ --> $DIR/dep-graph-type-alias.rs:52:1
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
- --> $DIR/dep-graph-type-alias.rs:52:1
+ --> $DIR/dep-graph-type-alias.rs:53:1
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that changing what a `type` points to does not go unnoticed
// by the variance analysis.
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-variance-alias
+// incremental
+// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(dead_code)]
error: OK
- --> $DIR/dep-graph-variance-alias.rs:18:1
+ --> $DIR/dep-graph-variance-alias.rs:19:1
|
LL | #[rustc_then_this_would_need(variances_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
- let x: Box<isize> = box 10;
+ let x: Box<isize> = Box::new(10);
let _y: isize = *x;
}
--> $DIR/deriving-copyclone.rs:31:13
|
LL | is_copy(B { a: 1, b: C });
- | ------- ^^^^^^^^^^^^^^^^
- | | |
- | | expected an implementor of trait `Copy`
- | | help: consider borrowing here: `&B { a: 1, b: C }`
+ | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy`
+ | |
| required by a bound introduced by this call
|
note: required because of the requirements on the impl of `Copy` for `B<C>`
LL | fn is_copy<T: Copy>(_: T) {}
| ^^^^ required by this bound in `is_copy`
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+ |
+LL | is_copy(&B { a: 1, b: C });
+ | +
error[E0277]: the trait bound `C: Clone` is not satisfied
--> $DIR/deriving-copyclone.rs:32:14
|
LL | is_clone(B { a: 1, b: C });
- | -------- ^^^^^^^^^^^^^^^^
- | | |
- | | expected an implementor of trait `Clone`
- | | help: consider borrowing here: `&B { a: 1, b: C }`
+ | -------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
+ | |
| required by a bound introduced by this call
|
note: required because of the requirements on the impl of `Clone` for `B<C>`
LL | fn is_clone<T: Clone>(_: T) {}
| ^^^^^ required by this bound in `is_clone`
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+ |
+LL | is_clone(&B { a: 1, b: C });
+ | +
error[E0277]: the trait bound `D: Copy` is not satisfied
--> $DIR/deriving-copyclone.rs:35:13
|
LL | is_copy(B { a: 1, b: D });
- | ------- ^^^^^^^^^^^^^^^^
- | | |
- | | expected an implementor of trait `Copy`
- | | help: consider borrowing here: `&B { a: 1, b: D }`
+ | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy`
+ | |
| required by a bound introduced by this call
|
note: required because of the requirements on the impl of `Copy` for `B<D>`
LL | fn is_copy<T: Copy>(_: T) {}
| ^^^^ required by this bound in `is_copy`
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+ |
+LL | is_copy(&B { a: 1, b: D });
+ | +
error: aborting due to 3 previous errors
// run-pass
-#![feature(box_syntax)]
-
use std::default::Default;
#[derive(Default)]
// reference work properly.
#![feature(box_patterns)]
-#![feature(box_syntax)]
trait T { fn foo(&self) {} }
impl T for isize {}
+
fn main() {
// For an expression of the form:
//
// n == m
let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced
let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced
- let box x = box 1isize as Box<dyn T>;
+ let box x = Box::new(1isize) as Box<dyn T>;
//~^ ERROR type `Box<dyn T>` cannot be dereferenced
// n > m
//~^ ERROR mismatched types
//~| expected trait object `dyn T`
//~| found reference `&_`
- let box box x = box 1isize as Box<dyn T>;
+ let box box x = Box::new(1isize) as Box<dyn T>;
//~^ ERROR mismatched types
//~| expected trait object `dyn T`
//~| found struct `Box<_>`
error[E0033]: type `Box<dyn T>` cannot be dereferenced
--> $DIR/destructure-trait-ref.rs:28:9
|
-LL | let box x = box 1isize as Box<dyn T>;
+LL | let box x = Box::new(1isize) as Box<dyn T>;
| ^^^^^ type `Box<dyn T>` cannot be dereferenced
error[E0308]: mismatched types
error[E0308]: mismatched types
--> $DIR/destructure-trait-ref.rs:40:13
|
-LL | let box box x = box 1isize as Box<dyn T>;
- | ^^^^^ ------------------------ this expression has type `Box<dyn T>`
+LL | let box box x = Box::new(1isize) as Box<dyn T>;
+ | ^^^^^ ------------------------------ this expression has type `Box<dyn T>`
| |
| expected trait object `dyn T`, found struct `Box`
|
// pretty-expanded FIXME #23616
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
-
enum t { foo(Box<isize>), }
pub fn main() {
- let tt = t::foo(box 10);
+ let tt = t::foo(Box::new(10));
match tt { t::foo(_z) => { } }
}
// Test that destructor on a struct runs successfully after the struct
// is boxed and converted to an object.
-#![feature(box_syntax)]
-
static mut value: usize = 0;
struct Cat {
pub fn main() {
{
- let x = box Cat {name: 22};
+ let x = Box::new(Cat {name: 22});
let nyan: Box<dyn Dummy> = x as Box<dyn Dummy>;
}
unsafe {
#![allow(unused_variables)]
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::thread;
use std::sync::mpsc::{channel, Sender};
let (sender, receiver) = channel();
{
- let v = Foo::NestedVariant(box 42, SendOnDrop { sender: sender.clone() }, sender);
+ let v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender);
}
assert_eq!(receiver.recv().unwrap(), Message::DestructorRan);
assert_eq!(receiver.recv().unwrap(), Message::Dropped);
let (sender, receiver) = channel();
let t = {
thread::spawn(move|| {
- let mut v = Foo::NestedVariant(box 42, SendOnDrop {
+ let mut v = Foo::NestedVariant(Box::new(42), SendOnDrop {
sender: sender.clone()
}, sender.clone());
- v = Foo::NestedVariant(box 42,
+ v = Foo::NestedVariant(Box::new(42),
SendOnDrop { sender: sender.clone() },
sender.clone());
v = Foo::SimpleVariant(sender.clone());
#![allow(type_alias_bounds)]
#![allow(unused_features)]
-#![feature(box_syntax)]
#![feature(unsized_tuple_coercion)]
type Fat<T: ?Sized> = (isize, &'static str, T);
// run-pass
#![allow(type_alias_bounds)]
-#![feature(box_syntax)]
#![feature(unsized_tuple_coercion)]
type Fat<T: ?Sized> = (isize, &'static str, T);
assert_eq!((*f2)[1], 2);
// Nested Box.
- let f1 : Box<Fat<[isize; 3]>> = box (5, "some str", [1, 2, 3]);
+ let f1 : Box<Fat<[isize; 3]>> = Box::new((5, "some str", [1, 2, 3]));
foo(&*f1);
let f2 : Box<Fat<[isize]>> = f1;
foo(&*f2);
// run-pass
#![allow(unused_braces)]
-#![feature(box_syntax)]
fn test_generic<T, F>(expected: Box<T>, eq: F) where T: Clone, F: FnOnce(Box<T>, Box<T>) -> bool {
let actual: Box<T> = { expected.clone() };
println!("{}", *b2);
return *b1 == *b2;
}
- test_generic::<bool, _>(box true, compare_box);
+ test_generic::<bool, _>(Box::new(true), compare_box);
}
pub fn main() { test_box(); }
// run-pass
#![allow(unused_braces)]
-#![feature(box_syntax)]
fn test_generic<T, F>(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> bool {
let actual: T = { expected.clone() };
fn test_vec() {
fn compare_vec(v1: Box<isize>, v2: Box<isize>) -> bool { return v1 == v2; }
- test_generic::<Box<isize>, _>(box 1, compare_vec);
+ test_generic::<Box<isize>, _>(Box::new(1), compare_vec);
}
pub fn main() { test_vec(); }
// run-pass
#![allow(unused_braces)]
-#![feature(box_syntax)]
-pub fn main() { let x: Box<_> = { box 100 }; assert_eq!(*x, 100); }
+pub fn main() { let x: Box<_> = { Box::new(100) }; assert_eq!(*x, 100); }
// run-pass
-#![feature(box_syntax)]
-
// Tests for if as expressions returning boxed types
fn test_box() {
- let rs: Box<_> = if true { box 100 } else { box 101 };
+ let rs: Box<_> = if true { Box::new(100) } else { Box::new(101) };
assert_eq!(*rs, 100);
}
-#![feature(box_syntax)]
-
fn needs_fn<F>(x: F) where F: Fn(isize) -> isize {}
+
+
fn main() {
- let _: () = (box |_: isize| {}) as Box<dyn FnOnce(isize)>;
+ let _: () = Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>;
//~^ ERROR mismatched types
//~| expected unit type `()`
//~| found struct `Box<dyn FnOnce(isize)>`
- let _: () = (box |_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
+ let _: () = Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
//~^ ERROR mismatched types
//~| expected unit type `()`
//~| found struct `Box<dyn Fn(isize, isize)>`
- let _: () = (box || -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
+ let _: () = Box::new(|| -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
//~^ ERROR mismatched types
//~| expected unit type `()`
//~| found struct `Box<dyn FnMut() -> isize>`
error[E0308]: mismatched types
--> $DIR/fn-trait-formatting.rs:6:17
|
-LL | let _: () = (box |_: isize| {}) as Box<dyn FnOnce(isize)>;
- | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
+LL | let _: () = Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>;
+ | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
| |
| expected due to this
|
error[E0308]: mismatched types
--> $DIR/fn-trait-formatting.rs:10:17
|
-LL | let _: () = (box |_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
- | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
+LL | let _: () = Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
+ | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
| |
| expected due to this
|
error[E0308]: mismatched types
--> $DIR/fn-trait-formatting.rs:14:17
|
-LL | let _: () = (box || -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
- | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
+LL | let _: () = Box::new(|| -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
+ | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
| |
| expected due to this
|
|
= help: the trait `Fn<(isize,)>` is not implemented for `{integer}`
note: required by a bound in `needs_fn`
- --> $DIR/fn-trait-formatting.rs:3:31
+ --> $DIR/fn-trait-formatting.rs:1:31
|
LL | fn needs_fn<F>(x: F) where F: Fn(isize) -> isize {}
| ^^^^^^^^^^^^^^^^^^ required by this bound in `needs_fn`
// This test verifies that temporaries created for `while`'s and `if`
// conditions are dropped after the condition is evaluated.
-#![feature(box_syntax)]
-
struct Temporary;
static mut DROPPED: isize = 0;
fn do_stuff(&self) -> bool {true}
}
-fn borrow() -> Box<Temporary> { box Temporary }
+fn borrow() -> Box<Temporary> { Box::new(Temporary) }
pub fn main() {
--> $DIR/gated-bad-feature.rs:5:1
|
LL | #![feature]
- | ^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]`
+ | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]`
error: malformed `feature` attribute input
--> $DIR/gated-bad-feature.rs:6:1
|
LL | #![feature = "foo"]
- | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]`
+ | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]`
error: aborting due to 5 previous errors
|
= note: expected type `for<'a> Generator<&'a mut bool>`
found type `Generator<&mut bool>`
+note: the lifetime requirement is introduced here
+ --> $DIR/resume-arg-late-bound.rs:8:17
+ |
+LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
// run-pass
-#![feature(box_syntax)]
fn id<T:Send>(t: T) -> T { return t; }
pub fn main() {
- let expected: Box<_> = box 100;
+ let expected: Box<_> = Box::new(100);
let actual = id::<Box<isize>>(expected.clone());
println!("{}", *actual);
assert_eq!(*expected, *actual);
// run-pass
-#![feature(box_syntax)]
struct Recbox<T> {x: Box<T>}
-fn reclift<T>(t: T) -> Recbox<T> { return Recbox {x: box t}; }
+fn reclift<T>(t: T) -> Recbox<T> { return Recbox { x: Box::new(t) }; }
pub fn main() {
let foo: isize = 17;
// run-pass
-#![feature(box_syntax)]
fn f<T>(x: Box<T>) -> Box<T> { return x; }
-pub fn main() { let x = f(box 3); println!("{}", *x); }
+pub fn main() {
+ let x = f(Box::new(3));
+ println!("{}", *x);
+}
// run-pass
-#![feature(box_syntax)]
trait Foo<T> {
fn get(&self) -> T;
}
pub fn main() {
- let x = box S { x: 1 };
+ let x = Box::new(S { x: 1 });
let y = x as Box<dyn Foo<isize>>;
assert_eq!(y.get(), 1);
}
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
enum list<T> { cons(Box<T>, Box<list<T>>), nil, }
pub fn main() {
let _a: list<isize> =
- list::cons::<isize>(box 10,
- box list::cons::<isize>(box 12,
- box list::cons::<isize>(box 13,
- box list::nil::<isize>)));
+ list::cons::<isize>(Box::new(10),
+ Box::new(list::cons::<isize>(Box::new(12),
+ Box::new(list::cons::<isize>(Box::new(13),
+ Box::new(list::nil::<isize>))))));
}
// pretty-expanded FIXME #23616
#![allow(unused_variables)]
-#![feature(box_syntax)]
enum option<T> { some(Box<T>), none, }
pub fn main() {
- let mut a: option<isize> = option::some::<isize>(box 10);
+ let mut a: option<isize> = option::some::<isize>(Box::new(10));
a = option::none::<isize>;
}
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct Triple<T> { x: T, y: T, z: T }
-fn box_it<T>(x: Triple<T>) -> Box<Triple<T>> { return box x; }
+fn box_it<T>(x: Triple<T>) -> Box<Triple<T>> { return Box::new(x); }
pub fn main() {
let x: Box<Triple<isize>> = box_it::<isize>(Triple{x: 1, y: 2, z: 3});
// error-pattern: reached the recursion limit while auto-dereferencing
-#![feature(box_syntax)]
+
use std::ops::Deref;
pub fn main() {
let mut x;
loop {
- x = box x;
+ x = Box::new(x);
x.foo;
x.bar();
}
error[E0308]: mismatched types
--> $DIR/infinite-autoderef.rs:20:13
|
-LL | x = box x;
- | ^^^^^ cyclic type of infinite size
- |
-help: try using a conversion method
- |
-LL | x = (box x).to_string();
- | + +++++++++++++
+LL | x = Box::new(x);
+ | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+ | |
+ | cyclic type of infinite size
error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
--> $DIR/infinite-autoderef.rs:25:5
#![allow(non_camel_case_types)]
#![allow(dead_code)]
-#![feature(box_syntax)]
use std::cell::Cell;
fn test_unique() {
let i = &Cell::new(0);
{
- let _a: Box<_> = box r(i);
+ let _a: Box<_> = Box::new(r(i));
}
assert_eq!(i.get(), 1);
}
fn test_unique_rec() {
let i = &Cell::new(0);
{
- let _a: Box<_> = box BoxR {
+ let _a: Box<_> = Box::new(BoxR {
x: r(i)
- };
+ });
}
assert_eq!(i.get(), 1);
}
// run-pass
-#![feature(box_syntax)]
#![feature(intrinsics)]
mod rusti {
pub fn main() {
unsafe {
- let mut x: Box<_> = box 1;
+ let mut x: Box<_> = Box::new(1);
assert_eq!(rusti::atomic_load(&*x), 1);
*x = 5;
--- /dev/null
+#![crate_type = foo!()] //~ ERROR malformed `crate_type` attribute
+
+macro_rules! foo {
+ () => {"rlib"};
+}
+
+fn main() {}
--- /dev/null
+error: malformed `crate_type` attribute input
+ --> $DIR/invalid-crate-type-macro.rs:1:1
+ |
+LL | #![crate_type = foo!()]
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
+
+error: aborting due to previous error
+
--> $DIR/invalid_crate_type_syntax.rs:2:1
|
LL | #![crate_type(lib)]
- | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]`
+ | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
error: aborting due to previous error
--> $DIR/issue-20605.rs:2:17
|
LL | for item in *things { *item = 0 }
- | ^^^^^^^
- | |
- | expected an implementor of trait `IntoIterator`
- | help: consider mutably borrowing here: `&mut *things`
+ | ^^^^^^^ expected an implementor of trait `IntoIterator`
|
= note: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator<Item = &'a mut u8>`
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider mutably borrowing here
+ |
+LL | for item in &mut *things { *item = 0 }
+ | ++++
error: aborting due to previous error
-#![feature(box_syntax)]
-
trait Foo {
}
+
+
impl<T:Copy> Foo for T {
}
fn take_param<T:Foo>(foo: &T) { }
fn main() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
take_param(&x);
//~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied
}
// Issue #14061: tests the interaction between generic implementation
// parameter bounds and trait objects.
-#![feature(box_syntax)]
+
use std::marker;
}
fn foo2<'a>() {
- let t: Box<S<String>> = box S(marker::PhantomData);
+ let t: Box<S<String>> = Box::new(S(marker::PhantomData));
let a = t as Box<dyn Gettable<String>>;
//~^ ERROR : Copy` is not satisfied
}
fn foo3<'a>() {
struct Foo; // does not impl Copy
- let t: Box<S<Foo>> = box S(marker::PhantomData);
+ let t: Box<S<Foo>> = Box::new(S(marker::PhantomData));
let a: Box<dyn Gettable<Foo>> = t;
//~^ ERROR : Copy` is not satisfied
}
// revisions: curr object_safe_for_dispatch
#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
-#![feature(box_syntax)]
+
use std::any::Any;
fn take_param<T:Foo>(foo: &T) { }
fn a() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
take_param(&x); //[curr]~ ERROR E0277
//[object_safe_for_dispatch]~^ ERROR E0277
}
fn b() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
let y = &x;
let z = &x as &dyn Foo;
//[curr]~^ ERROR E0038
--- /dev/null
+// Make sure that an error is reported if the `call` function of the
+// `fn`/`fn_mut` lang item is grossly ill-formed.
+
+#![feature(lang_items)]
+#![feature(no_core)]
+#![no_core]
+
+#[lang = "fn"]
+trait MyFn<T> {
+ const call: i32 = 42;
+ //~^ ERROR: `call` trait item in `fn` lang item must be a function
+}
+
+#[lang = "fn_mut"]
+trait MyFnMut<T> {
+ fn call(i: i32, j: i32) -> i32 { i + j }
+ //~^ ERROR: first argument of `call` in `fn_mut` lang item must be a reference
+}
+
+fn main() {
+ let a = || 42;
+ a();
+
+ let mut i = 0;
+ let mut b = || { i += 1; };
+ b();
+}
--- /dev/null
+error: `call` trait item in `fn` lang item must be a function
+ --> $DIR/fn-fn_mut-call-ill-formed.rs:10:5
+ |
+LL | const call: i32 = 42;
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: first argument of `call` in `fn_mut` lang item must be a reference
+ --> $DIR/fn-fn_mut-call-ill-formed.rs:16:16
+ |
+LL | fn call(i: i32, j: i32) -> i32 { i + j }
+ | ^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Regression test for the ICE reported in issue #83471.
+
+#![crate_type="lib"]
+#![feature(no_core)]
+#![no_core]
+
+#[lang = "sized"]
+//~^ ERROR: language items are subject to change [E0658]
+trait Sized {}
+
+#[lang = "fn"]
+//~^ ERROR: language items are subject to change [E0658]
+//~| ERROR: `fn` language item must be applied to a trait with 1 generic argument
+trait Fn {
+ fn call(export_name);
+ //~^ ERROR: expected type
+ //~| WARNING: anonymous parameters are deprecated
+ //~| WARNING: this is accepted in the current edition
+}
+fn call_through_fn_trait() {
+ a()
+ //~^ ERROR: cannot find function
+}
--- /dev/null
+error[E0573]: expected type, found built-in attribute `export_name`
+ --> $DIR/issue-83471.rs:15:13
+ |
+LL | fn call(export_name);
+ | ^^^^^^^^^^^ not a type
+
+error[E0425]: cannot find function `a` in this scope
+ --> $DIR/issue-83471.rs:21:5
+ |
+LL | a()
+ | ^ not found in this scope
+
+error[E0658]: language items are subject to change
+ --> $DIR/issue-83471.rs:7:1
+ |
+LL | #[lang = "sized"]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(lang_items)]` to the crate attributes to enable
+
+error[E0658]: language items are subject to change
+ --> $DIR/issue-83471.rs:11:1
+ |
+LL | #[lang = "fn"]
+ | ^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(lang_items)]` to the crate attributes to enable
+
+warning: anonymous parameters are deprecated and will be removed in the next edition.
+ --> $DIR/issue-83471.rs:15:13
+ |
+LL | fn call(export_name);
+ | ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name`
+ |
+ = note: `#[warn(anonymous_parameters)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+ = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
+
+error[E0718]: `fn` language item must be applied to a trait with 1 generic argument
+ --> $DIR/issue-83471.rs:11:1
+ |
+LL | #[lang = "fn"]
+ | ^^^^^^^^^^^^^^
+...
+LL | trait Fn {
+ | - this trait has 0 generic arguments
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0425, E0573, E0658, E0718.
+For more information about an error, try `rustc --explain E0425`.
#![allow(dead_code)]
// Make sure #1399 stays fixed
-#![feature(box_syntax)]
-
struct A { a: Box<isize> }
pub fn main() {
fn invoke<F>(f: F) where F: FnOnce() { f(); }
- let k: Box<_> = box 22;
+ let k: Box<_> = 22.into();
let _u = A {a: k.clone()};
invoke(|| println!("{}", k.clone()) )
}
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
fn leaky<T>(_t: T) { }
-pub fn main() { let x = box 10; leaky::<Box<isize>>(x); }
+pub fn main() {
+ let x = Box::new(10);
+ leaky::<Box<isize>>(x);
+}
|
LL | take_foo(|a| a);
| ^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-79187-2.rs:5:21
+ |
+LL | fn take_foo(_: impl Foo) {}
+ | ^^^
error[E0308]: mismatched types
--> $DIR/issue-79187-2.rs:9:5
|
= note: expected reference `&i32`
found reference `&i32`
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-79187-2.rs:5:21
+ |
+LL | fn take_foo(_: impl Foo) {}
+ | ^^^
error[E0308]: mismatched types
--> $DIR/issue-79187-2.rs:10:5
|
= note: expected reference `&i32`
found reference `&i32`
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-79187-2.rs:5:21
+ |
+LL | fn take_foo(_: impl Foo) {}
+ | ^^^
error: aborting due to 6 previous errors
|
LL | let f = |_| ();
| ^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-79187.rs:1:18
+ |
+LL | fn thing(x: impl FnOnce(&u32)) {}
+ | ^^^^^^^^^^^^
error: implementation of `FnOnce` is not general enough
--> $DIR/issue-79187.rs:5:5
|
= note: expected type `for<'r> Fn<(&'r T,)>`
found type `Fn<(&T,)>`
+note: the lifetime requirement is introduced here
+ --> $DIR/issue_74400.rs:8:34
+ |
+LL | fn f<T, S>(data: &[T], key: impl Fn(&T) -> S) {
+ | ^^^^^^^^^^^
error: implementation of `FnOnce` is not general enough
--> $DIR/issue_74400.rs:12:5
--- /dev/null
+// check-pass
+
+#![feature(register_tool)]
+#![register_tool(tool)]
+
+mod submodule;
+
+fn main() {
+ submodule::foo();
+}
--- /dev/null
+// ignore-test: not a test
+
+#[allow(tool::lint)]
+pub fn foo() {}
--> $DIR/lint-malformed.rs:1:1
|
LL | #![deny = "foo"]
- | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
+ | ^^^^^^^^^^^^^^^^ help: must be of the form: `#![deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
error[E0452]: malformed lint attribute input
--> $DIR/lint-malformed.rs:2:10
#![allow(dead_code)]
#![forbid(box_pointers)]
-#![feature(box_syntax)]
+
struct Foo {
x: Box<isize> //~ ERROR type uses owned
}
fn main() {
- let _x : Foo = Foo {x : box 10};
+ let _x: Foo = Foo { x : Box::new(10) };
//~^ ERROR type uses owned
}
error: type uses owned (Box type) pointers: Box<isize>
--> $DIR/lint-owned-heap-memory.rs:10:29
|
-LL | let _x : Foo = Foo {x : box 10};
- | ^^^^^^
+LL | let _x: Foo = Foo { x : Box::new(10) };
+ | ^^^^^^^^^^^^
error: aborting due to 2 previous errors
// check-pass
-#![feature(box_syntax)]
#![feature(box_patterns)]
+
#![warn(unused)] // UI tests pass `-A unused` (#43896)
struct SoulHistory {
};
// Boxed struct
- match box bag {
+ match Box::new(bag) {
box Large::Suit { case } => {} //~ WARNING unused variable: `case`
};
#![allow(non_camel_case_types)]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
enum list { cons(isize, Box<list>), nil, }
-pub fn main() { list::cons(10, box list::cons(11, box list::cons(12, box list::nil))); }
+pub fn main() {
+ list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
+}
-#![feature(box_syntax)]
-
fn take(_x: Box<isize>) {}
+
fn main() {
- let x: Box<isize> = box 25;
+ let x: Box<isize> = Box::new(25);
+
loop {
take(x); //~ ERROR use of moved value: `x`
}
error[E0382]: use of moved value: `x`
--> $DIR/liveness-move-call-arg.rs:9:14
|
-LL | let x: Box<isize> = box 25;
+LL | let x: Box<isize> = Box::new(25);
| - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
-LL | loop {
+...
LL | take(x);
| ^ value moved here, in previous iteration of loop
-#![feature(box_syntax)]
-
fn main() {
- let y: Box<isize> = box 42;
+
+ let y: Box<isize> = 42.into();
let mut x: Box<isize>;
+
loop {
println!("{}", y);
loop {
error[E0382]: use of moved value: `y`
--> $DIR/liveness-move-in-loop.rs:11:25
|
-LL | let y: Box<isize> = box 42;
+LL | let y: Box<isize> = 42.into();
| - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
...
LL | x = y;
-#![feature(box_syntax)]
-
fn main() {
- let y: Box<isize> = box 42;
+
+ let y: Box<isize> = 42.into();
let mut x: Box<isize>;
+
loop {
println!("{}", y); //~ ERROR borrow of moved value: `y`
while true { while true { while true { x = y; x.clone(); } } }
error[E0382]: borrow of moved value: `y`
--> $DIR/liveness-move-in-while.rs:7:24
|
-LL | let y: Box<isize> = box 42;
+LL | let y: Box<isize> = 42.into();
| - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
...
LL | println!("{}", y);
-#![feature(box_syntax)]
-
fn main() {
- let x: Box<_> = box 5;
+
+ let x: Box<_> = 5.into();
let y = x;
+
println!("{}", *x); //~ ERROR borrow of moved value: `x`
y.clone();
}
error[E0382]: borrow of moved value: `x`
--> $DIR/liveness-use-after-move.rs:6:20
|
-LL | let x: Box<_> = box 5;
+LL | let x: Box<_> = 5.into();
| - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
LL | let y = x;
| - value moved here
+LL |
LL | println!("{}", *x);
| ^^ value borrowed here after move
--- /dev/null
+// run-rustfix
+#[allow(unused_macros)]
+
+macro_rules! foo { //~ ERROR macro names aren't followed by a `!`
+ () => {};
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+#[allow(unused_macros)]
+
+macro_rules! foo! { //~ ERROR macro names aren't followed by a `!`
+ () => {};
+}
+
+fn main() {}
--- /dev/null
+error: macro names aren't followed by a `!`
+ --> $DIR/bang-after-name.rs:4:17
+ |
+LL | macro_rules! foo! {
+ | ^ help: remove the `!`
+
+error: aborting due to previous error
+
--> $DIR/malformed-plugin-1.rs:2:1
|
LL | #![plugin]
- | ^^^^^^^^^^ help: must be of the form: `#[plugin(name)]`
+ | ^^^^^^^^^^ help: must be of the form: `#![plugin(name)]`
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
--> $DIR/malformed-plugin-1.rs:2:1
--> $DIR/malformed-plugin-2.rs:2:1
|
LL | #![plugin="bleh"]
- | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name)]`
+ | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![plugin(name)]`
warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
--> $DIR/malformed-plugin-2.rs:2:1
-#![feature(box_syntax)]
-
use std::collections::HashMap;
+
+
trait Map<K, V>
{
fn get(&self, k: K) -> V { panic!() }
// Test that trait types printed in error msgs include the type arguments.
fn main() {
- let x: Box<HashMap<isize, isize>> = box HashMap::new();
+ let x: Box<HashMap<isize, isize>> = HashMap::new().into();
let x: Box<dyn Map<isize, isize>> = x;
let y: Box<dyn Map<usize, isize>> = Box::new(x);
//~^ ERROR `Box<dyn Map<isize, isize>>: Map<usize, isize>` is not satisfied
#![crate_type = "lib"]
-#![feature(box_syntax)]
-
static mut COUNT: u64 = 1;
pub fn get_count() -> u64 { unsafe { COUNT } }
Foo::baz(self);
Foo::baz(*x);
- Foo::qux(box self);
- Foo::qux(box *x);
+ Foo::qux(Box::new(self));
+ Foo::qux(Box::new(*x));
}
pub fn bar(&self) {
#![crate_type = "lib"]
-#![feature(box_syntax)]
-
static mut COUNT: u64 = 1;
pub fn get_count() -> u64 { unsafe { COUNT } }
// Test internal call.
Bar::foo1(&self);
Bar::foo2(self);
- Bar::foo3(box self);
+ Bar::foo3(Box::new(self));
Bar::bar1(&self);
Bar::bar2(self);
- Bar::bar3(box self);
+ Bar::bar3(Box::new(self));
}
}
// run-pass
// Test method calls with self as an argument (cross-crate)
-#![feature(box_syntax)]
-
// aux-build:method_self_arg1.rs
extern crate method_self_arg1;
use method_self_arg1::Foo;
// Test external call.
Foo::bar(&x);
Foo::baz(x);
- Foo::qux(box x);
+ Foo::qux(Box::new(x));
x.foo(&x);
// run-pass
// Test method calls with self as an argument (cross-crate)
-#![feature(box_syntax)]
-
// aux-build:method_self_arg2.rs
extern crate method_self_arg2;
use method_self_arg2::{Foo, Bar};
// Test external call.
Bar::foo1(&x);
Bar::foo2(x);
- Bar::foo3(box x);
+ Bar::foo3(Box::new(x));
Bar::bar1(&x);
Bar::bar2(x);
- Bar::bar3(box x);
+ Bar::bar3(Box::new(x));
x.run_trait();
// run-pass
// Test method calls with self as an argument
-#![feature(box_syntax)]
-
static mut COUNT: u64 = 1;
#[derive(Copy, Clone)]
// Test internal call.
Bar::foo1(&self);
Bar::foo2(self);
- Bar::foo3(box self);
+ Bar::foo3(Box::new(self));
Bar::bar1(&self);
Bar::bar2(self);
- Bar::bar3(box self);
+ Bar::bar3(Box::new(self));
}
}
// Test external call.
Bar::foo1(&x);
Bar::foo2(x);
- Bar::foo3(box x);
+ Bar::foo3(Box::new(x));
Bar::bar1(&x);
Bar::bar2(x);
- Bar::bar3(box x);
+ Bar::bar3(Box::new(x));
x.baz();
// run-pass
// Test method calls with self as an argument
-#![feature(box_syntax)]
-
static mut COUNT: usize = 1;
#[derive(Copy, Clone)]
Foo::baz(self);
Foo::baz(*x);
- Foo::qux(box self);
- Foo::qux(box *x);
+ Foo::qux(Box::new(self));
+ Foo::qux(Box::new(*x));
}
fn bar(&self) {
// Test external call.
Foo::bar(&x);
Foo::baz(x);
- Foo::qux(box x);
+ Foo::qux(Box::new(x));
x.foo(&x);
// codegen the call as `Foo::foo(&x)` and let the specific impl get
// chosen later.
-#![feature(box_syntax)]
-
trait Foo {
fn foo(&self) -> isize;
}
fn call_foo_other() -> isize {
let mut x: Vec<_> = Vec::new();
let y = x.foo();
- let z: Box<i32> = box 0;
+ let z: Box<i32> = Box::new(0);
x.push(z);
y
}
|
LL | baz(|_| ());
| ^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/closure-mismatch.rs:5:11
+ |
+LL | fn baz<T: Foo>(_: T) {}
+ | ^^^
error: aborting due to 2 previous errors
--- /dev/null
+#[path = 123] //~ ERROR malformed `path` attribute
+mod foo;
+
+fn main() {}
--- /dev/null
+error: malformed `path` attribute input
+ --> $DIR/path-invalid-form.rs:1:1
+ |
+LL | #[path = 123]
+ | ^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+
+error: aborting due to previous error
+
--- /dev/null
+macro_rules! foo {
+ () => {"bar.rs"};
+}
+
+#[path = foo!()] //~ ERROR malformed `path` attribute
+mod abc;
+
+fn main() {}
--- /dev/null
+error: malformed `path` attribute input
+ --> $DIR/path-macro.rs:5:1
+ |
+LL | #[path = foo!()]
+ | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+
+error: aborting due to previous error
+
// run-pass
#![allow(unused_mut)]
#![allow(dead_code)]
-#![feature(box_syntax)]
#[derive(Clone)]
struct Triple {
fn test(x: bool, foo: Box<Triple>) -> isize {
let bar = foo;
let mut y: Box<Triple>;
- if x { y = bar; } else { y = box Triple{x: 4, y: 5, z: 6}; }
+ if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); }
return y.y;
}
pub fn main() {
- let x: Box<_> = box Triple{x: 1, y: 2, z: 3};
+ let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3});
assert_eq!(test(true, x.clone()), 2);
assert_eq!(test(true, x.clone()), 2);
assert_eq!(test(true, x.clone()), 2);
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct X { x: isize, y: isize, z: isize }
pub fn main() {
- let x: Box<_> = box X{x: 1, y: 2, z: 3};
+ let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3});
let y = x;
assert_eq!(y.y, 2);
}
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct X { x: isize, y: isize, z: isize }
-pub fn main() { let x: Box<_> = box X {x: 1, y: 2, z: 3}; let y = x; assert_eq!(y.y, 2); }
+pub fn main() { let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); }
// run-pass
#![allow(unused_mut)]
#![allow(dead_code)]
-#![feature(box_syntax)]
#[derive(Clone)]
struct Triple {
fn test(x: bool, foo: Box<Triple>) -> isize {
let bar = foo;
let mut y: Box<Triple>;
- if x { y = bar; } else { y = box Triple {x: 4, y: 5, z: 6}; }
+ if x { y = bar; } else { y = Box::new(Triple {x: 4, y: 5, z: 6}); }
return y.y;
}
pub fn main() {
- let x: Box<_> = box Triple{x: 1, y: 2, z: 3};
+ let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3});
for _ in 0_usize..10000_usize {
assert_eq!(test(true, x.clone()), 2);
}
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct Triple {a: isize, b: isize, c: isize}
}
pub fn main() {
- let x = box Triple{a: 1, b: 2, c: 3};
+ let x = Box::new(Triple{a: 1, b: 2, c: 3});
let y = test(x);
assert_eq!(y.c, 3);
}
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct Triple { a: isize, b: isize, c: isize }
}
pub fn main() {
- let x = box Triple{a: 1, b: 2, c: 3};
+ let x = Box::new(Triple{ a: 1, b: 2, c: 3 });
let y = test(x);
assert_eq!(y.c, 3);
}
// run-pass
-#![feature(box_syntax)]
fn test(foo: Box<Vec<isize>> ) { assert_eq!((*foo)[0], 10); }
pub fn main() {
- let x = box vec![10];
+ let x = Box::new(vec![10]);
// Test forgetting a local by move-in
test(x);
// Test forgetting a temporary by move-in.
- test(box vec![10]);
+ test(Box::new(vec![10]));
}
// run-pass
-#![feature(box_syntax)]
fn test(foo: Box<Vec<isize>>) { assert_eq!((*foo)[0], 10); }
pub fn main() {
- let x = box vec![10];
+ let x = Box::new(vec![10]);
// Test forgetting a local by move-in
test(x);
// Test forgetting a temporary by move-in.
- test(box vec![10]);
+ test(Box::new(vec![10]));
}
// that assumption did not hold, at least not in the long run (namely,
// overlapping patterns were turned into warnings rather than errors).
-#![feature(box_syntax)]
+
fn main() {
- let x: Box<_> = box 1;
+ let x: Box<_> = Box::new(1);
let v = (1, 2);
error[E0382]: use of moved value: `x`
--> $DIR/move-guard-same-consts.rs:20:24
|
-LL | let x: Box<_> = box 1;
+LL | let x: Box<_> = Box::new(1);
| - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
...
LL | (1, 2) if take(x) => (),
-#![feature(box_syntax)]
-
pub fn main() {
- let x: Box<_> = box 1;
+
+
+ let x: Box<_> = Box::new(1);
let v = (1, 2);
error[E0382]: use of moved value: `x`
--> $DIR/move-in-guard-1.rs:10:24
|
-LL | let x: Box<_> = box 1;
+LL | let x: Box<_> = Box::new(1);
| - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
...
LL | (1, _) if take(x) => (),
-#![feature(box_syntax)]
-
pub fn main() {
- let x: Box<_> = box 1;
+ let x: Box<_> = Box::new(1);
let v = (1, 2);
error[E0382]: use of moved value: `x`
- --> $DIR/move-in-guard-2.rs:10:24
+ --> $DIR/move-in-guard-2.rs:8:24
|
-LL | let x: Box<_> = box 1;
+LL | let x: Box<_> = Box::new(1);
| - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
...
LL | (_, 2) if take(x) => (),
-#![feature(box_syntax)]
-
struct Foo(Box<isize>);
+
+
fn main() {
- let x: (Box<_>,) = (box 1,);
+ let x: (Box<_>,) = (Box::new(1),);
let y = x.0;
let z = x.0; //~ ERROR use of moved value: `x.0`
- let x = Foo(box 1);
+ let x = Foo(Box::new(1));
let y = x.0;
let z = x.0; //~ ERROR use of moved value: `x.0`
}
#![feature(box_patterns)]
-#![feature(box_syntax)]
+
struct S {
x: Box<E>
}
fn main() {
- let s = S { x: box E::Bar(box 42) };
+ let s = S { x: Box::new(E::Bar(Box::new(42))) };
loop {
f(&s, |hellothere| {
match hellothere.x { //~ ERROR cannot move out
-#![feature(box_syntax, unboxed_closures)]
+#![feature(unboxed_closures)]
fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
fn test(_x: Box<usize>) {}
fn main() {
- let i = box 3;
+ let i = Box::new(3);
let _f = to_fn(|| test(i)); //~ ERROR cannot move out
}
error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure
--> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28
|
-LL | let i = box 3;
+LL | let i = Box::new(3);
| - captured outer variable
LL | let _f = to_fn(|| test(i));
| --------^-
-#![feature(box_syntax)]
-
fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
- box (x, x)
+
+
+ Box::new((x, x))
//~^ use of moved value: `x` [E0382]
}
fn main() {
- dup(box 3);
+ dup(Box::new(3));
}
error[E0382]: use of moved value: `x`
- --> $DIR/moves-based-on-type-tuple.rs:4:13
+ --> $DIR/moves-based-on-type-tuple.rs:4:18
|
LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
| - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
-LL | box (x, x)
- | - ^ value used here after move
- | |
- | value moved here
+...
+LL | Box::new((x, x))
+ | - ^ value used here after move
+ | |
+ | value moved here
error: aborting due to previous error
-#![feature(box_syntax)]
-
type Noncopyable = Box<isize>;
+
+
struct Foo {
copied: isize,
moved: Box<isize>,
fn test0(f: Foo, g: Noncopyable, h: Noncopyable) {
// just copy implicitly copyable fields from `f`, no moves:
- let _b = Foo {moved: box 1, noncopyable: g, ..f};
- let _c = Foo {moved: box 2, noncopyable: h, ..f};
+ let _b = Foo {moved: Box::new(1), noncopyable: g, ..f};
+ let _c = Foo {moved: Box::new(2), noncopyable: h, ..f};
}
fn test1(f: Foo, g: Noncopyable, h: Noncopyable) {
// run-pass
-#![feature(box_syntax)]
-
fn f(mut y: Box<isize>) {
*y = 5;
assert_eq!(*y, 5);
fn g() {
let frob = |mut q: Box<isize>| { *q = 2; assert_eq!(*q, 2); };
- let w = box 37;
+ let w = Box::new(37);
frob(w);
}
pub fn main() {
- let z = box 17;
+ let z = Box::new(17);
f(z);
g();
}
-#![feature(box_syntax)]
-
fn f(_: &mut isize) {}
fn main() {
- let mut x: Box<_> = box 3;
+
+ let mut x: Box<_> = Box::new(3);
+
f(x) //~ ERROR mismatched types
}
* http://creativecommons.org/publicdomain/zero/1.0/ */
#![allow(dead_code, unused_variables)]
-#![feature(box_syntax)]
// Tests that the new `box` syntax works with unique pointers.
}
pub fn main() {
- let y: Box<isize> = box 2;
- let b: Box<isize> = box (1 + 2);
- let c = box (3 + 4);
+ let y: Box<isize> = Box::new(2);
+ let b: Box<isize> = Box::new(1 + 2);
+ let c = Box::new(3 + 4);
- let s: Box<Structure> = box Structure {
+ let s: Box<Structure> = Box::new(Structure {
x: 3,
y: 4,
- };
+ });
}
// run-pass
-#![feature(box_syntax)]
-
fn f(x: Box<isize>) {
let y: &isize = &*x;
println!("{}", *x);
}
fn main() {
- f(box 1234);
- g(box Struct as Box<dyn Trait>);
+ f(Box::new(1234));
+ g(Box::new(Struct) as Box<dyn Trait>);
}
-#![feature(box_syntax)]
-
trait Foo { fn get(&self); }
impl<A> Foo for A {
fn get(&self) { }
}
+
+
fn main() {
let _ = {
let tmp0 = 3;
let tmp1 = &tmp0;
- box tmp1 as Box<dyn Foo + '_>
+ Box::new(tmp1) as Box<dyn Foo + '_>
};
//~^^^ ERROR `tmp0` does not live long enough
}
|
LL | let tmp1 = &tmp0;
| ^^^^^ borrowed value does not live long enough
-LL | box tmp1 as Box<dyn Foo + '_>
- | ----------------------------- borrow later captured here by trait object
+LL | Box::new(tmp1) as Box<dyn Foo + '_>
+ | ----------------------------------- borrow later captured here by trait object
LL | };
| - `tmp0` dropped here while still borrowed
--> $DIR/no_crate_type.rs:2:1
|
LL | #![crate_type]
- | ^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]`
+ | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
error: aborting due to previous error
// run-pass
-#![feature(box_syntax)]
-
// Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions,
// which "says that a destructor applied to an object built from a constructor
// behaves as expected". -- https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction
pub fn main() {
check_type!(&17, &isize);
- check_type!(box 18, Box<isize>);
+ check_type!(Box::new(18), Box<isize>);
check_type!("foo".to_string(), String);
check_type!(vec![20, 22], Vec<isize>);
check_type!(main, fn(), |pthing| {
// closed over do not contain managed values, and thus the boxes do
// not have headers.
-#![feature(box_syntax)]
-
-
trait FooTrait {
fn foo(&self) -> usize;
}
pub fn main() {
let foos: Vec<Box<dyn FooTrait>> = vec![
- box BarStruct{ x: 0 } as Box<dyn FooTrait>,
- box BarStruct{ x: 1 } as Box<dyn FooTrait>,
- box BarStruct{ x: 2 } as Box<dyn FooTrait>
+ Box::new(BarStruct{ x: 0 }) as Box<dyn FooTrait>,
+ Box::new(BarStruct{ x: 1 }) as Box<dyn FooTrait>,
+ Box::new(BarStruct{ x: 2 }) as Box<dyn FooTrait>,
];
for i in 0..foos.len() {
// closed over contain managed values. This implies that the boxes
// will have headers that must be skipped over.
-#![feature(box_syntax)]
-
trait FooTrait {
fn foo(self: Box<Self>) -> usize;
}
}
pub fn main() {
- let foo = box BarStruct{ x: 22 } as Box<dyn FooTrait>;
+ let foo = Box::new(BarStruct{ x: 22 }) as Box<dyn FooTrait>;
assert_eq!(22, foo.foo());
}
-#![feature(box_syntax)]
-
fn main() {
+
let f;
let g;
+
g = f;
- f = box g;
+ f = Box::new(g);
//~^ ERROR mismatched types
//~| cyclic type of infinite size
}
error[E0308]: mismatched types
--> $DIR/occurs-check-2.rs:7:9
|
-LL | f = box g;
- | ^^^^^ cyclic type of infinite size
- |
-help: try using a conversion method
- |
-LL | f = (box g).to_string();
- | + +++++++++++++
+LL | f = Box::new(g);
+ | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+ | |
+ | cyclic type of infinite size
error: aborting due to previous error
-#![feature(box_syntax)]
-
fn main() {
+
let f;
- f = box f;
+
+ f = Box::new(f);
//~^ ERROR mismatched types
//~| cyclic type of infinite size
}
error[E0308]: mismatched types
--> $DIR/occurs-check.rs:5:9
|
-LL | f = box f;
- | ^^^^^ cyclic type of infinite size
- |
-help: try using a conversion method
- |
-LL | f = (box f).to_string();
- | + +++++++++++++
+LL | f = Box::new(f);
+ | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+ | |
+ | cyclic type of infinite size
error: aborting due to previous error
#![allow(dead_assignment)]
#![allow(unused_variables)]
-#![feature(box_syntax)]
struct A { a: isize, b: isize }
struct Abox { a: Box<isize>, b: Box<isize> }
fn ret_int_i() -> isize { 10 }
-fn ret_ext_i() -> Box<isize> { box 10 }
+fn ret_ext_i() -> Box<isize> { Box::new(10) }
fn ret_int_rec() -> A { A {a: 10, b: 10} }
-fn ret_ext_rec() -> Box<A> { box A {a: 10, b: 10} }
+fn ret_ext_rec() -> Box<A> { Box::new(A {a: 10, b: 10}) }
-fn ret_ext_mem() -> Abox { Abox {a: box 10, b: box 10} }
+fn ret_ext_mem() -> Abox { Abox {a: Box::new(10), b: Box::new(10) } }
-fn ret_ext_ext_mem() -> Box<Abox> { box Abox{a: box 10, b: box 10} }
+fn ret_ext_ext_mem() -> Box<Abox> { Box::new(Abox{a: Box::new(10), b: Box::new(10) }) }
pub fn main() {
let mut int_i: isize;
#![allow(unused_variables)]
#![allow(stable_features)]
-#![feature(box_syntax, core)]
-
use std::cell::RefCell;
use std::rc::Rc;
}
pub fn main() {
- let box_5: Box<_> = box 5_usize;
+ let box_5: Box<_> = Box::new(5_usize);
let point = Rc::new(Point {x: 2, y: 4});
assert_eq!(point.x, 2);
assert_eq!(point.y, 4);
// Test overloaded indexing combined with autoderef.
-#![feature(box_syntax, core)]
-
use std::ops::{Index, IndexMut};
struct Foo {
}
fn main() {
- let mut f: Box<_> = box Foo {
+ let mut f: Box<_> = Box::new(Foo {
x: 1,
y: 2,
- };
+ });
assert_eq!(f[1], 2);
// error-pattern:meep
// ignore-emscripten no processes
-#![feature(box_syntax)]
-
fn f(_a: isize, _b: isize, _c: Box<isize>) {
panic!("moop");
}
fn main() {
- f(1, panic!("meep"), box 42);
+ f(1, panic!("meep"), Box::new(42));
}
// error-pattern:panicked at 'Box<dyn Any>'
// ignore-emscripten no processes
-#![feature(box_syntax)]
#![allow(non_fmt_panics)]
fn main() {
- panic!(box 413 as Box<dyn std::any::Any + Send>);
+ panic!(Box::new(413) as Box<dyn std::any::Any + Send>);
}
// build-pass (FIXME(62277): could be check-pass?)
-#![feature(box_syntax)]
#![allow(bare_trait_objects)]
use std::fmt::Debug;
fn main() {
- let x: Box<Debug+> = box 3 as Box<Debug+>; // Trailing `+` is OK
+ let x: Box<Debug+> = Box::new(3) as Box<Debug+>; // Trailing `+` is OK
}
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![allow(dead_code)]
#![allow(unused_variables)]
#![deny(unreachable_patterns)]
+
enum IntList {
Cons(isize, Box<IntList>),
Nil
fn tail(source_list: &IntList) -> IntList {
match source_list {
&IntList::Cons(val, box ref next_list) => tail(next_list),
- &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil),
-//~^ ERROR unreachable pattern
- _ => panic!()
+ &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)),
+ //~^ ERROR unreachable pattern
+ _ => panic!(),
}
}
error: unreachable pattern
--> $DIR/issue-12116.rs:15:9
|
-LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil),
+LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/issue-12116.rs:5:9
+ --> $DIR/issue-12116.rs:4:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
#![feature(box_patterns)]
-#![feature(box_syntax)]
struct HTMLImageData {
image: Option<String>
fn main() {
let mut id = HTMLImageData { image: None };
- let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) };
- let n = NodeData {kind : box NodeKind::Element(ed)};
+ let ed = ElementData { kind: Box::new(ElementKind::HTMLImageElement(id)) };
+ let n = NodeData { kind: Box::new(NodeKind::Element(ed)) };
+
// n.b. span could be better
match n.kind {
box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
+++ /dev/null
-// gate-test-macro_attributes_in_derive_output
-// aux-build: test-macros.rs
-
-#![feature(proc_macro_hygiene)]
-#![feature(stmt_expr_attributes)]
-
-#[macro_use]
-extern crate test_macros;
-
-#[derive(Empty)]
-#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable
-struct S1 {
- field: [u8; 10],
-}
-
-#[derive(Empty)]
-#[empty_helper]
-#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable
-struct S2 {
- field: [u8; 10],
-}
-
-#[derive(Empty)]
-struct S3 {
- field: [u8; #[identity_attr] 10], //~ ERROR macro attributes in `#[derive]` output are unstable
-}
-
-#[derive(Empty)]
-struct S4 {
- field: [u8; {
- #[derive(Empty)] // OK, not gated
- struct Inner;
- 10
- }]
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: macro attributes in `#[derive]` output are unstable
- --> $DIR/attribute-after-derive-feature-gate.rs:11:3
- |
-LL | #[empty_attr]
- | ^^^^^^^^^^
- |
- = note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
- = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
-
-error[E0658]: macro attributes in `#[derive]` output are unstable
- --> $DIR/attribute-after-derive-feature-gate.rs:18:3
- |
-LL | #[empty_attr]
- | ^^^^^^^^^^
- |
- = note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
- = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
-
-error[E0658]: macro attributes in `#[derive]` output are unstable
- --> $DIR/attribute-after-derive-feature-gate.rs:25:19
- |
-LL | field: [u8; #[identity_attr] 10],
- | ^^^^^^^^^^^^^
- |
- = note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
- = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
// compile-flags: -Z span-debug
// aux-build: test-macros.rs
-#![feature(macro_attributes_in_derive_output)]
-
#![no_std] // Don't load unnecessary hygiene information from std
extern crate std;
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/attribute-after-derive.rs:17:1: 17:2 (#0),
+ span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "derive",
- span: $DIR/attribute-after-derive.rs:17:3: 17:9 (#0),
+ span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "Print",
- span: $DIR/attribute-after-derive.rs:17:10: 17:15 (#0),
+ span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0),
},
],
- span: $DIR/attribute-after-derive.rs:17:9: 17:16 (#0),
+ span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0),
},
],
- span: $DIR/attribute-after-derive.rs:17:2: 17:17 (#0),
+ span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0),
},
Ident {
ident: "struct",
- span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
+ span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
},
Ident {
ident: "AttributeDerive",
- span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
+ span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/attribute-after-derive.rs:19:5: 19:6 (#0),
+ span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg",
- span: $DIR/attribute-after-derive.rs:19:7: 19:10 (#0),
+ span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
- span: $DIR/attribute-after-derive.rs:19:11: 19:16 (#0),
+ span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0),
},
],
- span: $DIR/attribute-after-derive.rs:19:10: 19:17 (#0),
+ span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0),
},
],
- span: $DIR/attribute-after-derive.rs:19:6: 19:18 (#0),
+ span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0),
},
Ident {
ident: "field",
- span: $DIR/attribute-after-derive.rs:20:5: 20:10 (#0),
+ span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0),
},
Punct {
ch: ':',
spacing: Alone,
- span: $DIR/attribute-after-derive.rs:20:10: 20:11 (#0),
+ span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0),
},
Ident {
ident: "u8",
- span: $DIR/attribute-after-derive.rs:20:12: 20:14 (#0),
+ span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/attribute-after-derive.rs:20:14: 20:15 (#0),
+ span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0),
},
],
- span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
+ span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
+ span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
},
Ident {
ident: "AttributeDerive",
- span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
+ span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
+ span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
},
]
PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/attribute-after-derive.rs:24:1: 24:2 (#0),
+ span: $DIR/attribute-after-derive.rs:22:1: 22:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_attr",
- span: $DIR/attribute-after-derive.rs:24:3: 24:13 (#0),
+ span: $DIR/attribute-after-derive.rs:22:3: 22:13 (#0),
},
],
- span: $DIR/attribute-after-derive.rs:24:2: 24:14 (#0),
+ span: $DIR/attribute-after-derive.rs:22:2: 22:14 (#0),
},
Ident {
ident: "struct",
- span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
+ span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0),
},
Ident {
ident: "DeriveAttribute",
- span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
+ span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
+ span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
+PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
+ span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0),
},
Ident {
ident: "DeriveAttribute",
- span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
+ span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0),
},
Group {
delimiter: Brace,
- stream: TokenStream [],
- span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/attribute-after-derive.rs:24:5: 24:6 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "cfg",
+ span: $DIR/attribute-after-derive.rs:24:7: 24:10 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "FALSE",
+ span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0),
+ },
+ ],
+ span: $DIR/attribute-after-derive.rs:24:10: 24:17 (#0),
+ },
+ ],
+ span: $DIR/attribute-after-derive.rs:24:6: 24:18 (#0),
+ },
+ Ident {
+ ident: "field",
+ span: $DIR/attribute-after-derive.rs:25:5: 25:10 (#0),
+ },
+ Punct {
+ ch: ':',
+ spacing: Alone,
+ span: $DIR/attribute-after-derive.rs:25:10: 25:11 (#0),
+ },
+ Ident {
+ ident: "u8",
+ span: $DIR/attribute-after-derive.rs:25:12: 25:14 (#0),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: $DIR/attribute-after-derive.rs:25:14: 25:15 (#0),
+ },
+ ],
+ span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
},
]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
fn sums_to(v: Vec<isize> , sum: isize) -> bool {
let mut i = 0;
let mut sum0 = 0;
fn sums_to_using_uniq(v: Vec<isize> , sum: isize) -> bool {
let mut i = 0;
- let mut sum0: Box<_> = box 0;
+ let mut sum0: Box<_> = 0.into();
while i < v.len() {
*sum0 += v[i];
i += 1;
fn sums_to_using_uniq_rec(v: Vec<isize> , sum: isize) -> bool {
let mut i = 0;
- let mut sum0 = F::<Box<_>> {f: box 0};
+ let mut sum0 = F::<Box<_>> {f: 0.into() };
while i < v.len() {
*sum0.f += v[i];
i += 1;
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
trait get {
fn get(self) -> isize;
}
pub fn main() {
- let x: Box<_> = box 6;
+ let x: Box<_> = 6.into();
let y = x.get();
println!("y={}", y);
assert_eq!(y, 6);
-#![feature(box_syntax)]
#![allow(unused_variables)]
+
#![deny(unreachable_code)]
fn main() {
#![feature(box_patterns)]
-#![feature(box_syntax)]
+
#![allow(dead_code)]
#![deny(unreachable_patterns)]
--- /dev/null
+#![recursion_limit = 123] //~ ERROR malformed `recursion_limit` attribute
+
+fn main() {}
--- /dev/null
+error: malformed `recursion_limit` attribute input
+ --> $DIR/invalid_digit_type.rs:1:1
+ |
+LL | #![recursion_limit = 123]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+
+error: aborting due to previous error
+
--- /dev/null
+#![recursion_limit = foo!()] //~ ERROR malformed `recursion_limit` attribute
+
+macro_rules! foo {
+ () => {"128"};
+}
+
+fn main() {}
--- /dev/null
+error: malformed `recursion_limit` attribute input
+ --> $DIR/invalid_macro.rs:1:1
+ |
+LL | #![recursion_limit = foo!()]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+
+error: aborting due to previous error
+
-#![feature(box_syntax)]
-
trait X {
fn get_i(&self) -> isize;
}
+
+
struct B {
i: isize
}
}
fn make_make_a<'a>() -> A<'a> {
- let b: Box<B> = box B {i:1};
+ let b: Box<B> = Box::new(B { i: 1 });
let bb: &B = &*b;
make_a(bb) //~ ERROR cannot return value referencing local data `*b`
}
// run-pass
-#![feature(box_syntax)]
fn foo(x: &usize) -> usize {
*x
}
pub fn main() {
- let p: Box<_> = box 22;
+ let p: Box<_> = Box::new(22);
let r = foo(&*p);
println!("r={}", r);
assert_eq!(r, 22);
// run-pass
-#![feature(box_syntax)]
fn foo(x: &usize) -> usize {
*x
}
pub fn main() {
- let p: Box<_> = box 3;
+ let p: Box<_> = Box::new(3);
let r = foo(&*p);
assert_eq!(r, 3);
}
-#![feature(box_syntax)]
-
trait X {}
+
+
trait Iter {
type Item: X;
fn bad2<T: Iter>(v: T) -> Box<dyn X + 'static>
where Box<T::Item> : X
{
- let item: Box<_> = box v.into_item();
+ let item: Box<_> = Box::new(v.into_item());
Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
}
fn bad4<'a, T: Iter>(v: T) -> Box<dyn X + 'a>
where Box<T::Item> : X
{
- let item: Box<_> = box v.into_item();
+ let item: Box<_> = Box::new(v.into_item());
Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
}
-#![feature(box_syntax)]
#![allow(warnings)]
trait A<T> { }
+
struct B<'a, T:'a>(&'a (A<T>+'a));
trait X { }
impl<'a, T> X for B<'a, T> {}
fn f<'a, T:'static, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
- box B(&*v) as Box<X> //~ ERROR cannot return value referencing local data `*v`
+ Box::new(B(&*v)) as Box<X> //~ ERROR cannot return value referencing local data `*v`
}
fn main() {}
error[E0515]: cannot return value referencing local data `*v`
--> $DIR/regions-close-object-into-object-1.rs:12:5
|
-LL | box B(&*v) as Box<X>
- | ^^^^^^---^^^^^^^^^^^
- | | |
- | | `*v` is borrowed here
+LL | Box::new(B(&*v)) as Box<X>
+ | ^^^^^^^^^^^---^^^^^^^^^^^^
+ | | |
+ | | `*v` is borrowed here
| returns a value referencing data owned by the current function
error: aborting due to previous error
error: lifetime may not live long enough
- --> $DIR/regions-close-object-into-object-2.rs:10:5
+ --> $DIR/regions-close-object-into-object-2.rs:9:5
|
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
| -- lifetime `'a` defined here
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
error[E0515]: cannot return value referencing local data `*v`
- --> $DIR/regions-close-object-into-object-2.rs:10:5
+ --> $DIR/regions-close-object-into-object-2.rs:9:5
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^---^^^^^^^^^^^^^^^
- | | |
- | | `*v` is borrowed here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+ | | |
+ | | `*v` is borrowed here
| returns a value referencing data owned by the current function
error: aborting due to 2 previous errors
-#![feature(box_syntax)]
-
trait A<T> { }
+
struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
trait X { }
impl<'a, T> X for B<'a, T> {}
fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- box B(&*v) as Box<dyn X> //~ ERROR E0759
+ Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
}
fn main() { }
error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-close-object-into-object-2.rs:10:11
+ --> $DIR/regions-close-object-into-object-2.rs:9:16
|
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
| ------------------ this data with lifetime `'a`...
-LL | box B(&*v) as Box<dyn X>
- | ^^^ ...is captured here, requiring it to live as long as `'static`
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...is captured here, requiring it to live as long as `'static`
|
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
-#![feature(box_syntax)]
#![allow(warnings)]
trait A<T> { }
+
struct B<'a, T:'a>(&'a (A<T>+'a));
trait X { }
impl<'a, T> X for B<'a, T> {}
fn h<'a, T, U:'static>(v: Box<A<U>+'static>) -> Box<X+'static> {
- box B(&*v) as Box<X> //~ ERROR cannot return value referencing local data `*v`
+ Box::new(B(&*v)) as Box<X> //~ ERROR cannot return value referencing local data `*v`
}
fn main() {}
error[E0515]: cannot return value referencing local data `*v`
--> $DIR/regions-close-object-into-object-3.rs:11:5
|
-LL | box B(&*v) as Box<X>
- | ^^^^^^---^^^^^^^^^^^
- | | |
- | | `*v` is borrowed here
+LL | Box::new(B(&*v)) as Box<X>
+ | ^^^^^^^^^^^---^^^^^^^^^^^^
+ | | |
+ | | `*v` is borrowed here
| returns a value referencing data owned by the current function
error: aborting due to previous error
error[E0310]: the parameter type `U` may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:10:5
+ --> $DIR/regions-close-object-into-object-4.rs:9:5
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^^^^^
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `U: 'static`...
+
+error[E0310]: the parameter type `U` may not live long enough
+ --> $DIR/regions-close-object-into-object-4.rs:9:5
+ |
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `U: 'static`...
+
+error[E0310]: the parameter type `U` may not live long enough
+ --> $DIR/regions-close-object-into-object-4.rs:9:5
+ |
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `U: 'static`...
error: lifetime may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:10:5
+ --> $DIR/regions-close-object-into-object-4.rs:9:5
|
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
| -- lifetime `'a` defined here
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
error[E0515]: cannot return value referencing local data `*v`
- --> $DIR/regions-close-object-into-object-4.rs:10:5
+ --> $DIR/regions-close-object-into-object-4.rs:9:5
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^---^^^^^^^^^^^^^^^
- | | |
- | | `*v` is borrowed here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+ | | |
+ | | `*v` is borrowed here
| returns a value referencing data owned by the current function
error[E0310]: the parameter type `U` may not live long enough
- --> $DIR/regions-close-object-into-object-4.rs:10:9
+ --> $DIR/regions-close-object-into-object-4.rs:9:14
|
-LL | box B(&*v) as Box<dyn X>
- | ^^^^^^
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^
|
= help: consider adding an explicit lifetime bound `U: 'static`...
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0310, E0515.
For more information about an error, try `rustc --explain E0310`.
-#![feature(box_syntax)]
-
trait A<T> { }
+
struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
trait X { }
impl<'a, T> X for B<'a, T> {}
fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- box B(&*v) as Box<dyn X> //~ ERROR E0759
+ Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
}
fn main() {}
error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/regions-close-object-into-object-4.rs:10:11
+ --> $DIR/regions-close-object-into-object-4.rs:9:16
|
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
| ---------------- this data with lifetime `'a`...
-LL | box B(&*v) as Box<dyn X>
- | ^^^ ...is captured here, requiring it to live as long as `'static`
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...is captured here, requiring it to live as long as `'static`
|
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/regions-close-object-into-object-5.rs:17:5
|
-LL | box B(&*v) as Box<X>
- | ^^^^^^^^^^
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:17:5
+ |
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:17:5
+ |
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
error[E0515]: cannot return value referencing local data `*v`
--> $DIR/regions-close-object-into-object-5.rs:17:5
|
-LL | box B(&*v) as Box<X>
- | ^^^^^^---^^^^^^^^^^^
- | | |
- | | `*v` is borrowed here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+ | | |
+ | | `*v` is borrowed here
| returns a value referencing data owned by the current function
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:9
+ --> $DIR/regions-close-object-into-object-5.rs:17:14
|
-LL | box B(&*v) as Box<X>
- | ^^^^^^
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0310, E0515.
For more information about an error, try `rustc --explain E0310`.
-#![feature(box_syntax)]
#![allow(warnings)]
+
trait A<T>
{
fn get(&self) -> T { panic!() }
fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
// oh dear!
- box B(&*v) as Box<X>
+ Box::new(B(&*v)) as Box<dyn X>
//~^ ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
+ //~| ERROR the parameter type `T` may not live long enough
}
fn main() {}
LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | // oh dear!
-LL | box B(&*v) as Box<X>
- | ^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/regions-close-object-into-object-5.rs:9:17
+ |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+ | ^^
+
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/regions-close-object-into-object-5.rs:17:5
+ |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | // oh dear!
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:9
+ --> $DIR/regions-close-object-into-object-5.rs:17:14
|
LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | // oh dear!
-LL | box B(&*v) as Box<X>
- | ^ ...so that the type `T` will meet its required lifetime bounds
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:9
+ --> $DIR/regions-close-object-into-object-5.rs:17:14
|
LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | // oh dear!
-LL | box B(&*v) as Box<X>
- | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
note: ...that is required by this bound
--> $DIR/regions-close-object-into-object-5.rs:9:17
| ^^
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:11
+ --> $DIR/regions-close-object-into-object-5.rs:17:16
|
LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | // oh dear!
-LL | box B(&*v) as Box<X>
- | ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:11
+ --> $DIR/regions-close-object-into-object-5.rs:17:16
|
LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | // oh dear!
-LL | box B(&*v) as Box<X>
- | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/regions-close-object-into-object-5.rs:17:11
+ --> $DIR/regions-close-object-into-object-5.rs:17:16
|
LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`
LL | // oh dear!
-LL | box B(&*v) as Box<X>
- | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0310`.
error[E0310]: the parameter type `A` may not live long enough
--> $DIR/regions-close-over-type-parameter-1.rs:12:5
|
-LL | box v as Box<dyn SomeTrait + 'static>
- | ^^^^^
+LL | Box::new(v) as Box<dyn SomeTrait + 'static>
+ | ^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `A: 'static`...
error[E0309]: the parameter type `A` may not live long enough
--> $DIR/regions-close-over-type-parameter-1.rs:21:5
|
-LL | box v as Box<dyn SomeTrait + 'b>
- | ^^^^^
+LL | Box::new(v) as Box<dyn SomeTrait + 'b>
+ | ^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `A: 'b`...
-#![feature(box_syntax)]
-
// Test for what happens when a type parameter `A` is closed over into
// an object. This should yield errors unless `A` (and the object)
// both have suitable bounds.
+
trait SomeTrait {
fn get(&self) -> isize;
}
+
fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
- box v as Box<dyn SomeTrait + 'static>
+ Box::new(v) as Box<dyn SomeTrait + 'static>
//~^ ERROR the parameter type `A` may not live long enough
}
fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'a> {
- box v as Box<dyn SomeTrait + 'a>
+ Box::new(v) as Box<dyn SomeTrait + 'a>
}
fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
- box v as Box<dyn SomeTrait + 'b>
+ Box::new(v) as Box<dyn SomeTrait + 'b>
//~^ ERROR the parameter type `A` may not live long enough
}
|
LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
| -- help: consider adding an explicit lifetime bound...: `A: 'static +`
-LL | box v as Box<dyn SomeTrait + 'static>
- | ^^^^^ ...so that the type `A` will meet its required lifetime bounds
+LL | Box::new(v) as Box<dyn SomeTrait + 'static>
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
error[E0309]: the parameter type `A` may not live long enough
--> $DIR/regions-close-over-type-parameter-1.rs:21:5
|
LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
| -- help: consider adding an explicit lifetime bound...: `A: 'b +`
-LL | box v as Box<dyn SomeTrait + 'b>
- | ^^^^^ ...so that the type `A` will meet its required lifetime bounds
+LL | Box::new(v) as Box<dyn SomeTrait + 'b>
+ | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
error: aborting due to 2 previous errors
| |
| lifetime `'a` defined here
LL | // A outlives 'a AND 'b...but not 'c.
-LL | box v as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c`
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c`
|
= help: consider adding the following bound: `'a: 'c`
-#![feature(box_syntax)]
-
// Various tests where we over type parameters with multiple lifetime
// bounds.
+
trait SomeTrait { fn get(&self) -> isize; }
+
fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'a> {
// A outlives 'a AND 'b...
- box v as Box<dyn SomeTrait + 'a> // ...hence this type is safe.
+ Box::new(v) as Box<dyn SomeTrait + 'a> // ...hence this type is safe.
}
fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'b> {
// A outlives 'a AND 'b...
- box v as Box<dyn SomeTrait + 'b> // ...hence this type is safe.
+ Box::new(v) as Box<dyn SomeTrait + 'b> // ...hence this type is safe.
}
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
// A outlives 'a AND 'b...but not 'c.
- box v as Box<dyn SomeTrait + 'a> //~ ERROR cannot infer an appropriate lifetime
+ Box::new(v) as Box<dyn SomeTrait + 'a> //~ ERROR cannot infer an appropriate lifetime
}
fn main() {
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
|
-LL | box v as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 18:20...
--> $DIR/regions-close-over-type-parameter-multiple.rs:18:20
note: ...so that the declared lifetime parameter bounds are satisfied
--> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
|
-LL | box v as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'c` as defined on the function body at 18:26...
--> $DIR/regions-close-over-type-parameter-multiple.rs:18:26
|
note: ...so that the types are compatible
--> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
|
-LL | box v as Box<dyn SomeTrait + 'a>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | Box::new(v) as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Box<(dyn SomeTrait + 'c)>`
found `Box<dyn SomeTrait>`
// A test where we (successfully) close over a reference into
// an object.
-#![feature(box_syntax)]
-
trait SomeTrait { fn get(&self) -> isize; }
impl<'a> SomeTrait for &'a isize {
}
fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait+'a> {
- box v as Box<dyn SomeTrait+'a>
+ Box::new(v) as Box<dyn SomeTrait+'a>
}
fn main() {
// Issue #3148.
#![feature(box_patterns)]
-#![feature(box_syntax)]
struct A {
value: B
v2: [23, 24, 25],
v3: vec![26, 27, 28],
v4: C { f: 29 },
- v5: box C { f: 30 },
+ v5: Box::new(C { f: 30 }),
v6: Some(C { f: 31 })}};
let p = get_v1(&a);
// Tests that you can use an early-bound lifetime parameter as
// on of the generic parameters in a trait.
-#![feature(box_syntax)]
-
trait Trait<'a> {
fn long(&'a self) -> isize;
fn short<'b>(&'b self) -> isize;
impl<'t> MakerTrait for Box<dyn Trait<'t>+'static> {
fn mk() -> Box<dyn Trait<'t>+'static> {
- let tup: Box<(isize, isize)> = box (4,5);
+ let tup: Box<(isize, isize)> = Box::new((4,5));
tup as Box<dyn Trait>
}
}
// run-pass
-#![feature(box_syntax)]
-
fn foo(x: &usize) -> &usize { x }
fn bar(x: &usize) -> usize { *x }
pub fn main() {
- let p: Box<_> = box 3;
+ let p: Box<_> = Box::new(3);
assert_eq!(bar(foo(&*p)), 3);
}
// run-pass
-#![feature(box_syntax)]
fn borrow<T>(x: &T) -> &T {x}
pub fn main() {
- let x: Box<_> = box 3;
+ let x: Box<_> = Box::new(3);
loop {
let y = borrow(&*x);
assert_eq!(*x, *y);
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct Point {x: isize, y: isize}
}
pub fn main() {
- let p: Box<_> = box Point {x: 3, y: 4};
+ let p: Box<_> = Box::new(Point {x: 3, y: 4});
let xc = x_coord(&*p);
assert_eq!(*xc, 3);
}
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
fn explicit() {
fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<dyn for<'a> FnMut(&'a isize)>) {}
- test(Some(box |_f: Box<dyn for<'a> FnMut(&'a isize)>| {}));
+ test(Some(Box::new(|_f: Box<dyn for<'a> FnMut(&'a isize)>| {})));
}
// The code below is shorthand for the code above (and more likely
// to represent what one encounters in practice).
fn implicit() {
fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<dyn FnMut(& isize)>) {}
- test(Some(box |_f: Box<dyn FnMut(& isize)>| {}));
+ test(Some(Box::new(|_f: Box<dyn FnMut(& isize)>| {})));
}
explicit();
#![feature(box_patterns)]
-#![feature(box_syntax)]
+
fn arg_item(box ref x: Box<isize>) -> &'static isize {
x //~ ERROR cannot return value referencing function parameter
}
-fn with<R, F>(f: F) -> R where F: FnOnce(Box<isize>) -> R { f(box 3) }
+fn with<R, F>(f: F) -> R where F: FnOnce(Box<isize>) -> R { f(Box::new(3)) }
fn arg_closure() -> &'static isize {
with(|box ref x| x) //~ ERROR cannot return value referencing function parameter
// changes were caught. However, those uses in the compiler could
// easily get changed or refactored away in the future.
-#![feature(box_syntax)]
-
struct Ctxt<'tcx> {
x: &'tcx Vec<isize>
}
-#![feature(box_syntax)]
-
// Issue #12470.
trait X {
}
fn make_make_a<'a>() -> A<'a> {
- let b: Box<B> = box B {
+
+ let b: Box<B> = Box::new(B {
i: 1,
- };
+ });
+
let bb: &B = &*b;
make_a(bb) //~ ERROR cannot return value referencing local data `*b`
}
--- /dev/null
+mod module {
+ pub struct SomeTupleStruct(u8);
+ pub struct SomeRegularStruct {
+ foo: u8
+ }
+
+ impl SomeTupleStruct {
+ pub fn new() -> Self {
+ Self(0)
+ }
+ }
+ impl SomeRegularStruct {
+ pub fn new() -> Self {
+ Self { foo: 0 }
+ }
+ }
+}
+
+use module::{SomeTupleStruct, SomeRegularStruct};
+
+fn main() {
+ let _ = SomeTupleStruct.new();
+ //~^ ERROR expected value, found struct `SomeTupleStruct`
+ let _ = SomeRegularStruct.new();
+ //~^ ERROR expected value, found struct `SomeRegularStruct`
+}
--- /dev/null
+error[E0423]: expected value, found struct `SomeTupleStruct`
+ --> $DIR/suggest-path-for-tuple-struct.rs:22:13
+ |
+LL | let _ = SomeTupleStruct.new();
+ | ^^^^^^^^^^^^^^^----
+ | |
+ | help: use the path separator to refer to an item: `SomeTupleStruct::new`
+
+error[E0423]: expected value, found struct `SomeRegularStruct`
+ --> $DIR/suggest-path-for-tuple-struct.rs:24:13
+ |
+LL | let _ = SomeRegularStruct.new();
+ | ^^^^^^^^^^^^^^^^^----
+ | |
+ | help: use the path separator to refer to an item: `SomeRegularStruct::new`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
// run-pass
#![allow(unreachable_patterns)]
-#![feature(box_syntax, box_patterns)]
+#![feature(box_patterns)]
struct Foo{}
pub fn main() {
- let b = box Foo{};
+ let b = Box::new(Foo{});
let box f = &b;
let _: &Foo = f;
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
#[derive(Copy, Clone)]
struct LM { resize_at: usize, size: usize }
}
pub fn main() {
- let mut m: Box<_> = box linear_map::<(),()>();
+ let mut m: Box<_> = Box::new(linear_map::<(),()>());
assert_eq!(m.len(), 0);
}
// run-pass
-#![feature(box_syntax)]
trait Foo {
fn f(self: Box<Self>);
}
pub fn main() {
- let x = box S { x: 3 };
+ let x = Box::new(S { x: 3 });
let y = x as Box<dyn Foo>;
y.f();
}
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
-#![feature(box_syntax)]
-
static tau: f64 = 2.0*3.14159265358979323;
struct Point {x: f64, y: f64}
impl Nus for thing { fn f(&self) {} }
pub fn main() {
- let y: Box<_> = box thing(A {a: 10});
+ let y: Box<_> = Box::new(thing(A {a: 10}));
assert_eq!(y.clone().bar(), 10);
assert_eq!(y.quux(), 10);
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
struct Foo;
// Test uses on inherent impl.
let _: Self::SuperQux = true;
let _: <Self as SuperBar>::SuperQux = true;
- box Baz { f: 42 }
+ Box::new(Baz { f: 42 })
}
}
fn main() {
- let _: Foo = Foo::foo(Foo, &Foo, box Foo);
- let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 },
- &box Baz { f: 42 },
- box box Baz { f: 42 },
+ let _: Foo = Foo::foo(Foo, &Foo, Box::new(Foo));
+ let _: Box<Baz<isize>> = Bar::bar(Box::new(Baz { f: 42 }),
+ &Box::new(Baz { f: 42 }),
+ Box::new(Box::new(Baz { f: 42 })),
true);
}
// run-pass
-#![feature(box_syntax)]
struct X {
a: isize
let new_x = x.change();
assert_eq!(new_x.a, 55);
- let x: Box<_> = box new_x;
+ let x: Box<_> = Box::new(new_x);
let new_x = x.change_again();
assert_eq!(new_x.a, 45);
}
// Ensure assigning an owned or managed variable to itself works. In particular,
// that we do not glue_drop before we glue_take (#3290).
-#![feature(box_syntax)]
#![allow(dead_code)]
use std::rc::Rc;
pub fn main() {
- let mut x: Box<_> = box 3;
+ let mut x: Box<_> = Box::new(3);
x = x;
assert_eq!(*x, 3);
// run-pass
-#![feature(box_syntax)]
#![allow(dead_code)]
#[derive(Copy, Clone)]
}
fn main() {
- let foo: Box<_> = box Foo {
+ let foo: Box<_> = Box::new(Foo {
f: 1,
- };
+ });
println!("{} {} {}", foo.foo(2), foo.bar(2), foo.baz(2));
- let bar: Box<_> = box Bar {
+ let bar: Box<_> = Box::new(Bar {
f: 1,
- };
+ });
println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2));
let bar: Box<Bar<isize>> = bar;
println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2));
// run-pass
-#![feature(box_syntax)]
struct X {
a: isize
}
pub fn main() {
- let x: Box<_> = box X { a: 32 };
+ let x: Box<_> = Box::new(X { a: 32 });
let new_x = x.change();
assert_eq!(new_x.a, 55);
}
// Test that shadowed lifetimes generate an error.
-#![feature(box_syntax)]
struct Foo<T>(T);
+
impl<T> Foo<T> {
fn shadow_in_method<T>(&self) {}
//~^ ERROR the name `T` is already used
-#![feature(box_syntax)]
-
fn test(_x: &mut String) {}
+
fn test2(_x: &mut i32) {}
+
fn main() {
let x: usize = String::new();
//~^ ERROR E0308
test2(&y);
//~^ ERROR E0308
let f;
- f = box f;
+ f = Box::new(f);
//~^ ERROR E0308
let s = &mut String::new();
error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:17:9
|
-LL | f = box f;
- | ^^^^^ cyclic type of infinite size
- |
-help: try using a conversion method
- |
-LL | f = (box f).to_string();
- | + +++++++++++++
+LL | f = Box::new(f);
+ | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+ | |
+ | cyclic type of infinite size
error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:21:9
-#![feature(box_syntax, unboxed_closures)]
+#![feature(unboxed_closures)]
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
let r = {
- let x: Box<_> = box 42;
+ let x: Box<_> = Box::new(42);
let f = to_fn_once(move|| &x); //~ ERROR cannot return reference to local data `x`
f()
};
-#![feature(box_syntax)]
-
fn id<T>(x: T) -> T { x }
trait Foo { }
impl<'a> Foo for &'a isize { }
fn main() {
+
let blah;
+
{
let ss: &isize = &id(1);
//~^ ERROR temporary value dropped while borrowed
- blah = box ss as Box<dyn Foo>;
+ blah = Box::new(ss) as Box<dyn Foo>;
}
}
-#![feature(box_syntax)]
-
// Test for what happens when a type parameter `A` is closed over into
// an object. This should yield errors unless `A` (and the object)
// both have suitable bounds.
trait Foo { fn get(&self); }
impl<A> Foo for A {
- fn get(&self) { }
+ fn get(&self) {
+ }
}
fn repeater3<'a,A:'a>(v: A) -> Box<dyn Foo + 'a> {
- box v as Box<dyn Foo+'a>
+ Box::new(v) as Box<dyn Foo+'a>
}
fn main() {
+
// Error results because the type of is inferred to be
// ~Repeat<&'blk isize> where blk is the lifetime of the block below.
-#![feature(box_syntax)]
-
fn id<T>(x: T) -> T { x }
fn f<T:'static>(_: T) {}
fn main() {
- let x: Box<_> = box 3;
+
+ let x: Box<_> = Box::new(3);
f(x);
+
let x = &id(3); //~ ERROR temporary value dropped while borrowed
f(x);
}
// run-pass
// aux-build:cci_class_cast.rs
-#![feature(box_syntax)]
-
extern crate cci_class_cast;
use std::string::ToString;
}
pub fn main() {
- let nyan: Box<dyn ToString> = box cat(0, 2, "nyan".to_string()) as Box<dyn ToString>;
+ let nyan: Box<dyn ToString> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn ToString>;
print_out(nyan, "nyan".to_string());
}
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
-
use std::fmt;
struct cat {
}
pub fn main() {
- let nyan: Box<dyn ToString> = box cat(0, 2, "nyan".to_string()) as Box<dyn ToString>;
+ let nyan: Box<dyn ToString> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn ToString>;
print_out(nyan, "nyan".to_string());
}
// run-pass
-#![feature(box_syntax)]
/*!
* This is a regression test for a bug in LLVM, fixed in upstream r179587,
enum List<X> { Nil, Cons(X, Box<List<X>>) }
pub fn main() {
- match List::Cons(10, box List::Nil) {
+ match List::Cons(10, Box::new(List::Nil)) {
List::Cons(10, _) => {}
List::Nil => {}
_ => panic!()
--> $DIR/imm-ref-trait-object-literal.rs:13:7
|
LL | foo(s);
- | --- ^
- | | |
- | | expected an implementor of trait `Trait`
- | | help: consider mutably borrowing here: `&mut s`
+ | --- ^ expected an implementor of trait `Trait`
+ | |
| required by a bound introduced by this call
|
note: required by a bound in `foo`
|
LL | fn foo<X: Trait>(_: X) {}
| ^^^^^ required by this bound in `foo`
+help: consider mutably borrowing here
+ |
+LL | foo(&mut s);
+ | ++++
error: aborting due to 2 previous errors
--> $DIR/issue-62843.rs:4:32
|
LL | println!("{:?}", line.find(pattern));
- | ---- ^^^^^^^
- | | |
- | | expected an implementor of trait `Pattern<'_>`
- | | help: consider borrowing here: `&pattern`
+ | ---- ^^^^^^^ expected an implementor of trait `Pattern<'_>`
+ | |
| required by a bound introduced by this call
|
= note: the trait bound `String: Pattern<'_>` is not satisfied
= note: required because of the requirements on the impl of `Pattern<'_>` for `String`
+help: consider borrowing here
+ |
+LL | println!("{:?}", line.find(&pattern));
+ | +
error: aborting due to previous error
// edition:2018
-// compile-flags: -Cincremental=tmp/issue-72766
+// incremental
pub struct SadGirl;
--> $DIR/issue-84973-2.rs:11:9
|
LL | foo(a);
- | --- ^
- | | |
- | | expected an implementor of trait `Tr`
- | | help: consider mutably borrowing here: `&mut a`
+ | --- ^ expected an implementor of trait `Tr`
+ | |
| required by a bound introduced by this call
|
note: required by a bound in `foo`
|
LL | fn foo<T: Tr>(i: T) {}
| ^^ required by this bound in `foo`
+help: consider mutably borrowing here
+ |
+LL | foo(&mut a);
+ | ++++
error: aborting due to previous error
--> $DIR/issue-84973-negative.rs:11:9
|
LL | bar(b);
- | --- ^
- | | |
- | | expected an implementor of trait `Tr`
- | | help: consider borrowing here: `&b`
+ | --- ^ expected an implementor of trait `Tr`
+ | |
| required by a bound introduced by this call
|
note: required by a bound in `bar`
|
LL | fn bar<T: Tr>(t: T) {}
| ^^ required by this bound in `bar`
+help: consider borrowing here
+ |
+LL | bar(&b);
+ | +
error: aborting due to 2 previous errors
--> $DIR/issue-84973.rs:6:24
|
LL | let o = Other::new(f);
- | ---------- ^
- | | |
- | | expected an implementor of trait `SomeTrait`
- | | help: consider borrowing here: `&f`
+ | ---------- ^ expected an implementor of trait `SomeTrait`
+ | |
| required by a bound introduced by this call
|
note: required by `Other::<'a, G>::new`
|
LL | pub fn new(g: G) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+ |
+LL | let o = Other::new(&f);
+ | +
error: aborting due to previous error
--> $DIR/slice-issue-87994.rs:3:12
|
LL | for _ in v[1..] {
- | ^^^^^^
- | |
- | expected an implementor of trait `IntoIterator`
- | help: consider borrowing here: `&v[1..]`
+ | ^^^^^^ expected an implementor of trait `IntoIterator`
|
= note: the trait bound `[i32]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[i32]`
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+ |
+LL | for _ in &v[1..] {
+ | +
+LL | for _ in &mut v[1..] {
+ | ++++
error[E0277]: `[i32]` is not an iterator
--> $DIR/slice-issue-87994.rs:3:12
|
LL | for _ in v[1..] {
- | ^^^^^^
- | |
- | expected an implementor of trait `IntoIterator`
- | help: consider borrowing here: `&v[1..]`
+ | ^^^^^^ expected an implementor of trait `IntoIterator`
|
= note: the trait bound `[i32]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[i32]`
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+ |
+LL | for _ in &v[1..] {
+ | +
+LL | for _ in &mut v[1..] {
+ | ++++
error[E0277]: the size for values of type `[K]` cannot be known at compilation time
--> $DIR/slice-issue-87994.rs:11:13
|
LL | for i2 in v2[1..] {
- | ^^^^^^^
- | |
- | expected an implementor of trait `IntoIterator`
- | help: consider borrowing here: `&v2[1..]`
+ | ^^^^^^^ expected an implementor of trait `IntoIterator`
|
= note: the trait bound `[K]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[K]`
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+ |
+LL | for i2 in &v2[1..] {
+ | +
+LL | for i2 in &mut v2[1..] {
+ | ++++
error[E0277]: `[K]` is not an iterator
--> $DIR/slice-issue-87994.rs:11:13
|
LL | for i2 in v2[1..] {
- | ^^^^^^^
- | |
- | expected an implementor of trait `IntoIterator`
- | help: consider borrowing here: `&v2[1..]`
+ | ^^^^^^^ expected an implementor of trait `IntoIterator`
|
= note: the trait bound `[K]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[K]`
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+ |
+LL | for i2 in &v2[1..] {
+ | +
+LL | for i2 in &mut v2[1..] {
+ | ++++
error: aborting due to 4 previous errors
--- /dev/null
+trait Trait {}
+
+struct A;
+struct B;
+struct C;
+
+impl Trait for &A {}
+impl Trait for &mut A {}
+
+impl Trait for &B {}
+
+impl Trait for &mut C {}
+
+fn foo<X: Trait>(_: X) {}
+
+fn main() {
+ let a = A;
+ let b = B;
+ let c = C;
+ foo(a); //~ ERROR the trait bound `A: Trait` is not satisfied
+ foo(b); //~ ERROR the trait bound `B: Trait` is not satisfied
+ foo(c); //~ ERROR the trait bound `C: Trait` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `A: Trait` is not satisfied
+ --> $DIR/suggest-imm-mut-trait-implementations.rs:20:9
+ |
+LL | foo(a);
+ | --- ^ expected an implementor of trait `Trait`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `foo`
+ --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11
+ |
+LL | fn foo<X: Trait>(_: X) {}
+ | ^^^^^ required by this bound in `foo`
+help: consider borrowing here
+ |
+LL | foo(&a);
+ | +
+LL | foo(&mut a);
+ | ++++
+
+error[E0277]: the trait bound `B: Trait` is not satisfied
+ --> $DIR/suggest-imm-mut-trait-implementations.rs:21:9
+ |
+LL | foo(b);
+ | --- ^ expected an implementor of trait `Trait`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `foo`
+ --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11
+ |
+LL | fn foo<X: Trait>(_: X) {}
+ | ^^^^^ required by this bound in `foo`
+help: consider borrowing here
+ |
+LL | foo(&b);
+ | +
+
+error[E0277]: the trait bound `C: Trait` is not satisfied
+ --> $DIR/suggest-imm-mut-trait-implementations.rs:22:9
+ |
+LL | foo(c);
+ | --- ^ expected an implementor of trait `Trait`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `foo`
+ --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11
+ |
+LL | fn foo<X: Trait>(_: X) {}
+ | ^^^^^ required by this bound in `foo`
+help: consider mutably borrowing here
+ |
+LL | foo(&mut c);
+ | ++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
// run-pass
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::thread;
pub fn main() { test05(); }
}
fn test05() {
- let three: Box<_> = box 3;
+ let three: Box<_> = Box::new(3);
let fn_to_send = move|n:isize| {
println!("{}", *three + n); // will copy x into the closure
assert_eq!(*three, 3);
#![allow(unused_must_use)]
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::thread;
use std::sync::mpsc::channel;
pub fn main() {
let (tx, rx) = channel::<usize>();
- let x: Box<isize> = box 1;
+ let x: Box<isize> = Box::new(1);
let x_in_parent = &(*x) as *const isize as usize;
let t = thread::spawn(move || {
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::thread;
swim_speed: 998,
name: "alec_guinness".to_string(),
};
- let arc = Arc::new(vec![box catte as Box<dyn Pet+Sync+Send>,
- box dogge1 as Box<dyn Pet+Sync+Send>,
- box fishe as Box<dyn Pet+Sync+Send>,
- box dogge2 as Box<dyn Pet+Sync+Send>]);
+ let arc = Arc::new(vec![
+ Box::new(catte) as Box<dyn Pet+Sync+Send>,
+ Box::new(dogge1) as Box<dyn Pet+Sync+Send>,
+ Box::new(fishe) as Box<dyn Pet+Sync+Send>,
+ Box::new(dogge2) as Box<dyn Pet+Sync+Send>]);
let (tx1, rx1) = channel();
let arc1 = arc.clone();
let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); });
#![allow(dead_code)]
#![allow(unused_mut)]
#![allow(unused_variables)]
-#![feature(box_syntax)]
use std::io::{self, Write};
// blanket impl for T:Copy coexists with an impl for Box<T>, because
// Box does not impl Copy.
-#![feature(box_syntax)]
trait Get {
fn get(&self) -> Self;
}
impl Get for Box<i32> {
- fn get(&self) -> Box<i32> { box get_it(&**self) }
+ fn get(&self) -> Box<i32> { Box::new(get_it(&**self)) }
}
fn get_it<T:Get>(t: &T) -> T {
// run-pass
-#![feature(box_syntax)]
-
use std::collections::HashMap;
trait Graph<Node, Edge> {
}
pub fn main() {
- let g : Box<HashMap<isize,isize>> = box HashMap::new();
+ let g : Box<HashMap<isize,isize>> = Box::new(HashMap::new());
let _g2 : Box<dyn Graph<isize,isize>> = g as Box<dyn Graph<isize,isize>>;
}
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
-
trait repeat<A> { fn get(&self) -> A; }
impl<A:Clone + 'static> repeat<A> for Box<A> {
}
fn repeater<A:Clone + 'static>(v: Box<A>) -> Box<dyn repeat<A>+'static> {
- box v as Box<dyn repeat<A>+'static> // No
+ Box::new(v) as Box<dyn repeat<A>+'static> // No
}
pub fn main() {
let x = 3;
- let y = repeater(box x);
+ let y = repeater(Box::new(x));
assert_eq!(x, y.get());
}
--> $DIR/negated-auto-traits-error.rs:48:13
|
LL | is_send(Box::new(TestType));
- | ------- ^^^^^^^^^^^^^^^^^^
- | | |
- | | expected an implementor of trait `Send`
- | | help: consider borrowing here: `&Box::new(TestType)`
+ | ------- ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Send`
+ | |
| required by a bound introduced by this call
|
= note: the trait bound `dummy2::TestType: Send` is not satisfied
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
+help: consider borrowing here
+ |
+LL | is_send(&Box::new(TestType));
+ | +
error[E0277]: `dummy3::TestType` cannot be sent between threads safely
--> $DIR/negated-auto-traits-error.rs:56:13
--> $DIR/negated-auto-traits-error.rs:66:13
|
LL | is_sync(Outer2(TestType));
- | ------- ^^^^^^^^^^^^^^^^
- | | |
- | | expected an implementor of trait `Sync`
- | | help: consider borrowing here: `&Outer2(TestType)`
+ | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync`
+ | |
| required by a bound introduced by this call
|
= note: the trait bound `main::TestType: Sync` is not satisfied
|
LL | fn is_sync<T: Sync>(_: T) {}
| ^^^^ required by this bound in `is_sync`
+help: consider borrowing here
+ |
+LL | is_sync(&Outer2(TestType));
+ | +
+LL | is_sync(&mut Outer2(TestType));
+ | ++++
error: aborting due to 7 previous errors
// Testing creating two vtables with the same self type, but different
// traits.
-#![feature(box_syntax)]
-
use std::any::Any;
trait Wrap {
}
fn main() {
- let x = box 22isize as Box<dyn Wrap>;
+ let x = Box::new(22isize) as Box<dyn Wrap>;
println!("x={}", x.get());
let y = x.wrap();
}
// run-pass
// test for #8664
-#![feature(box_syntax)]
-
use std::marker;
pub trait Trait2<A> {
}
pub fn main() {
- let a = box () as Box<dyn Trait<u8, u8>>;
+ let a = Box::new(()) as Box<dyn Trait<u8, u8>>;
assert_eq!(a.method(Type::Constant((1, 2))), 0);
}
-#![feature(box_syntax)]
-
#[allow(non_camel_case_types)]
+
+
trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
//~^ ERROR this associated function takes 0 generic arguments but 1
10.blah::<i32, i32>();
//~^ ERROR this associated function takes 1 generic argument but 2
- (box 10 as Box<dyn bar>).dup();
+ (Box::new(10) as Box<dyn bar>).dup();
//~^ ERROR E0038
//~| ERROR E0038
+ //~| ERROR E0038
}
| ^^^^ -
error[E0038]: the trait `bar` cannot be made into an object
- --> $DIR/test-2.rs:13:16
+ --> $DIR/test-2.rs:13:22
|
-LL | (box 10 as Box<dyn bar>).dup();
- | ^^^^^^^^^^^^ `bar` cannot be made into an object
+LL | (Box::new(10) as Box<dyn bar>).dup();
+ | ^^^^^^^^^^^^ `bar` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/test-2.rs:4:30
+ |
+LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
+ | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters
+ | | |
+ | | ...because method `dup` references the `Self` type in its return type
+ | this trait cannot be made into an object...
+ = help: consider moving `dup` to another trait
+ = help: consider moving `blah` to another trait
+
+error[E0038]: the trait `bar` cannot be made into an object
+ --> $DIR/test-2.rs:13:5
+ |
+LL | (Box::new(10) as Box<dyn bar>).dup();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/test-2.rs:4:30
error[E0038]: the trait `bar` cannot be made into an object
--> $DIR/test-2.rs:13:6
|
-LL | (box 10 as Box<dyn bar>).dup();
- | ^^^^^^ `bar` cannot be made into an object
+LL | (Box::new(10) as Box<dyn bar>).dup();
+ | ^^^^^^^^^^^^ `bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/test-2.rs:4:30
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
= note: required by cast to type `Box<dyn bar>`
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.
// run-pass
-#![feature(box_syntax, trait_upcasting)]
+#![feature(trait_upcasting)]
#![allow(incomplete_features)]
struct Test {
fn main() {
let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
- let mut test = box Test { func: closure };
+ let mut test = Box::new(Test { func: closure });
(test.func)();
}
#![allow(dead_code)]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
fn p_foo<T>(_pinned: T) { }
fn s_foo<T>(_shared: T) { }
fn u_foo<T:Send>(_unique: T) { }
pub fn main() {
p_foo(r(10));
- p_foo::<Box<_>>(box r(10));
- p_foo::<Box<_>>(box 10);
+ p_foo::<Box<_>>(Box::new(r(10)));
+ p_foo::<Box<_>>(Box::new(10));
p_foo(10);
- s_foo::<Box<_>>(box 10);
+ s_foo::<Box<_>>(Box::new(10));
s_foo(10);
- u_foo::<Box<_>>(box 10);
+ u_foo::<Box<_>>(Box::new(10));
u_foo(10);
}
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
-#![feature(box_syntax)]
// Example from lkuper's intern talk, August 2012 -- now with static
// methods!
assert!(Equal::isEq(&leaf(cyan), &leaf(cyan)));
assert!(!Equal::isEq(&leaf(cyan), &leaf(yellow)));
- assert!(Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)),
- &branch(box leaf(magenta), box leaf(cyan))));
+ assert!(Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))),
+ &branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))));
- assert!(!Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)),
- &branch(box leaf(magenta), box leaf(magenta))));
+ assert!(!Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))),
+ &branch(Box::new(leaf(magenta)), Box::new(leaf(magenta)))));
println!("Assertions all succeeded!");
}
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
-#![feature(box_syntax)]
// Example from lkuper's intern talk, August 2012.
use Color::{cyan, magenta, yellow, black};
assert!(leaf(cyan).isEq(&leaf(cyan)));
assert!(!leaf(cyan).isEq(&leaf(yellow)));
- assert!(branch(box leaf(magenta), box leaf(cyan))
- .isEq(&branch(box leaf(magenta), box leaf(cyan))));
+ assert!(branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))
+ .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))));
- assert!(!branch(box leaf(magenta), box leaf(cyan))
- .isEq(&branch(box leaf(magenta), box leaf(magenta))));
+ assert!(!branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))
+ .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(magenta)))));
println!("Assertions all succeeded!");
}
-#![feature(box_syntax)]
-
struct Foo {
f: isize,
}
+
+
impl Foo {
fn foo(self: isize, x: isize) -> isize {
//~^ ERROR invalid `self` parameter type
}
fn main() {
- let foo = box Foo {
+ let foo = Box::new(Foo {
f: 1,
- };
+ });
println!("{}", foo.foo(2));
- let bar = box Bar {
+ let bar = Box::new(Bar {
f: 1,
- };
+ });
println!("{} {}", bar.foo(2), bar.bar(2));
}
// run-pass
-#![feature(box_syntax)]
use std::ops::FnMut;
fn make_adder(x: i32) -> Box<dyn FnMut(i32)->i32+'static> {
- (box move |y: i32| -> i32 { x + y }) as
+ Box::new(move |y: i32| -> i32 { x + y }) as
Box<dyn FnMut(i32)->i32+'static>
}
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
+
#![deny(unreachable_patterns)]
mod foo {
-#![feature(box_syntax)]
-
trait Foo {
fn f(&self);
}
}
}
+
+
fn main() {
- let x = box Bar { x: 10 };
+ let x = Box::new(Bar { x: 10 });
let y: Box<dyn Foo> = x as Box<dyn Foo>;
let _z = y.clone(); //~ ERROR the method
}
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let mut i: Box<_> = box 1;
+ let mut i: Box<_> = Box::new(1);
// Should be a copy
let mut j;
j = i.clone();
// run-pass
#![allow(unused_assignments)]
-#![feature(box_syntax)]
-
pub fn main() {
- let i: Box<_> = box 1;
- let mut j: Box<_> = box 2;
+ let i: Box<_> = Box::new(1);
+ let mut j: Box<_> = Box::new(2);
// Should drop the previous value of j
j = i;
assert_eq!(*j, 1);
// run-pass
-#![feature(box_syntax)]
fn f<T>(t: T) -> T {
let t1 = t;
}
pub fn main() {
- let t = f::<Box<_>>(box 100);
- assert_eq!(t, box 100);
+ let t = f::<Box<_>>(Box::new(100));
+ assert_eq!(t, Box::new(100));
}
// run-pass
#![allow(unused_mut)]
-#![feature(box_syntax)]
pub fn main() {
let mut i: Box<_>;
- i = box 1;
+ i = Box::new(1);
assert_eq!(*i, 1);
}
// run-pass
-#![feature(box_syntax)]
struct J { j: isize }
pub fn main() {
- let i: Box<_> = box J {
+ let i: Box<_> = Box::new(J {
j: 100
- };
+ });
assert_eq!(i.j, 100);
}
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box vec![100];
+ let i: Box<_> = Box::new(vec![100]);
assert_eq!((*i)[0], 100);
}
// run-pass
#![allow(unused_allocation)]
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 100;
- assert_eq!(i, box 100);
- assert!(i < box 101);
- assert!(i <= box 100);
- assert!(i > box 99);
- assert!(i >= box 99);
+ let i: Box<_> = Box::new(100);
+ assert_eq!(i, Box::new(100));
+ assert!(i < Box::new(101));
+ assert!(i <= Box::new(100));
+ assert!(i > Box::new(99));
+ assert!(i >= Box::new(99));
}
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
enum t { t1(isize), t2(isize), }
- let _x: Box<_> = box t::t1(10);
+ let _x: Box<_> = Box::new(t::t1(10));
/*alt *x {
t1(a) {
}*/
/*alt x {
- box t1(a) {
+ Box::new(t1(a) {
assert_eq!(a, 10);
- }
+ })
_ { panic!(); }
}*/
}
#![allow(dead_code)]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
- let _: Box<_> = box 100;
+ let _: Box<_> = Box::new(100);
}
fn vec() {
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let mut i: Box<_> = box 1;
+ let mut i: Box<_> = Box::new(1);
// Should be a copy
let mut j = i.clone();
*i = 2;
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 1;
+ let i: Box<_> = Box::new(1);
let j = i;
assert_eq!(*j, 1);
}
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
let j = i;
assert_eq!(*j, 100);
}
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
assert_eq!(*i, 100);
}
// run-pass
#![feature(box_patterns)]
-#![feature(box_syntax)]
struct Foo { a: isize, b: isize }
pub fn main() {
- let box Foo{a, b} = box Foo{a: 100, b: 200};
+ let box Foo{ a, b } = Box::new(Foo { a: 100, b: 200 });
assert_eq!(a + b, 300);
}
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
- let _x: Box<_> = box vec![0,0,0,0,0];
+ let _x: Box<_> = Box::new(vec![0,0,0,0,0]);
}
// run-pass
-#![feature(box_syntax)]
fn f(i: Box<isize>) {
assert_eq!(*i, 100);
}
pub fn main() {
- let i = box 100;
+ let i = Box::new(100);
f(i);
}
// run-pass
-#![feature(box_syntax)]
fn f(i: &mut Box<isize>) {
- *i = box 200;
+ *i = Box::new(200);
}
pub fn main() {
- let mut i = box 100;
+ let mut i = Box::new(100);
f(&mut i);
assert_eq!(*i, 200);
}
// run-pass
-#![feature(box_syntax)]
fn f(i: Box<isize>) {
assert_eq!(*i, 100);
}
pub fn main() {
- f(box 100);
- let i = box 100;
+ f(Box::new(100));
+ let i = Box::new(100);
f(i);
}
// run-pass
-#![feature(box_syntax)]
fn f() -> Box<isize> {
- box 100
+ Box::new(100)
}
pub fn main() {
- assert_eq!(f(), box 100);
+ assert_eq!(f(), Box::new(100));
}
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
-
fn test1() {
enum bar { u(Box<isize>), w(isize), }
- let x = bar::u(box 10);
+ let x = bar::u(Box::new(10));
assert!(match x {
bar::u(a) => {
println!("{}", a);
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let mut a: Vec<Box<_>> = vec![box 10];
+ let mut a: Vec<Box<_>> = vec![Box::new(10)];
let b = a.clone();
assert_eq!(*a[0], 10);
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let vect : Vec<Box<_>> = vec![box 100];
- assert_eq!(vect[0], box 100);
+ let vect : Vec<Box<_>> = vec![Box::new(100)];
+ assert_eq!(vect[0], Box::new(100));
}
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
- let _i: Box<_> = box 100;
+ let _i: Box<_> = Box::new(100);
}
// run-pass
-#![feature(box_syntax)]
use std::cmp::PartialEq;
use std::fmt::Debug;
assert!(i != j);
}
- let i: Box<_> = box 100;
- let j: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(100);
f(i, j);
- let i: Box<_> = box 100;
- let j: Box<_> = box 101;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(101);
g(i, j);
}
assert!(i != j);
}
- let i: Box<_> = box 100;
- let j: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(100);
f(i, j);
- let i: Box<_> = box 100;
- let j: Box<_> = box 101;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(101);
g(i, j);
}
assert!(i != j);
}
- let i: Box<_> = box 100;
- let j: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(100);
f(i, j);
- let i: Box<_> = box 100;
- let j: Box<_> = box 101;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(101);
g(i, j);
}
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
println!("{}", i);
}
// run-pass
#![allow(unused_variables)]
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 100;
- let j: Box<_> = box 200;
+ let i: Box<_> = Box::new(100);
+ let j: Box<_> = Box::new(200);
let j = i;
assert_eq!(*j, 100);
}
// run-pass
#![allow(unused_mut)]
-#![feature(box_syntax)]
pub fn main() {
let mut i: Box<_>;
- i = box 100;
+ i = Box::new(100);
assert_eq!(*i, 100);
}
// run-pass
#![allow(unused_mut)]
-#![feature(box_syntax)]
pub fn main() {
- let i: Box<_> = box 100;
+ let i: Box<_> = Box::new(100);
let mut j;
j = i;
assert_eq!(*j, 100);
// run-pass
-#![feature(box_syntax)]
pub fn main() {
- let mut i: Box<_> = box 0;
+ let mut i: Box<_> = Box::new(0);
*i = 1;
assert_eq!(*i, 1);
}
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub trait EventLoop { fn foo(&self) {} }
pub struct UvEventLoop {
impl EventLoop for UvEventLoop { }
pub fn main() {
- let loop_: Box<dyn EventLoop> = box UvEventLoop { uvio: 0 } as Box<dyn EventLoop>;
+ let loop_: Box<dyn EventLoop> = Box::new(UvEventLoop { uvio: 0 }) as Box<dyn EventLoop>;
let _loop2_ = loop_;
}
#![allow(non_shorthand_field_patterns)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
struct Foo {a: isize, b: usize}
enum bar { u(Box<Foo>), w(isize), }
pub fn main() {
- assert!(match bar::u(box Foo{a: 10, b: 40}) {
- bar::u(box Foo{a: a, b: b}) => { a + (b as isize) }
- _ => { 66 }
- } == 50);
+ let v = match bar::u(Box::new(Foo{ a: 10, b: 40 })) {
+ bar::u(box Foo{ a: a, b: b }) => { a + (b as isize) }
+ _ => { 66 }
+ };
+ assert_eq!(v, 50);
}
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
-
enum bar { u(Box<isize>), w(isize), }
pub fn main() {
- assert!(match bar::u(box 10) {
- bar::u(a) => {
- println!("{}", a);
- *a
- }
- _ => { 66 }
- } == 10);
+ let v = match bar::u(10.into()) {
+ bar::u(a) => {
+ println!("{}", a);
+ *a
+ }
+ _ => { 66 }
+ };
+ assert_eq!(v, 10);
}
// run-pass
#![feature(box_patterns)]
-#![feature(box_syntax)]
fn simple() {
- match box true {
+ match Box::new(true) {
box true => { }
_ => { panic!(); }
}
// run-pass
-#![feature(box_syntax)]
struct X { x: isize }
pub fn main() {
- let x: Box<_> = box X {x: 1};
+ let x: Box<_> = Box::new(X {x: 1});
let bar = x;
assert_eq!(bar.x, 1);
}
#![allow(unused_must_use)]
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::sync::mpsc::{channel, Sender};
use std::thread;
fn child(tx: &Sender<Box<usize>>, i: usize) {
- tx.send(box i).unwrap();
+ tx.send(Box::new(i)).unwrap();
}
pub fn main() {
// run-pass
-#![feature(box_syntax)]
use std::sync::mpsc::channel;
pub fn main() {
let (tx, rx) = channel::<Box<_>>();
- tx.send(box 100).unwrap();
+ tx.send(Box::new(100)).unwrap();
let v = rx.recv().unwrap();
- assert_eq!(v, box 100);
+ assert_eq!(v, Box::new(100));
}
// run-pass
-#![feature(box_syntax)]
use std::mem::swap;
pub fn main() {
- let mut i: Box<_> = box 100;
- let mut j: Box<_> = box 200;
+ let mut i: Box<_> = Box::new(100);
+ let mut j: Box<_> = Box::new(200);
swap(&mut i, &mut j);
- assert_eq!(i, box 200);
- assert_eq!(j, box 100);
+ assert_eq!(i, Box::new(200));
+ assert_eq!(j, Box::new(100));
}
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_imports)]
-#![feature(box_syntax)]
// Test sized-ness checking in substitution.
struct S;
impl T2 for S {
fn f() -> Box<S> {
- box S
+ Box::new(S)
}
}
fn f5<X: ?Sized+T2>(x: &X) {
}
impl T3 for S {
fn f() -> Box<S> {
- box S
+ Box::new(S)
}
}
fn f7<X: ?Sized+T3>(x: &X) {
// Test structs with always-unsized fields.
#![allow(warnings)]
-#![feature(box_syntax, unsize, ptr_metadata)]
+#![feature(unsize, ptr_metadata)]
use std::mem;
use std::ptr;
f: [T; 3],
}
- let data: Box<Foo_<i32>> = box Foo_ { f: [1, 2, 3] };
+ let data: Box<Foo_<i32>> = Box::new(Foo_ { f: [1, 2, 3] });
let x: &Foo<i32> = mem::transmute(slice::from_raw_parts(&*data, 3));
assert_eq!(x.f.len(), 3);
assert_eq!(x.f[0], 1);
}
let data: Box<_> =
- box Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] };
+ Box::new(Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] });
let x: &Baz = mem::transmute(slice::from_raw_parts(&*data, 5));
assert_eq!(x.f1, 42);
let chs: Vec<char> = x.f2.chars().collect();
f: St,
}
- let obj: Box<St> = box St { f: 42 };
+ let obj: Box<St> = Box::new(St { f: 42 });
let obj: &Tr = &*obj;
- let data: Box<_> = box Qux_ { f: St { f: 234 } };
+ let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } });
let x: &Qux = &*ptr::from_raw_parts::<Qux>((&*data as *const _).cast(), ptr::metadata(obj));
assert_eq!(x.f.foo(), 234);
}
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
- let _x: Box<_> = box 1;
+ let _x: Box<_> = Box::new(1);
let lam_move = || {};
lam_move();
}
// pretty-expanded FIXME #23616
#![allow(path_statements)]
-#![feature(box_syntax)]
-pub fn main()
-{
- let y: Box<_> = box 1;
+pub fn main() {
+ let y: Box<_> = Box::new(1);
y;
}
// run-pass
// ignore-emscripten no threads support
-#![feature(box_syntax)]
-
use std::thread;
fn f() {
- let _a: Box<_> = box 0;
+ let _a: Box<_> = Box::new(0);
panic!();
}
-#![feature(box_syntax)]
-
use std::fmt;
struct Number {
}
fn main() {
- let n: Box<_> = box Number { n: 42 };
- let mut l: Box<_> = box List { list: Vec::new() };
+
+ let n: Box<_> = Number { n: 42 }.into();
+ let mut l: Box<_> = List { list: Vec::new() }.into();
l.push(n);
+
let x = n.to_string();
//~^ ERROR: borrow of moved value: `n`
}
error[E0382]: borrow of moved value: `n`
--> $DIR/use-after-move-implicity-coerced-object.rs:28:13
|
-LL | let n: Box<_> = box Number { n: 42 };
+LL | let n: Box<_> = Number { n: 42 }.into();
| - move occurs because `n` has type `Box<Number>`, which does not implement the `Copy` trait
-LL | let mut l: Box<_> = box List { list: Vec::new() };
+LL | let mut l: Box<_> = List { list: Vec::new() }.into();
LL | l.push(n);
| - value moved here
+LL |
LL | let x = n.to_string();
| ^ value borrowed here after move
-#![feature(box_syntax)]
-
struct S {
x: Box<isize>,
}
+
+
impl S {
pub fn foo(self) -> isize {
self.bar();
}
fn main() {
- let x = S { x: box 1 };
+ let x = S { x: 1.into() };
println!("{}", x.foo());
}
// Regression test for #87549.
-// compile-flags: -C incremental=tmp/wf/hir-wf-check-erase-regions
+// incremental
pub struct Table<T, const N: usize>([Option<T>; N]);
// be sure we have `self` parameter in this function
if let AssocItemKind::Fn { has_self: true } = trait_item.kind {
trait_self_ty =
- Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty());
+ Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty().skip_binder());
}
}
}
declare_clippy_lint! {
/// ### What it does
/// Checks for use of `.iter().nth()` (and the related
- /// `.iter_mut().nth()`) on standard library types with O(1) element access.
+ /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
///
/// ### Why is this bad?
/// `.get()` and `.get_mut()` are more efficient and more
then {
let first_arg_span = first_arg_ty.span;
let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
- let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
+ let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
wrong_self_convention::check(
cx,
&item.ident.name.as_str(),
if item.ident.name == sym::new;
if let TraitItemKind::Fn(_, _) = item.kind;
let ret_ty = return_ty(cx, item.hir_id());
- let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
+ let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
if !contains_ty(cx.tcx, ret_ty, self_ty);
then {
},
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => Ok(()),
Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
+ Rvalue::ShallowInitBox(_, _) => Ok(()),
Rvalue::UnaryOp(_, operand) => {
let ty = operand.ty(body, tcx);
if ty.is_integral() || ty.is_bool() {
pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
}
+
+/// Absolute path to the directory to use for incremental compilation. Example:
+/// /path/to/build/host-triple/test/ui/relative/testname.mode/testname.inc
+pub fn incremental_dir(config: &Config, testpaths: &TestPaths) -> PathBuf {
+ output_base_name(config, testpaths, None).with_extension("inc")
+}
// testing harness and used when generating compilation
// arguments. (In particular, it propagates to the aux-builds.)
pub incremental_dir: Option<PathBuf>,
+ // If `true`, this test will use incremental compilation.
+ //
+ // This can be set manually with the `incremental` header, or implicitly
+ // by being a part of an incremental mode test. Using the `incremental`
+ // header should be avoided if possible; using an incremental mode test is
+ // preferred. Incremental mode tests support multiple passes, which can
+ // verify that the incremental cache can be loaded properly after being
+ // created. Just setting the header will only verify the behavior with
+ // creating an incremental cache, but doesn't check that it is created
+ // correctly.
+ //
+ // Compiletest will create the incremental directory, and ensure it is
+ // empty before the test starts. Incremental mode tests will reuse the
+ // incremental directory between passes in the same test.
+ pub incremental: bool,
// How far should the test proceed while still passing.
pass_mode: Option<PassMode>,
// Ignore `--pass` overrides from the command line for this test.
pretty_compare_only: false,
forbid_output: vec![],
incremental_dir: None,
+ incremental: false,
pass_mode: None,
fail_mode: None,
ignore_pass: false,
if !self.stderr_per_bitwidth {
self.stderr_per_bitwidth = config.parse_stderr_per_bitwidth(ln);
}
+
+ if !self.incremental {
+ self.incremental = config.parse_incremental(ln);
+ }
});
}
self.failure_status = 101;
}
+ if config.mode == Mode::Incremental {
+ self.incremental = true;
+ }
+
for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
if let Ok(val) = env::var(key) {
if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() {
fn parse_edition(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "edition")
}
+
+ fn parse_incremental(&self, line: &str) -> bool {
+ self.parse_name_directive(line, "incremental")
+ }
}
fn expand_variables(mut value: String, config: &Config) -> String {
// ignore-tidy-filelength
use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
-use crate::common::{output_base_dir, output_base_name, output_testname_unique};
+use crate::common::{incremental_dir, output_base_dir, output_base_name, output_testname_unique};
use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui};
use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
use crate::common::{CompareMode, FailMode, PassMode};
print!("\n\n");
}
debug!("running {:?}", testpaths.file.display());
- let props = TestProps::from_file(&testpaths.file, revision, &config);
+ let mut props = TestProps::from_file(&testpaths.file, revision, &config);
+ if props.incremental {
+ props.incremental_dir = Some(incremental_dir(&config, testpaths));
+ }
let cx = TestCx { config: &config, props: &props, testpaths, revision };
create_dir_all(&cx.output_base_dir()).unwrap();
+ if props.incremental {
+ cx.init_incremental_test();
+ }
if config.mode == Incremental {
// Incremental tests are special because they cannot be run in
// parallel.
assert!(!props.revisions.is_empty(), "Incremental tests require revisions.");
- cx.init_incremental_test();
for revision in &props.revisions {
- let revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config);
+ let mut revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config);
+ revision_props.incremental_dir = props.incremental_dir.clone();
let rev_cx = TestCx {
config: &config,
props: &revision_props,
// incremental workproduct directory. Delete any old
// incremental work products that may be there from prior
// runs.
- let incremental_dir = self.incremental_dir();
+ let incremental_dir = self.props.incremental_dir.as_ref().unwrap();
if incremental_dir.exists() {
// Canonicalizing the path will convert it to the //?/ format
// on Windows, which enables paths longer than 260 character
fs::create_dir_all(&incremental_dir).unwrap();
if self.config.verbose {
- print!("init_incremental_test: incremental_dir={}", incremental_dir.display());
+ println!("init_incremental_test: incremental_dir={}", incremental_dir.display());
}
}
let revision = self.revision.expect("incremental tests require a list of revisions");
// Incremental workproduct directory should have already been created.
- let incremental_dir = self.incremental_dir();
+ let incremental_dir = self.props.incremental_dir.as_ref().unwrap();
assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
- // Add an extra flag pointing at the incremental directory.
- let mut revision_props = self.props.clone();
- revision_props.incremental_dir = Some(incremental_dir);
-
- let revision_cx = TestCx {
- config: self.config,
- props: &revision_props,
- testpaths: self.testpaths,
- revision: self.revision,
- };
-
if self.config.verbose {
- print!("revision={:?} revision_props={:#?}", revision, revision_props);
+ print!("revision={:?} props={:#?}", revision, self.props);
}
if revision.starts_with("rpass") {
- if revision_cx.props.should_ice {
- revision_cx.fatal("can only use should-ice in cfail tests");
+ if self.props.should_ice {
+ self.fatal("can only use should-ice in cfail tests");
}
- revision_cx.run_rpass_test();
+ self.run_rpass_test();
} else if revision.starts_with("rfail") {
- if revision_cx.props.should_ice {
- revision_cx.fatal("can only use should-ice in cfail tests");
+ if self.props.should_ice {
+ self.fatal("can only use should-ice in cfail tests");
}
- revision_cx.run_rfail_test();
+ self.run_rfail_test();
} else if revision.starts_with("cfail") {
- revision_cx.run_cfail_test();
+ self.run_cfail_test();
} else {
- revision_cx.fatal("revision name must begin with rpass, rfail, or cfail");
+ self.fatal("revision name must begin with rpass, rfail, or cfail");
}
}
- /// Directory where incremental work products are stored.
- fn incremental_dir(&self) -> PathBuf {
- self.output_base_name().with_extension("inc")
- }
-
fn run_rmake_test(&self) {
let cwd = env::current_dir().unwrap();
let src_root = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap();
let skip = [
"tidy-test-file",
"compiler/rustc_codegen_cranelift",
+ "compiler/rustc_codegen_gcc",
"src/llvm-project",
"library/backtrace",
"library/stdarch",