uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
env:
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
os: ubuntu-latest-xl
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: x86_64-apple
+ env:
+ SCRIPT: "./x.py --stage 2 test"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: x86_64-apple
+ env:
+ SCRIPT: "./x.py --stage 2 test"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
- name: x86_64-msvc-1
env:
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
- self-hosted
- ARM64
- linux
- - name: dist-x86_64-apple
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- os: macos-latest
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- os: macos-latest
- - name: x86_64-apple
- env:
- SCRIPT: "./x.py --stage 2 test"
- RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- os: macos-latest
timeout-minutes: 600
runs-on: "${{ matrix.os }}"
steps:
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
"if_chain",
"itertools 0.9.0",
"lazy_static",
- "pulldown-cmark",
+ "pulldown-cmark 0.7.2",
"quine-mc_cluskey",
"quote",
"regex-syntax",
"log",
"memchr",
"open",
- "pulldown-cmark",
+ "pulldown-cmark 0.7.2",
"regex",
"serde",
"serde_derive",
"unicase",
]
+[[package]]
+name = "pulldown-cmark"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+dependencies = [
+ "bitflags",
+ "memchr",
+ "unicase",
+]
+
[[package]]
name = "punycode"
version = "0.4.1"
"expect-test",
"itertools 0.9.0",
"minifier",
- "pulldown-cmark",
+ "pulldown-cmark 0.8.0",
"rustc-rayon",
"serde",
"serde_json",
let start = match start {
Bound::Included(lo) => lo,
- Bound::Excluded(lo) => lo + 1,
+ Bound::Excluded(lo) => lo.checked_add(1)?,
Bound::Unbounded => 0,
};
let end = match end {
- Bound::Included(hi) => hi + 1,
+ Bound::Included(hi) => hi.checked_add(1)?,
Bound::Excluded(hi) => hi,
Bound::Unbounded => length,
};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
use rustc_middle::hir::map::Map;
+use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_middle::ty::{self, DefIdTree, InferConst, Ty};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::kw;
use rustc_span::Span;
local_visitor.visit_expr(expr);
}
+ let mut param_name = None;
+ let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
+ let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+ if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind {
+ param_name = Some(param);
+ }
+ origin.span
+ } else {
+ local_visitor.target_span
+ };
+
let error_code = error_code.into();
- let mut err = self.tcx.sess.struct_span_err_with_code(
- local_visitor.target_span,
- "type annotations needed",
- error_code,
- );
+ let mut err =
+ self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
- err.note("unable to infer the value of a const parameter");
+ if let Some(param_name) = param_name {
+ err.note(&format!("cannot infer the value of the const parameter `{}`", param_name));
+ } else {
+ err.note("unable to infer the value of a const parameter");
+ }
err
}
debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
if sub == &ty::ReStatic
- && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some()
+ && v.0.into_iter().any(|t| t.span.desugaring_kind().is_none())
{
// If the failure is due to a `'static` requirement coming from a `dyn` or
// `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
pub enum ConstVariableOriginKind {
MiscVariable,
ConstInference,
+ // FIXME(const_generics): Consider storing the `DefId` of the param here.
ConstParameterDefinition(Symbol),
SubstitutionPlaceholder,
}
/// Constants
///
/// Two constants are equal if they are the same constant. Note that
-/// this does not necessarily mean that they are "==" in Rust -- in
-/// particular one must be wary of `NaN`!
+/// this does not necessarily mean that they are `==` in Rust -- in
+/// particular, one must be wary of `NaN`!
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)]
pub struct Constant<'tcx> {
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_macros::HashStable;
+use rustc_span::Span;
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub enum PointerCast {
pub struct OverloadedDeref<'tcx> {
pub region: ty::Region<'tcx>,
pub mutbl: hir::Mutability,
+ /// The `Span` associated with the field access or method call
+ /// that triggered this overloaded deref.
+ pub span: Span,
}
impl<'tcx> OverloadedDeref<'tcx> {
use std::ops::{Bound, Deref};
use std::sync::Arc;
-/// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
-/// except through `tcx.err*()`, which are in this module.
+/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
+/// except through the error-reporting functions on a [`tcx`][TyCtxt].
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[derive(TyEncodable, TyDecodable, HashStable)]
pub struct DelaySpanBugEmitted(());
// Suggestion:
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
// - insert: `, T: Zar`
+ //
+ // Additionally, there may be no `where` clause whatsoever in the case that this was
+ // reached because the generic parameter has a default:
+ //
+ // Message:
+ // trait Foo<T=()> {... }
+ // - help: consider further restricting this type parameter with `where T: Zar`
+ //
+ // Suggestion:
+ // trait Foo<T=()> where T: Zar {... }
+ // - insert: `where T: Zar`
- let mut param_spans = Vec::new();
+ if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
+ && generics.where_clause.predicates.len() == 0
+ {
+ // Suggest a bound, but there is no existing `where` clause *and* the type param has a
+ // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
+ err.span_suggestion_verbose(
+ generics.where_clause.tail_span_for_suggestion(),
+ &msg_restrict_type_further,
+ format!(" where {}: {}", param_name, constraint),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let mut param_spans = Vec::new();
- for predicate in generics.where_clause.predicates {
- if let WherePredicate::BoundPredicate(WhereBoundPredicate {
- span, bounded_ty, ..
- }) = predicate
- {
- if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
- if let Some(segment) = path.segments.first() {
- if segment.ident.to_string() == param_name {
- param_spans.push(span);
+ for predicate in generics.where_clause.predicates {
+ if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+ span,
+ bounded_ty,
+ ..
+ }) = predicate
+ {
+ if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
+ if let Some(segment) = path.segments.first() {
+ if segment.ident.to_string() == param_name {
+ param_spans.push(span);
+ }
}
}
}
}
- }
- match ¶m_spans[..] {
- &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
- _ => {
- err.span_suggestion_verbose(
- generics.where_clause.tail_span_for_suggestion(),
- &msg_restrict_type_further,
- format!(", {}: {}", param_name, constraint),
- Applicability::MachineApplicable,
- );
+ match ¶m_spans[..] {
+ &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
+ _ => {
+ err.span_suggestion_verbose(
+ generics.where_clause.tail_span_for_suggestion(),
+ &msg_restrict_type_further,
+ format!(", {}: {}", param_name, constraint),
+ Applicability::MachineApplicable,
+ );
+ }
}
}
}
match self.tcx().trimmed_def_paths(LOCAL_CRATE).get(&def_id) {
- None => return Ok((self, false)),
+ None => Ok((self, false)),
Some(symbol) => {
self.write_str(&symbol.as_str())?;
- return Ok((self, true));
+ Ok((self, true))
}
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.region)
- .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl })
+ tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref {
+ region,
+ mutbl: self.mutbl,
+ span: self.span,
+ })
}
}
/// particular, imagine a type like this:
///
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
- /// ^ ^ | | |
- /// | | | | |
- /// | +------------+ 0 | |
- /// | | |
- /// +--------------------------------+ 1 |
- /// | |
- /// +------------------------------------------+ 0
+ /// ^ ^ | | |
+ /// | | | | |
+ /// | +------------+ 0 | |
+ /// | | |
+ /// +----------------------------------+ 1 |
+ /// | |
+ /// +----------------------------------------------+ 0
///
/// In this type, there are two binders (the outer fn and the inner
/// fn). We need to be able to determine, for any given region, which
///
/// Returning true means the type is known to be sized. Returning
/// `false` means nothing -- could be sized, might not be.
+ ///
+ /// Note that we could never rely on the fact that a type such as `[_]` is
+ /// trivially `!Sized` because we could be in a type environment with a
+ /// bound such as `[_]: Copy`. A function with such a bound obviously never
+ /// can be called, but that doesn't mean it shouldn't typecheck. This is why
+ /// this method doesn't return `Option<bool>`.
pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
let span = use_spans.args_or_use();
let move_site_vec = self.get_moved_indexes(location, mpi);
- debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec);
+ debug!(
+ "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
+ move_site_vec, use_spans
+ );
let move_out_indices: Vec<_> =
move_site_vec.iter().map(|move_site| move_site.moi).collect();
);
}
}
+ // Deref::deref takes &self, which cannot cause a move
+ FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
}
} else {
err.span_label(
self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str);
}
+ if let UseSpans::FnSelfUse {
+ kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
+ ..
+ } = use_spans
+ {
+ err.note(&format!(
+ "{} occurs due to deref coercion to `{}`",
+ desired_action.as_noun(),
+ deref_target_ty
+ ));
+
+ err.span_note(deref_target, "deref defined here");
+ }
+
if let Some((_, mut old_err)) =
self.move_error_reported.insert(move_out_indices, (used_place, err))
{
name: &str,
borrow: &BorrowData<'tcx>,
drop_span: Span,
- borrow_spans: UseSpans,
+ borrow_spans: UseSpans<'tcx>,
explanation: BorrowExplanation,
) -> DiagnosticBuilder<'cx> {
debug!(
location: Location,
borrow: &BorrowData<'tcx>,
drop_span: Span,
- borrow_spans: UseSpans,
+ borrow_spans: UseSpans<'tcx>,
proper_span: Span,
explanation: BorrowExplanation,
) -> DiagnosticBuilder<'cx> {
fn report_escaping_closure_capture(
&mut self,
- use_span: UseSpans,
+ use_span: UseSpans<'tcx>,
var_span: Span,
fr_name: &RegionName,
category: ConstraintCategory,
fn later_use_kind(
&self,
borrow: &BorrowData<'tcx>,
- use_spans: UseSpans,
+ use_spans: UseSpans<'tcx>,
location: Location,
) -> (LaterUseKind, Span) {
match use_spans {
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
use rustc_middle::ty::print::Print;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
use rustc_span::{
hygiene::{DesugaringKind, ForLoopLoc},
symbol::sym,
/// The span(s) associated to a use of a place.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum UseSpans {
+pub(super) enum UseSpans<'tcx> {
/// The access is caused by capturing a variable for a closure.
ClosureUse {
/// This is true if the captured variable was from a generator.
fn_call_span: Span,
/// The definition span of the method being called
fn_span: Span,
- kind: FnSelfUseKind,
+ kind: FnSelfUseKind<'tcx>,
},
/// This access is caused by a `match` or `if let` pattern.
PatUse(Span),
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum FnSelfUseKind {
+pub(super) enum FnSelfUseKind<'tcx> {
/// A normal method call of the form `receiver.foo(a, b, c)`
Normal { self_arg: Ident, implicit_into_iter: bool },
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
FnOnceCall,
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
Operator { self_arg: Ident },
+ DerefCoercion {
+ /// The `Span` of the `Target` associated type
+ /// in the `Deref` impl we are using.
+ deref_target: Span,
+ /// The type `T::Deref` we are dereferencing to
+ deref_target_ty: Ty<'tcx>,
+ },
}
-impl UseSpans {
+impl UseSpans<'_> {
pub(super) fn args_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { args_span: span, .. }
| UseSpans::PatUse(span)
- | UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
+ UseSpans::FnSelfUse {
+ fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+ } => fn_call_span,
+ UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
match self {
UseSpans::ClosureUse { var_span: span, .. }
| UseSpans::PatUse(span)
- | UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
+ UseSpans::FnSelfUse {
+ fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+ } => fn_call_span,
+ UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
&self,
moved_place: PlaceRef<'tcx>, // Could also be an upvar.
location: Location,
- ) -> UseSpans {
+ ) -> UseSpans<'tcx> {
use self::UseSpans::*;
let stmt = match self.body[location.block].statements.get(location.statement_index) {
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
}) = &self.body[location.block].terminator
{
- let method_did = if let Some(method_did) =
+ let (method_did, method_substs) = if let Some(info) =
crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
{
- method_did
+ info
} else {
return normal_ret;
};
let tcx = self.infcx.tcx;
-
let parent = tcx.parent(method_did);
let is_fn_once = parent == tcx.lang_items().fn_once_trait();
let is_operator = !from_hir_call
&& parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
+ let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
let fn_call_span = *fn_span;
let self_arg = tcx.fn_arg_names(method_did)[0];
+ debug!(
+ "terminator = {:?} from_hir_call={:?}",
+ self.body[location.block].terminator, from_hir_call
+ );
+
+ // Check for a 'special' use of 'self' -
+ // an FnOnce call, an operator (e.g. `<<`), or a
+ // deref coercion.
let kind = if is_fn_once {
- FnSelfUseKind::FnOnceCall
+ Some(FnSelfUseKind::FnOnceCall)
} else if is_operator {
- FnSelfUseKind::Operator { self_arg }
+ Some(FnSelfUseKind::Operator { self_arg })
+ } else if is_deref {
+ let deref_target =
+ tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
+ Instance::resolve(tcx, self.param_env, deref_target, method_substs)
+ .transpose()
+ });
+ if let Some(Ok(instance)) = deref_target {
+ let deref_target_ty = instance.ty(tcx, self.param_env);
+ Some(FnSelfUseKind::DerefCoercion {
+ deref_target: tcx.def_span(instance.def_id()),
+ deref_target_ty,
+ })
+ } else {
+ None
+ }
} else {
+ None
+ };
+
+ let kind = kind.unwrap_or_else(|| {
+ // This isn't a 'special' use of `self`
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
let implicit_into_iter = matches!(
fn_call_span.desugaring_kind(),
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
);
FnSelfUseKind::Normal { self_arg, implicit_into_iter }
- };
+ });
return FnSelfUse {
var_span: stmt.source_info.span,
/// and its usage of the local assigned at `location`.
/// This is done by searching in statements succeeding `location`
/// and originating from `maybe_closure_span`.
- pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
+ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
use self::UseSpans::*;
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
/// Helper to retrieve span(s) of given borrow from the current MIR
/// representation
- pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
+ pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
let span = self.body.source_info(borrow.reserve_location).span;
self.borrow_spans(span, borrow.reserve_location)
}
// Everything that isn't from pattern matching.
OtherIllegalMove {
original_path: Place<'tcx>,
- use_spans: UseSpans,
+ use_spans: UseSpans<'tcx>,
kind: IllegalMoveOriginKind<'tcx>,
},
}
let (mut err, err_span) = {
let (span, use_spans, original_path, kind): (
Span,
- Option<UseSpans>,
+ Option<UseSpans<'tcx>>,
Place<'tcx>,
&IllegalMoveOriginKind<'_>,
) = match error {
move_place: Place<'tcx>,
deref_target_place: Place<'tcx>,
span: Span,
- use_spans: Option<UseSpans>,
+ use_spans: Option<UseSpans<'tcx>>,
) -> DiagnosticBuilder<'a> {
// Inspect the type of the content behind the
// borrow to provide feedback about why this
if let ReturnConstraint::ClosureUpvar(upvar) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
DefiningTy::Closure(def_id, _) => def_id,
- ty @ _ => bug!("unexpected DefiningTy {:?}", ty),
+ ty => bug!("unexpected DefiningTy {:?}", ty),
};
let upvar_def_span = self.infcx.tcx.hir().span(upvar);
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt};
use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
use rustc_span::{Span, Symbol, DUMMY_SP};
if let Err((move_data, move_errors)) = move_data_results {
let mut promoted_mbcx = MirBorrowckCtxt {
infcx,
+ param_env,
body: promoted_body,
mir_def_id: def.did,
move_data: &move_data,
let mut mbcx = MirBorrowckCtxt {
infcx,
+ param_env,
body,
mir_def_id: def.did,
move_data: &mdpe.move_data,
crate struct MirBorrowckCtxt<'cx, 'tcx> {
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
+ param_env: ParamEnv<'tcx>,
body: &'cx Body<'tcx>,
mir_def_id: LocalDefId,
move_data: &'cx MoveData<'tcx>,
use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt};
use rustc_span::symbol::Symbol;
+use super::PartitioningCx;
use crate::monomorphize::collector::InliningMap;
use crate::monomorphize::partitioning::merging;
use crate::monomorphize::partitioning::{
impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
fn place_root_mono_items(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
) -> PreInliningPartitioning<'tcx> {
let mut roots = FxHashSet::default();
let mut codegen_units = FxHashMap::default();
- let is_incremental_build = tcx.sess.opts.incremental.is_some();
+ let is_incremental_build = cx.tcx.sess.opts.incremental.is_some();
let mut internalization_candidates = FxHashSet::default();
// Determine if monomorphizations instantiated in this crate will be made
// available to downstream crates. This depends on whether we are in
// share-generics mode and whether the current crate can even have
// downstream crates.
- let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics();
+ let export_generics =
+ cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics();
- let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+ let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
let cgu_name_cache = &mut FxHashMap::default();
for mono_item in mono_items {
- match mono_item.instantiation_mode(tcx) {
+ match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => continue,
}
- let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item);
+ let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
let is_volatile = is_incremental_build && mono_item.is_generic_fn();
let codegen_unit_name = match characteristic_def_id {
Some(def_id) => compute_codegen_unit_name(
- tcx,
+ cx.tcx,
cgu_name_builder,
def_id,
is_volatile,
let mut can_be_internalized = true;
let (linkage, visibility) = mono_item_linkage_and_visibility(
- tcx,
+ cx.tcx,
&mono_item,
&mut can_be_internalized,
export_generics,
fn merge_codegen_units(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- target_cgu_count: usize,
) {
- merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count);
+ merging::merge_codegen_units(cx, initial_partitioning);
}
fn place_inlined_mono_items(
&mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: PreInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
) -> PostInliningPartitioning<'tcx> {
let mut new_partitioning = Vec::new();
let mut mono_item_placements = FxHashMap::default();
// Collect all items that need to be available in this codegen unit.
let mut reachable = FxHashSet::default();
for root in old_codegen_unit.items().keys() {
- follow_inlining(*root, inlining_map, &mut reachable);
+ follow_inlining(*root, cx.inlining_map, &mut reachable);
}
let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name());
fn internalize_symbols(
&mut self,
- _tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
partitioning: &mut PostInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
) {
if partitioning.codegen_units.len() == 1 {
// Fast path for when there is only one codegen unit. In this case we
// Build a map from every monomorphization to all the monomorphizations that
// reference it.
let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default();
- inlining_map.iter_accesses(|accessor, accessees| {
+ cx.inlining_map.iter_accesses(|accessor, accessees| {
for accessee in accessees {
accessor_map.entry(*accessee).or_default().push(accessor);
}
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder};
-use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{Symbol, SymbolStr};
+use super::PartitioningCx;
use crate::monomorphize::partitioning::PreInliningPartitioning;
pub fn merge_codegen_units<'tcx>(
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- target_cgu_count: usize,
) {
- assert!(target_cgu_count >= 1);
+ assert!(cx.target_cgu_count >= 1);
let codegen_units = &mut initial_partitioning.codegen_units;
// Note that at this point in time the `codegen_units` here may not be in a
codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect();
// Merge the two smallest codegen units until the target size is reached.
- while codegen_units.len() > target_cgu_count {
+ while codegen_units.len() > cx.target_cgu_count {
// Sort small cgus to the back
codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
let mut smallest = codegen_units.pop().unwrap();
);
}
- let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+ let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
- if tcx.sess.opts.incremental.is_some() {
+ if cx.tcx.sess.opts.incremental.is_some() {
// If we are doing incremental compilation, we want CGU names to
// reflect the path of the source level module they correspond to.
// For CGUs that contain the code of multiple modules because of the
for cgu in codegen_units.iter_mut() {
if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
- if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
+ if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
cgu.set_name(Symbol::intern(&new_cgu_name));
} else {
// If we don't require CGU names to be human-readable, we
use crate::monomorphize::collector::InliningMap;
use crate::monomorphize::collector::{self, MonoItemCollectionMode};
+pub struct PartitioningCx<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ target_cgu_count: usize,
+ inlining_map: &'a InliningMap<'tcx>,
+}
+
trait Partitioner<'tcx> {
fn place_root_mono_items(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
) -> PreInliningPartitioning<'tcx>;
fn merge_codegen_units(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- target_cgu_count: usize,
);
fn place_inlined_mono_items(
&mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: PreInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
) -> PostInliningPartitioning<'tcx>;
fn internalize_symbols(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
partitioning: &mut PostInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
);
}
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
let mut partitioner = get_partitioner(tcx);
+ let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map };
// In the first step, we place all regular monomorphizations into their
// respective 'home' codegen unit. Regular monomorphizations are all
// functions and statics defined in the local crate.
let mut initial_partitioning = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
- partitioner.place_root_mono_items(tcx, mono_items)
+ partitioner.place_root_mono_items(cx, mono_items)
};
initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
// Merge until we have at most `max_cgu_count` codegen units.
{
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
- partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count);
+ partitioner.merge_codegen_units(cx, &mut initial_partitioning);
debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
}
// local functions the definition of which is marked with `#[inline]`.
let mut post_inlining = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
- partitioner.place_inlined_mono_items(initial_partitioning, inlining_map)
+ partitioner.place_inlined_mono_items(cx, initial_partitioning)
};
post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
// more freedom to optimize.
if !tcx.sess.link_dead_code() {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
- partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map);
+ partitioner.internalize_symbols(cx, &mut post_inlining);
}
// Finally, sort by codegen unit name, so that we get deterministic results.
.note("each usage of a `const` item creates a new temporary")
.note("the mutable reference will refer to this temporary, not the original `const` item");
- if let Some(method_did) = method_did {
+ if let Some((method_did, _substs)) = method_did {
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
}
}
}
- return None;
+ None
}
}
use rustc_middle::mir::*;
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
/// Checks if the specified `local` is used as the `self` prameter of a method call
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
/// returned.
-pub fn find_self_call(
- tcx: TyCtxt<'_>,
- body: &Body<'_>,
+pub fn find_self_call<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
local: Local,
block: BasicBlock,
-) -> Option<DefId> {
+) -> Option<(DefId, SubstsRef<'tcx>)> {
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
&body[block].terminator
{
debug!("find_self_call: func={:?}", func);
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
- if let ty::FnDef(def_id, _) = *ty.kind() {
+ if let ty::FnDef(def_id, substs) = *ty.kind() {
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
{
debug!("find_self_call: args={:?}", args);
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
if self_place.as_local() == Some(local) {
- return Some(def_id);
+ return Some((def_id, substs));
}
}
}
},
};
- overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
+ overloaded_place(
+ cx,
+ hir_expr,
+ adjustment.target,
+ Some(call),
+ vec![expr.to_ref()],
+ deref.span,
+ )
}
Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
hir::ExprKind::Index(ref lhs, ref index) => {
if cx.typeck_results().is_method_call(expr) {
- overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
+ overloaded_place(
+ cx,
+ expr,
+ expr_ty,
+ None,
+ vec![lhs.to_ref(), index.to_ref()],
+ expr.span,
+ )
} else {
ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
}
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
if cx.typeck_results().is_method_call(expr) {
- overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
+ overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span)
} else {
ExprKind::Deref { arg: arg.to_ref() }
}
place_ty: Ty<'tcx>,
overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
args: Vec<ExprRef<'tcx>>,
+ span: Span,
) -> ExprKind<'tcx> {
// For an overloaded *x or x[y] expression of type T, the method
// call returns an &T and we must add the deref so that the types
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
let (region, mutbl) = match *recv_ty.kind() {
ty::Ref(region, _, mutbl) => (region, mutbl),
- _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"),
+ _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
};
let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
// construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let fun = method_callee(cx, expr, expr.span, overloaded_callee);
+ let fun = method_callee(cx, expr, span, overloaded_callee);
let ref_expr = Expr {
temp_lifetime,
ty: ref_ty,
- span: expr.span,
+ span,
kind: ExprKind::Call {
ty: fun.ty,
fun: fun.to_ref(),
args,
from_hir_call: false,
- fn_span: expr.span,
+ fn_span: span,
},
};
}
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
- let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
+ let and_span = self.prev_token.span;
+ let mut opt_lifetime =
+ if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
let mutbl = self.parse_mutability();
+ if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
+ // A lifetime is invalid here: it would be part of a bare trait bound, which requires
+ // it to be followed by a plus, but we disallow plus in the pointee type.
+ // So we can handle this case as an error here, and suggest `'a mut`.
+ // If there *is* a plus next though, handling the error later provides better suggestions
+ // (like adding parentheses)
+ if !self.look_ahead(1, |t| t.is_like_plus()) {
+ let lifetime_span = self.token.span;
+ let span = and_span.to(lifetime_span);
+
+ let mut err = self.struct_span_err(span, "lifetime must precede `mut`");
+ if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {
+ err.span_suggestion(
+ span,
+ "place the lifetime before `mut`",
+ format!("&{} mut", lifetime_src),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
+
+ opt_lifetime = Some(self.expect_lifetime());
+ }
+ }
let ty = self.parse_ty_no_plus()?;
Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
}
);
err
}
- ResolutionError::ParamInNonTrivialAnonConst(name) => {
+ ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
let mut err = self.session.struct_span_err(
span,
"generic parameters must not be used inside of non trivial constant values",
name
),
);
- err.help(
- &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
- );
+
+ if is_type {
+ err.note("type parameters are currently not permitted in anonymous constants");
+ } else {
+ err.help(
+ &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants",
+ name
+ )
+ );
+ }
+
err
}
ResolutionError::SelfInTyParamDefault => {
}
};
- let lifetime_names: Vec<_> = lifetime_names.into_iter().collect();
+ let lifetime_names: Vec<_> = lifetime_names.iter().collect();
match (&lifetime_names[..], snippet.as_deref()) {
([name], Some("&")) => {
suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name));
/// generic parameters must not be used inside of non trivial constant values.
///
/// This error is only emitted when using `min_const_generics`.
- ParamInNonTrivialAnonConst(Symbol),
+ ParamInNonTrivialAnonConst { name: Symbol, is_type: bool },
/// Error E0735: type parameters with a default cannot use `Self`
SelfInTyParamDefault,
/// Error E0767: use of unreachable label
if record_used {
self.report_error(
span,
- ResolutionError::ParamInNonTrivialAnonConst(
- rib_ident.name,
- ),
+ ResolutionError::ParamInNonTrivialAnonConst {
+ name: rib_ident.name,
+ is_type: true,
+ },
);
}
return Res::Err;
if record_used {
self.report_error(
span,
- ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+ ResolutionError::ParamInNonTrivialAnonConst {
+ name: rib_ident.name,
+ is_type: false,
+ },
);
}
return Res::Err;
deny,
deprecated,
deref,
+ deref_method,
deref_mut,
+ deref_target,
derive,
diagnostic,
direct,
("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
+ ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
--- /dev/null
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+ Ok(Target {
+ llvm_target: "riscv32-unknown-linux-gnu".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ target_env: "gnu".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ arch: "riscv32".to_string(),
+ target_os: "linux".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: TargetOptions {
+ unsupported_abis: super::riscv_base::unsupported_abis(),
+ code_model: Some(CodeModel::Medium),
+ cpu: "generic-rv32".to_string(),
+ features: "+m,+a,+f,+d,+c".to_string(),
+ llvm_abiname: "ilp32d".to_string(),
+ max_atomic_width: Some(32),
+ ..super::linux_base::opts()
+ },
+ })
+}
// Meta infos:
infcx: &'a InferCtxt<'a, 'tcx>,
span: Span,
+ overloaded_span: Span,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
span: Span,
base_ty: Ty<'tcx>,
+ overloaded_span: Span,
) -> Autoderef<'a, 'tcx> {
Autoderef {
infcx,
span,
+ overloaded_span,
body_id,
param_env,
state: AutoderefSnapshot {
self.span
}
+ pub fn overloaded_span(&self) -> Span {
+ self.overloaded_span
+ }
+
pub fn reached_recursion_limit(&self) -> bool {
self.state.reached_recursion_limit
}
}
if !skip_leak_check.is_yes() {
- if let Err(_) = infcx.leak_check(true, snapshot) {
+ if infcx.leak_check(true, snapshot).is_err() {
debug!("overlap: leak check failed");
return None;
}
// avoid inundating the user with unnecessary errors, but we now
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
- if self
- .tcx
- .lang_items()
- .sized_trait()
- .map_or(false, |sized_id| sized_id == trait_ref.def_id())
- {
+ if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
return;
}
};
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
- let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
+ let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
// Re-add the `&`
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
.map(|i| chalk_ir::AssocTypeId(i.def_id))
.collect();
- let well_known = if self
- .interner
- .tcx
- .lang_items()
- .sized_trait()
- .map(|t| def_id == t)
- .unwrap_or(false)
- {
+ let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
- } else if self.interner.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false)
- {
+ } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
- } else if self.interner.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false)
- {
+ } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
- } else if self.interner.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false)
- {
+ } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
- } else if self.interner.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) {
+ } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
} else if self
.interner
}
// If all the obligations hold (or there are no obligations) the tail expression
// we can suggest to return a boxed trait object instead of an opaque type.
- if suggest_box { self.ret_type_span.clone() } else { None }
+ if suggest_box { self.ret_type_span } else { None }
}
_ => None,
};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
- Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
+ Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
+ }
+
+ /// Like `autoderef`, but provides a custom `Span` to use for calls to
+ /// an overloaded `Deref` operator
+ pub fn autoderef_overloaded_span(
+ &'a self,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ overloaded_span: Span,
+ ) -> Autoderef<'a, 'tcx> {
+ Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
}
pub fn try_overloaded_deref(
|InferOk { value: method, obligations: o }| {
obligations.extend(o);
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
- Some(OverloadedDeref { region, mutbl })
+ Some(OverloadedDeref {
+ region,
+ mutbl,
+ span: autoderef.overloaded_span(),
+ })
} else {
None
}
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
let no_accessible_remaining_fields = remaining_fields
.iter()
- .filter(|(_, (_, field))| {
+ .find(|(_, (_, field))| {
field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
})
- .next()
.is_none();
if no_accessible_remaining_fields {
) -> Ty<'tcx> {
// Commit the autoderefs by calling `autoderef` again, but this
// time writing the results into the various typeck results.
- let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
+ let mut autoderef =
+ self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
let (_, n) = match autoderef.nth(pick.autoderefs) {
Some(n) => n,
None => {
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
let ParamEnvAnd { param_env, value: self_ty } = goal;
- let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
- .include_raw_pointers()
- .silence_errors();
+ let mut autoderef =
+ Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+ .include_raw_pointers()
+ .silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef
.by_ref()
} else if !etc && !unmentioned_fields.is_empty() {
let no_accessible_unmentioned_fields = unmentioned_fields
.iter()
- .filter(|(field, _)| {
+ .find(|(field, _)| {
field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
})
- .next()
.is_none();
if no_accessible_unmentioned_fields {
) {
let method = self.register_infer_ok_obligations(ok);
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
- *deref = OverloadedDeref { region, mutbl };
+ *deref = OverloadedDeref { region, mutbl, span: deref.span };
}
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
// This helps avoid accidental drops.
# General build configuration options
# =============================================================================
[build]
+# The default stage to use for the `doc` subcommand
+#doc-stage = 0
+
+# The default stage to use for the `build` subcommand
+#build-stage = 1
+
+# The default stage to use for the `test` subcommand
+#test-stage = 1
+
+# The default stage to use for the `dist` subcommand
+#dist-stage = 2
+
+# The default stage to use for the `install` subcommand
+#install-stage = 2
+
+# The default stage to use for the `bench` subcommand
+#bench-stage = 2
# Build triple for the original snapshot compiler. This must be a compiler that
# nightlies are already produced for. The current platform must be able to run
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T> From<BinaryHeap<T>> for Vec<T> {
+ /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
+ ///
+ /// This conversion requires no data movement or allocation, and has
+ /// constant time complexity.
fn from(heap: BinaryHeap<T>) -> Vec<T> {
heap.data
}
where
R: RangeBounds<usize>,
{
- // SAFETY: This buffer is only used to check the range. It might be partially
- // uninitialized, but `check_range` needs a contiguous slice.
- // https://github.com/rust-lang/rust/pull/75207#discussion_r471193682
- let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) };
- let Range { start, end } = buffer.check_range(range);
+ let Range { start, end } = slice::check_range(self.len(), range);
let tail = self.wrap_add(self.tail, start);
let head = self.wrap_add(self.tail, end);
(tail, head)
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(array_chunks)]
+#![feature(array_windows)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
use crate::boxed::Box;
use crate::vec::Vec;
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub use core::slice::check_range;
#[unstable(feature = "array_chunks", issue = "74985")]
pub use core::slice::ArrayChunks;
#[unstable(feature = "array_chunks", issue = "74985")]
pub use core::slice::ArrayChunksMut;
+#[unstable(feature = "array_windows", issue = "75027")]
+pub use core::slice::ArrayWindows;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[stable(feature = "from_ref", since = "1.28.0")]
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
use core::ptr;
+use core::slice;
use core::str::{lossy, pattern::Pattern};
use crate::borrow::{Cow, ToOwned};
// of the vector version. The data is just plain bytes.
// Because the range removal happens in Drop, if the Drain iterator is leaked,
// the removal will not happen.
- let Range { start, end } = self.as_bytes().check_range(range);
+ let Range { start, end } = slice::check_range(self.len(), range);
assert!(self.is_char_boundary(start));
assert!(self.is_char_boundary(end));
///
/// // ... and that's all!
/// // you can also do it like this:
-/// let x : &[usize] = &v;
+/// let u: &[usize] = &v;
+/// // or like this:
+/// let u: &[_] = &v;
/// ```
///
/// In Rust, it's more common to pass slices as arguments rather than vectors
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
- let Range { start, end } = self.check_range(range);
+ let Range { start, end } = slice::check_range(len, range);
unsafe {
// set self.vec length's to start, to be safe in case Drain is leaked
/// A draining iterator for `Vec<T>`.
///
/// This `struct` is created by [`Vec::drain`].
+/// See its documentation for more.
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
/// Index of tail to preserve
#![feature(slice_ptr_get)]
#![feature(split_inclusive)]
#![feature(binary_heap_retain)]
+#![feature(deque_range)]
#![feature(inplace_iteration)]
#![feature(iter_map_while)]
foo::<&str>("x");
}
+
+#[test]
+fn test_str_multiline() {
+ let a: String = "this \
+is a test"
+ .to_string();
+ let b: String = "this \
+ is \
+ another \
+ test"
+ .to_string();
+ assert_eq!(a, "this is a test".to_string());
+ assert_eq!(b, "this is another test".to_string());
+}
+
+#[test]
+fn test_str_escapes() {
+ let x = "\\\\\
+ ";
+ assert_eq!(x, r"\\"); // extraneous whitespace stripped
+}
use std::borrow::Cow;
use std::collections::TryReserveError::*;
use std::mem::size_of;
+use std::ops::Bound::*;
pub trait IntoCow<'a, B: ?Sized>
where
#[test]
#[should_panic]
fn test_split_off_mid_char() {
- let mut orig = String::from("å±±");
- let _ = orig.split_off(1);
+ let mut shan = String::from("å±±");
+ let _broken_mountain = shan.split_off(1);
}
#[test]
assert_eq!(t, "");
}
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+ let mut s = String::from("abc");
+ s.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+ let mut s = String::from("abc");
+ s.drain((Included(0), Included(usize::MAX)));
+}
+
#[test]
fn test_replace_range() {
let mut s = "Hello, world!".to_owned();
s.replace_range(5..=5, "789");
}
+#[test]
+#[should_panic]
+fn test_replace_range_start_overflow() {
+ let mut s = String::from("123");
+ s.replace_range((Excluded(usize::MAX), Included(0)), "");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_end_overflow() {
+ let mut s = String::from("456");
+ s.replace_range((Included(0), Included(usize::MAX)), "");
+}
+
#[test]
fn test_replace_range_empty() {
let mut s = String::from("12345");
use std::fmt::Debug;
use std::iter::InPlaceIterable;
use std::mem::size_of;
+use std::ops::Bound::*;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::rc::Rc;
use std::vec::{Drain, IntoIter};
assert_eq!(v.len(), usize::MAX - 1);
}
+#[test]
+#[should_panic]
+fn test_drain_index_overflow() {
+ let mut v = Vec::<()>::with_capacity(usize::MAX);
+ unsafe {
+ v.set_len(usize::MAX);
+ }
+ v.drain(0..=usize::MAX);
+}
+
#[test]
#[should_panic]
fn test_drain_inclusive_out_of_bounds() {
v.drain(5..=5);
}
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+ let mut v = vec![1, 2, 3];
+ v.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+ let mut v = vec![1, 2, 3];
+ v.drain((Included(0), Included(usize::MAX)));
+}
+
#[test]
fn test_drain_leak() {
static mut DROPS: i32 = 0;
#[test]
fn test_from_iter_specialization_with_iterator_adapters() {
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
- let src: Vec<usize> = vec![0usize; 65535];
+ let src: Vec<usize> = vec![0usize; 256];
let srcptr = src.as_ptr();
let iter = src
.into_iter()
use std::collections::{vec_deque::Drain, VecDeque};
use std::fmt::Debug;
use std::mem::size_of;
+use std::ops::Bound::*;
use std::panic::{catch_unwind, AssertUnwindSafe};
use crate::hash;
deq[3];
}
+#[test]
+#[should_panic]
+fn test_range_start_overflow() {
+ let deq = VecDeque::from(vec![1, 2, 3]);
+ deq.range((Included(0), Included(usize::MAX)));
+}
+
+#[test]
+#[should_panic]
+fn test_range_end_overflow() {
+ let deq = VecDeque::from(vec![1, 2, 3]);
+ deq.range((Excluded(usize::MAX), Included(0)));
+}
+
#[derive(Clone, PartialEq, Debug)]
enum Taggy {
One(i32),
/// ```
#[inline]
#[must_use]
+ #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn reverse(self) -> Ordering {
+ pub const fn reverse(self) -> Ordering {
match self {
Less => Greater,
Equal => Equal,
/// ```
#[inline]
#[must_use]
+ #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")]
#[stable(feature = "ordering_chaining", since = "1.17.0")]
- pub fn then(self, other: Ordering) -> Ordering {
+ pub const fn then(self, other: Ordering) -> Ordering {
match self {
Equal => other,
_ => self,
#[inline]
#[unstable(feature = "test", issue = "50297")]
#[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
-pub fn black_box<T>(dummy: T) -> T {
+pub fn black_box<T>(mut dummy: T) -> T {
// We need to "use" the argument in some way LLVM can't introspect, and on
// targets that support it we can typically leverage inline assembly to do
// this. LLVM's interpretation of inline assembly is that it's, well, a black
#[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
// SAFETY: the inline assembly is a no-op.
unsafe {
- llvm_asm!("" : : "r"(&dummy));
+ // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
+ llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
}
dummy
/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
-/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`flat_map`]: trait.Iterator.html#method.flat_map
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::flat_map`]. See its documentation
+/// for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
/// forever in an unreachable state. However, it does not guarantee that pointers
/// to this memory will remain valid.
///
-/// * If you want to leak memory, see [`Box::leak`][leak].
-/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw].
+/// * If you want to leak memory, see [`Box::leak`].
+/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`].
/// * If you want to dispose of a value properly, running its destructor, see
-/// [`mem::drop`][drop].
+/// [`mem::drop`].
///
/// # Safety
///
/// ownership to `s` — the final step of interacting with `v` to dispose of it without
/// running its destructor is entirely avoided.
///
-/// [drop]: fn.drop.html
-/// [uninit]: fn.uninitialized.html
-/// [clone]: ../clone/trait.Clone.html
-/// [swap]: fn.swap.html
-/// [box]: ../../std/boxed/struct.Box.html
-/// [leak]: ../../std/boxed/struct.Box.html#method.leak
-/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw
+/// [`Box`]: ../../std/boxed/struct.Box.html
+/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak
+/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw
+/// [`mem::drop`]: drop
/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [`ManuallyDrop`]: struct.ManuallyDrop.html
#[inline]
#[rustc_const_stable(feature = "const_forget", since = "1.46.0")]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// This function is just a shim intended to be removed when the `unsized_locals` feature gets
/// stabilized.
-///
-/// [`forget`]: fn.forget.html
#[inline]
#[unstable(feature = "forget_unsized", issue = "none")]
pub fn forget_unsized<T: ?Sized>(t: T) {
/// assert_eq!(2, mem::size_of::<ExampleUnion>());
/// ```
///
-/// [alignment]: ./fn.align_of.html
+/// [alignment]: align_of
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
-/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html
///
/// # Examples
///
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
-/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html
///
/// # Examples
///
/// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop
/// values one at a time and should use this API.
///
-/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html
+/// [`drop_in_place`]: crate::ptr::drop_in_place
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
///
/// # Examples
/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
/// It is useful for FFI sometimes, but should generally be avoided.
///
-/// [zeroed]: union.MaybeUninit.html#method.zeroed
+/// [zeroed]: MaybeUninit::zeroed
/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [inv]: union.MaybeUninit.html#initialization-invariant
+/// [inv]: MaybeUninit#initialization-invariant
///
/// # Examples
///
/// (Notice that the rules around uninitialized integers are not finalized yet, but
/// until they are, it is advisable to avoid them.)
///
-/// [`MaybeUninit<T>`]: union.MaybeUninit.html
-/// [uninit]: union.MaybeUninit.html#method.uninit
-/// [assume_init]: union.MaybeUninit.html#method.assume_init
-/// [inv]: union.MaybeUninit.html#initialization-invariant
+/// [`MaybeUninit<T>`]: MaybeUninit
+/// [uninit]: MaybeUninit::uninit
+/// [assume_init]: MaybeUninit::assume_init
+/// [inv]: MaybeUninit#initialization-invariant
#[inline(always)]
#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
#[stable(feature = "rust1", since = "1.0.0")]
/// assert_eq!(42, x);
/// assert_eq!(5, y);
/// ```
-///
-/// [`replace`]: fn.replace.html
-/// [`take`]: fn.take.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn swap<T>(x: &mut T, y: &mut T) {
/// assert_eq!(buffer.get_and_reset(), vec![0, 1]);
/// assert_eq!(buffer.buf.len(), 0);
/// ```
-///
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [`replace`]: fn.replace.html
-/// [`swap`]: fn.swap.html
#[inline]
#[stable(feature = "mem_take", since = "1.40.0")]
pub fn take<T: Default>(dest: &mut T) -> T {
/// assert_eq!(buffer.replace_index(0, 2), 0);
/// assert_eq!(buffer.buf[0], 2);
/// ```
-///
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [`swap`]: fn.swap.html
-/// [`take`]: fn.take.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
/// Because `_x` is moved into the function, it is automatically dropped before
/// the function returns.
///
-/// [drop]: ../ops/trait.Drop.html
+/// [drop]: Drop
///
/// # Examples
///
/// println!("x: {}, y: {}", x, y.0); // still available
/// ```
///
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
-/// [`Copy`]: ../../std/marker/trait.Copy.html
+/// [`RefCell`]: crate::cell::RefCell
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn drop<T>(_x: T) {}
/// `T`.
///
/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [size_of]: fn.size_of.html
///
/// # Examples
///
/// Opaque type representing the discriminant of an enum.
///
/// See the [`discriminant`] function in this module for more information.
-///
-/// [`discriminant`]: fn.discriminant.html
#[stable(feature = "discriminant_value", since = "1.21.0")]
pub struct Discriminant<T>(<T as DiscriminantKind>::Discriminant);
fn set_cw(cw: u16) {
// SAFETY: the `fldcw` instruction has been audited to be able to work correctly with
// any `u16`
- unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") }
+ unsafe {
+ asm!(
+ "fldcw ({})",
+ in(reg) &cw,
+ // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9.
+ options(att_syntax, nostack),
+ )
+ }
}
/// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`.
pub fn set_precision<T>() -> FPUControlWord {
- let cw = 0u16;
+ let mut cw = 0_u16;
// Compute the value for the Precision Control field that is appropriate for `T`.
let cw_precision = match size_of::<T>() {
// `FPUControlWord` structure is dropped
// SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with
// any `u16`
- unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") }
+ unsafe {
+ asm!(
+ "fnstcw ({})",
+ in(reg) &mut cw,
+ // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9.
+ options(att_syntax, nostack),
+ )
+ }
// Set the control word to the desired precision. This is achieved by masking away the old
// precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above.
///
/// This error is used as the error type for the [`FromStr`] implementation
/// for [`f32`] and [`f64`].
+///
+/// # Example
+///
+/// ```
+/// use std::str::FromStr;
+///
+/// if let Err(e) = f64::from_str("a.12") {
+/// println!("Failed conversion to f64: {}", e);
+/// }
+/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseFloatError {
///
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
+///
+/// # Example
+///
+/// ```
+/// if let Err(e) = i32::from_str_radix("a12", 10) {
+/// println!("Failed conversion to i32: {}", e);
+/// }
+/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseIntError {
}
/// Enum to store the various types of errors that can cause parsing an integer to fail.
+///
+/// # Example
+///
+/// ```
+/// #![feature(int_error_matching)]
+///
+/// # fn main() {
+/// if let Err(e) = i32::from_str_radix("a12", 10) {
+/// println!("Failed conversion to i32: {:?}", e.kind());
+/// }
+/// # }
+/// ```
#[unstable(
feature = "int_error_matching",
reason = "it can be useful to match errors when making error messages \
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_diagnostic_item = "deref_target"]
type Target: ?Sized;
/// Dereferences the value.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_diagnostic_item = "deref_method"]
fn deref(&self) -> &Self::Target;
}
//! Indexing implementations for `[T]`.
-use crate::ops;
+use crate::ops::{self, Bound, Range, RangeBounds};
use crate::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
panic!("attempted to index slice up to maximum usize");
}
+/// Performs bounds-checking of the given range.
+/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
+/// for slices of the given length.
+///
+/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
+/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
+///
+/// # Panics
+///
+/// Panics if the range is out of bounds.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(slice_check_range)]
+/// use std::slice;
+///
+/// let v = [10, 40, 30];
+/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
+/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
+/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
+/// ```
+///
+/// Panics when [`Index::index`] would panic:
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 2..1);
+/// ```
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 1..4);
+/// ```
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 1..=usize::MAX);
+/// ```
+///
+/// [`Index::index`]: ops::Index::index
+#[track_caller]
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
+ let start = match range.start_bound() {
+ Bound::Included(&start) => start,
+ Bound::Excluded(start) => {
+ start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
+ }
+ Bound::Unbounded => 0,
+ };
+
+ let end = match range.end_bound() {
+ Bound::Included(end) => {
+ end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
+ }
+ Bound::Excluded(&end) => end,
+ Bound::Unbounded => len,
+ };
+
+ if start > end {
+ slice_index_order_fail(start, end);
+ }
+ if end > len {
+ slice_end_index_len_fail(end, len);
+ }
+
+ Range { start, end }
+}
+
mod private_slice_index {
use super::ops;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
}
}
+/// A windowed iterator over a slice in overlapping chunks (`N` elements at a
+/// time), starting at the beginning of the slice
+///
+/// This struct is created by the [`array_windows`] method on [slices].
+///
+/// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug, Clone, Copy)]
+#[unstable(feature = "array_windows", issue = "75027")]
+pub struct ArrayWindows<'a, T: 'a, const N: usize> {
+ pub(crate) slice_head: *const T,
+ pub(crate) num: usize,
+ pub(crate) marker: marker::PhantomData<&'a [T; N]>,
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+ type Item = &'a [T; N];
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.num == 0 {
+ return None;
+ }
+ // SAFETY:
+ // This is safe because it's indexing into a slice guaranteed to be length > N.
+ let ret = unsafe { &*self.slice_head.cast::<[T; N]>() };
+ // SAFETY: Guaranteed that there are at least 1 item remaining otherwise
+ // earlier branch would've been hit
+ self.slice_head = unsafe { self.slice_head.add(1) };
+
+ self.num -= 1;
+ Some(ret)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.num, Some(self.num))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.num
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ if self.num <= n {
+ self.num = 0;
+ return None;
+ }
+ // SAFETY:
+ // This is safe because it's indexing into a slice guaranteed to be length > N.
+ let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() };
+ // SAFETY: Guaranteed that there are at least n items remaining
+ self.slice_head = unsafe { self.slice_head.add(n + 1) };
+
+ self.num -= n + 1;
+ Some(ret)
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.nth(self.num.checked_sub(1)?)
+ }
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T; N]> {
+ if self.num == 0 {
+ return None;
+ }
+ // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
+ let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() };
+ self.num -= 1;
+ Some(ret)
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> {
+ if self.num <= n {
+ self.num = 0;
+ return None;
+ }
+ // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
+ let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() };
+ self.num -= n + 1;
+ Some(ret)
+ }
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<T, const N: usize> ExactSizeIterator for ArrayWindows<'_, T, N> {
+ fn is_empty(&self) -> bool {
+ self.num == 0
+ }
+}
+
/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
/// time), starting at the beginning of the slice.
///
use crate::intrinsics::assume;
use crate::marker::{self, Copy};
use crate::mem;
-use crate::ops::{Bound, FnMut, Range, RangeBounds};
+use crate::ops::{FnMut, Range, RangeBounds};
use crate::option::Option;
use crate::option::Option::{None, Some};
use crate::ptr::{self, NonNull};
#[unstable(feature = "array_chunks", issue = "74985")]
pub use iter::{ArrayChunks, ArrayChunksMut};
+#[unstable(feature = "array_windows", issue = "75027")]
+pub use iter::ArrayWindows;
+
#[unstable(feature = "split_inclusive", issue = "72360")]
pub use iter::{SplitInclusive, SplitInclusiveMut};
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use index::SliceIndex;
-use index::{slice_end_index_len_fail, slice_index_order_fail};
-use index::{slice_end_index_overflow_fail, slice_start_index_overflow_fail};
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub use index::check_range;
#[lang = "slice"]
#[cfg(not(test))]
unsafe { &mut *index.get_unchecked_mut(self) }
}
- /// Converts a range over this slice to [`Range`].
- ///
- /// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
- ///
- /// [`get_unchecked`]: #method.get_unchecked
- /// [`get_unchecked_mut`]: #method.get_unchecked_mut
- ///
- /// # Panics
- ///
- /// Panics if the range is out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(slice_check_range)]
- ///
- /// let v = [10, 40, 30];
- /// assert_eq!(1..2, v.check_range(1..2));
- /// assert_eq!(0..2, v.check_range(..2));
- /// assert_eq!(1..3, v.check_range(1..));
- /// ```
- ///
- /// Panics when [`Index::index`] would panic:
- ///
- /// ```should_panic
- /// #![feature(slice_check_range)]
- ///
- /// [10, 40, 30].check_range(2..1);
- /// ```
- ///
- /// ```should_panic
- /// #![feature(slice_check_range)]
- ///
- /// [10, 40, 30].check_range(1..4);
- /// ```
- ///
- /// ```should_panic
- /// #![feature(slice_check_range)]
- ///
- /// [10, 40, 30].check_range(1..=usize::MAX);
- /// ```
- ///
- /// [`Index::index`]: crate::ops::Index::index
- #[track_caller]
- #[unstable(feature = "slice_check_range", issue = "76393")]
- pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
- let start = match range.start_bound() {
- Bound::Included(&start) => start,
- Bound::Excluded(start) => {
- start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
- }
- Bound::Unbounded => 0,
- };
-
- let len = self.len();
- let end = match range.end_bound() {
- Bound::Included(end) => {
- end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
- }
- Bound::Excluded(&end) => end,
- Bound::Unbounded => len,
- };
-
- if start > end {
- slice_index_order_fail(start, end);
- }
- if end > len {
- slice_end_index_len_fail(end, len);
- }
-
- Range { start, end }
- }
-
/// Returns a raw pointer to the slice's buffer.
///
/// The caller must ensure that the slice outlives the pointer this
}
}
+ /// Returns an iterator over overlapping windows of `N` elements of a slice,
+ /// starting at the beginning of the slice.
+ ///
+ /// This is the const generic equivalent of [`windows`].
+ ///
+ /// If `N` is smaller than the size of the array, it will return no windows.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N` is 0. This check will most probably get changed to a compile time
+ /// error before this method gets stabilized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_windows)]
+ /// let slice = [0, 1, 2, 3];
+ /// let mut iter = slice.array_windows();
+ /// assert_eq!(iter.next().unwrap(), &[0, 1]);
+ /// assert_eq!(iter.next().unwrap(), &[1, 2]);
+ /// assert_eq!(iter.next().unwrap(), &[2, 3]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`windows`]: #method.windows
+ #[unstable(feature = "array_windows", issue = "75027")]
+ #[inline]
+ pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
+ assert_ne!(N, 0);
+
+ let num_windows = self.len().saturating_sub(N - 1);
+ ArrayWindows { slice_head: self.as_ptr(), num: num_windows, marker: marker::PhantomData }
+ }
+
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
/// of the slice.
///
where
T: Copy,
{
- let Range { start: src_start, end: src_end } = self.check_range(src);
+ let Range { start: src_start, end: src_end } = check_range(self.len(), src);
let count = src_end - src_start;
assert!(dest <= self.len() - count, "dest is out of bounds");
// SAFETY: the conditions for `ptr::copy` have all been checked above,
#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
+ /// Convert to a `Ready` variant.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use core::task::Poll;
+ /// assert_eq!(Poll::from(true), Poll::Ready(true));
+ /// ```
fn from(t: T) -> Poll<T> {
Poll::Ready(t)
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn from_secs_f64(secs: f64) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn from_secs_f64(secs: f64) -> Duration {
const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
let nanos = secs * (NANOS_PER_SEC as f64);
if !nanos.is_finite() {
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn from_secs_f32(secs: f32) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn from_secs_f32(secs: f32) -> Duration {
const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
let nanos = secs * (NANOS_PER_SEC as f32);
if !nanos.is_finite() {
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn mul_f64(self, rhs: f64) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn mul_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(rhs * self.as_secs_f64())
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn mul_f32(self, rhs: f32) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn mul_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(rhs * self.as_secs_f32())
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn div_f64(self, rhs: f64) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn div_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(self.as_secs_f64() / rhs)
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn div_f32(self, rhs: f32) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn div_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(self.as_secs_f32() / rhs)
}
-use core::cmp::{self, Ordering::*};
+use core::cmp::{
+ self,
+ Ordering::{self, *},
+};
#[test]
fn test_int_totalord() {
assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 });
assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 });
}
+
+#[test]
+fn ordering_const() {
+ // test that the methods of `Ordering` are usable in a const context
+
+ const ORDERING: Ordering = Greater;
+
+ const REVERSE: Ordering = ORDERING.reverse();
+ assert_eq!(REVERSE, Less);
+
+ const THEN: Ordering = Equal.then(ORDERING);
+ assert_eq!(THEN, Greater);
+}
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_map)]
+#![feature(array_windows)]
#![feature(bool_to_option)]
#![feature(bound_cloned)]
#![feature(box_syntax)]
#![feature(core_private_diy_float)]
#![feature(debug_non_exhaustive)]
#![feature(dec2flt)]
+#![feature(div_duration)]
+#![feature(duration_consts_2)]
#![feature(duration_constants)]
#![feature(duration_saturating_ops)]
+#![feature(duration_zero)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]
int_module!(i32, i32);
+
+#[test]
+fn test_arith_operation() {
+ let a: isize = 10;
+ assert_eq!(a * (a - 1), 90);
+ let i32_a: isize = 10;
+ assert_eq!(i32_a, 10);
+ assert_eq!(i32_a - 10, 0);
+ assert_eq!(i32_a / 10, 1);
+ assert_eq!(i32_a - 20, -10);
+ assert_eq!(i32_a << 10, 10240);
+ assert_eq!(i32_a << 16, 655360);
+ assert_eq!(i32_a * 16, 160);
+ assert_eq!(i32_a * i32_a * i32_a, 1000);
+ assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
+ assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
+ assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
+ let i32_b: isize = 0x10101010;
+ assert_eq!(i32_b + 1 - 1, i32_b);
+ assert_eq!(i32_b << 1, i32_b << 1);
+ assert_eq!(i32_b >> 1, i32_b >> 1);
+ assert_eq!(i32_b & i32_b << 1, 0);
+ assert_eq!(i32_b | i32_b << 1, 0x30303030);
+ let i32_c: isize = 0x10101010;
+ assert_eq!(
+ i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
+ i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)
+ );
+}
assert_eq!(v1, [13, 14, 19, 20, 4]);
}
+#[test]
+fn test_array_windows_infer() {
+ let v: &[i32] = &[0, 1, 0, 1];
+ assert_eq!(v.array_windows::<2>().count(), 3);
+ let c = v.array_windows();
+ for &[a, b] in c {
+ assert_eq!(a + b, 1);
+ }
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::<i32>();
+ assert_eq!(total, 3 + 6 + 9 + 12 + 15);
+}
+
+#[test]
+fn test_array_windows_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.array_windows::<3>();
+ assert_eq!(c.count(), 4);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.array_windows::<6>();
+ assert_eq!(c2.count(), 0);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.array_windows::<2>();
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_array_windows_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let snd = v.array_windows::<4>().nth(1);
+ assert_eq!(snd, Some(&[1, 2, 3, 4]));
+ let mut arr_windows = v.array_windows::<2>();
+ assert_ne!(arr_windows.nth(0), arr_windows.nth(0));
+ let last = v.array_windows::<3>().last();
+ assert_eq!(last, Some(&[3, 4, 5]));
+}
+
+#[test]
+fn test_array_windows_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let snd = v.array_windows::<4>().nth_back(1);
+ assert_eq!(snd, Some(&[1, 2, 3, 4]));
+ let mut arr_windows = v.array_windows::<2>();
+ assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0));
+}
+
#[test]
fn test_rchunks_count() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s");
assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s");
}
+
+#[test]
+fn duration_const() {
+ // test that the methods of `Duration` are usable in a const context
+
+ const DURATION: Duration = Duration::new(0, 123_456_789);
+
+ const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis();
+ assert_eq!(SUB_SEC_MILLIS, 123);
+
+ const SUB_SEC_MICROS: u32 = DURATION.subsec_micros();
+ assert_eq!(SUB_SEC_MICROS, 123_456);
+
+ const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos();
+ assert_eq!(SUB_SEC_NANOS, 123_456_789);
+
+ const ZERO: Duration = Duration::zero();
+ assert_eq!(ZERO, Duration::new(0, 0));
+
+ const IS_ZERO: bool = ZERO.is_zero();
+ assert!(IS_ZERO);
+
+ const ONE: Duration = Duration::new(1, 0);
+
+ const SECONDS: u64 = ONE.as_secs();
+ assert_eq!(SECONDS, 1);
+
+ const FROM_SECONDS: Duration = Duration::from_secs(1);
+ assert_eq!(FROM_SECONDS, ONE);
+
+ const SECONDS_F32: f32 = ONE.as_secs_f32();
+ assert_eq!(SECONDS_F32, 1.0);
+
+ const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
+ assert_eq!(FROM_SECONDS_F32, ONE);
+
+ const SECONDS_F64: f64 = ONE.as_secs_f64();
+ assert_eq!(SECONDS_F64, 1.0);
+
+ const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
+ assert_eq!(FROM_SECONDS_F64, ONE);
+
+ const MILLIS: u128 = ONE.as_millis();
+ assert_eq!(MILLIS, 1_000);
+
+ const FROM_MILLIS: Duration = Duration::from_millis(1_000);
+ assert_eq!(FROM_MILLIS, ONE);
+
+ const MICROS: u128 = ONE.as_micros();
+ assert_eq!(MICROS, 1_000_000);
+
+ const FROM_MICROS: Duration = Duration::from_micros(1_000_000);
+ assert_eq!(FROM_MICROS, ONE);
+
+ const NANOS: u128 = ONE.as_nanos();
+ assert_eq!(NANOS, 1_000_000_000);
+
+ const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
+ assert_eq!(FROM_NANOS, ONE);
+
+ const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
+
+ const CHECKED_ADD: Option<Duration> = MAX.checked_add(ONE);
+ assert_eq!(CHECKED_ADD, None);
+
+ const CHECKED_SUB: Option<Duration> = ZERO.checked_sub(ONE);
+ assert_eq!(CHECKED_SUB, None);
+
+ const CHECKED_MUL: Option<Duration> = ONE.checked_mul(1);
+ assert_eq!(CHECKED_MUL, Some(ONE));
+
+ const MUL_F32: Duration = ONE.mul_f32(1.0);
+ assert_eq!(MUL_F32, ONE);
+
+ const MUL_F64: Duration = ONE.mul_f64(1.0);
+ assert_eq!(MUL_F64, ONE);
+
+ const CHECKED_DIV: Option<Duration> = ONE.checked_div(1);
+ assert_eq!(CHECKED_DIV, Some(ONE));
+
+ const DIV_F32: Duration = ONE.div_f32(1.0);
+ assert_eq!(DIV_F32, ONE);
+
+ const DIV_F64: Duration = ONE.div_f64(1.0);
+ assert_eq!(DIV_F64, ONE);
+
+ const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE);
+ assert_eq!(DIV_DURATION_F32, 1.0);
+
+ const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE);
+ assert_eq!(DIV_DURATION_F64, 1.0);
+
+ const SATURATING_ADD: Duration = MAX.saturating_add(ONE);
+ assert_eq!(SATURATING_ADD, MAX);
+
+ const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE);
+ assert_eq!(SATURATING_SUB, ZERO);
+
+ const SATURATING_MUL: Duration = MAX.saturating_mul(2);
+ assert_eq!(SATURATING_MUL, MAX);
+}
//! [`Read`]: io::Read
#![stable(feature = "process", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
mod tests;
#[inline]
unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
+ // SAFETY: Read is guaranteed to work on uninitialized memory
+ unsafe { Initializer::nop() }
}
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
+ // SAFETY: Read is guaranteed to work on uninitialized memory
+ unsafe { Initializer::nop() }
}
}
+++ /dev/null
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
-use crate::path::{Path, PathBuf};
-use crate::sys::time::SystemTime;
-use crate::sys::{unsupported, Void};
-
-pub struct File(Void);
-
-pub struct FileAttr(Void);
-
-pub struct ReadDir(Void);
-
-pub struct DirEntry(Void);
-
-#[derive(Clone, Debug)]
-pub struct OpenOptions {}
-
-pub struct FilePermissions(Void);
-
-pub struct FileType(Void);
-
-#[derive(Debug)]
-pub struct DirBuilder {}
-
-impl FileAttr {
- pub fn size(&self) -> u64 {
- match self.0 {}
- }
-
- pub fn perm(&self) -> FilePermissions {
- match self.0 {}
- }
-
- pub fn file_type(&self) -> FileType {
- match self.0 {}
- }
-
- pub fn modified(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-
- pub fn accessed(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-
- pub fn created(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-}
-
-impl Clone for FileAttr {
- fn clone(&self) -> FileAttr {
- match self.0 {}
- }
-}
-
-impl FilePermissions {
- pub fn readonly(&self) -> bool {
- match self.0 {}
- }
-
- pub fn set_readonly(&mut self, _readonly: bool) {
- match self.0 {}
- }
-}
-
-impl Clone for FilePermissions {
- fn clone(&self) -> FilePermissions {
- match self.0 {}
- }
-}
-
-impl PartialEq for FilePermissions {
- fn eq(&self, _other: &FilePermissions) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for FilePermissions {}
-
-impl fmt::Debug for FilePermissions {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl FileType {
- pub fn is_dir(&self) -> bool {
- match self.0 {}
- }
-
- pub fn is_file(&self) -> bool {
- match self.0 {}
- }
-
- pub fn is_symlink(&self) -> bool {
- match self.0 {}
- }
-}
-
-impl Clone for FileType {
- fn clone(&self) -> FileType {
- match self.0 {}
- }
-}
-
-impl Copy for FileType {}
-
-impl PartialEq for FileType {
- fn eq(&self, _other: &FileType) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for FileType {}
-
-impl Hash for FileType {
- fn hash<H: Hasher>(&self, _h: &mut H) {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for FileType {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for ReadDir {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl Iterator for ReadDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- match self.0 {}
- }
-}
-
-impl DirEntry {
- pub fn path(&self) -> PathBuf {
- match self.0 {}
- }
-
- pub fn file_name(&self) -> OsString {
- match self.0 {}
- }
-
- pub fn metadata(&self) -> io::Result<FileAttr> {
- match self.0 {}
- }
-
- pub fn file_type(&self) -> io::Result<FileType> {
- match self.0 {}
- }
-}
-
-impl OpenOptions {
- pub fn new() -> OpenOptions {
- OpenOptions {}
- }
-
- pub fn read(&mut self, _read: bool) {}
- pub fn write(&mut self, _write: bool) {}
- pub fn append(&mut self, _append: bool) {}
- pub fn truncate(&mut self, _truncate: bool) {}
- pub fn create(&mut self, _create: bool) {}
- pub fn create_new(&mut self, _create_new: bool) {}
-}
-
-impl File {
- pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
- unsupported()
- }
-
- pub fn file_attr(&self) -> io::Result<FileAttr> {
- match self.0 {}
- }
-
- pub fn fsync(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn datasync(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn truncate(&self, _size: u64) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn flush(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
- match self.0 {}
- }
-
- pub fn duplicate(&self) -> io::Result<File> {
- match self.0 {}
- }
-
- pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-impl DirBuilder {
- pub fn new() -> DirBuilder {
- DirBuilder {}
- }
-
- pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
- unsupported()
- }
-}
-
-impl fmt::Debug for File {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
- unsupported()
-}
-
-pub fn unlink(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
- match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
- unsupported()
-}
+++ /dev/null
-use crate::mem;
-
-#[derive(Copy, Clone)]
-pub struct IoSlice<'a>(&'a [u8]);
-
-impl<'a> IoSlice<'a> {
- #[inline]
- pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
- IoSlice(buf)
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- self.0 = &self.0[n..]
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- self.0
- }
-}
-
-pub struct IoSliceMut<'a>(&'a mut [u8]);
-
-impl<'a> IoSliceMut<'a> {
- #[inline]
- pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
- IoSliceMut(buf)
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- let slice = mem::replace(&mut self.0, &mut []);
- let (_, remaining) = slice.split_at_mut(n);
- self.0 = remaining;
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- self.0
- }
-
- #[inline]
- pub fn as_mut_slice(&mut self) -> &mut [u8] {
- self.0
- }
-}
pub mod env;
pub mod ext;
pub mod fd;
+#[path = "../unsupported/fs.rs"]
pub mod fs;
+#[path = "../unsupported/io.rs"]
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
+#[path = "../unsupported/pipe.rs"]
pub mod pipe;
+#[path = "../unsupported/process.rs"]
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
+++ /dev/null
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
- match p1.0 {}
-}
+++ /dev/null
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
- env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
- pub stdin: Option<AnonPipe>,
- pub stdout: Option<AnonPipe>,
- pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
- Inherit,
- Null,
- MakePipe,
-}
-
-impl Command {
- pub fn new(_program: &OsStr) -> Command {
- Command { env: Default::default() }
- }
-
- pub fn arg(&mut self, _arg: &OsStr) {}
-
- pub fn env_mut(&mut self) -> &mut CommandEnv {
- &mut self.env
- }
-
- pub fn cwd(&mut self, _dir: &OsStr) {}
-
- pub fn stdin(&mut self, _stdin: Stdio) {}
-
- pub fn stdout(&mut self, _stdout: Stdio) {}
-
- pub fn stderr(&mut self, _stderr: Stdio) {}
-
- pub fn spawn(
- &mut self,
- _default: Stdio,
- _needs_stdin: bool,
- ) -> io::Result<(Process, StdioPipes)> {
- unsupported()
- }
-}
-
-impl From<AnonPipe> for Stdio {
- fn from(pipe: AnonPipe) -> Stdio {
- pipe.diverge()
- }
-}
-
-impl From<File> for Stdio {
- fn from(file: File) -> Stdio {
- file.diverge()
- }
-}
-
-impl fmt::Debug for Command {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
- }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
- pub fn success(&self) -> bool {
- match self.0 {}
- }
-
- pub fn code(&self) -> Option<i32> {
- match self.0 {}
- }
-}
-
-impl Clone for ExitStatus {
- fn clone(&self) -> ExitStatus {
- match self.0 {}
- }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
- fn eq(&self, _other: &ExitStatus) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Display for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
- pub const SUCCESS: ExitCode = ExitCode(false);
- pub const FAILURE: ExitCode = ExitCode(true);
-
- pub fn as_i32(&self) -> i32 {
- self.0 as i32
- }
-}
-
-pub struct Process(Void);
-
-impl Process {
- pub fn id(&self) -> u32 {
- match self.0 {}
- }
-
- pub fn kill(&mut self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn wait(&mut self) -> io::Result<ExitStatus> {
- match self.0 {}
- }
-
- pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
- match self.0 {}
- }
-}
}
}
-#[cfg(any(
- target_os = "android",
- target_os = "illumos",
- 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 = "illumos",
- target_os = "redox",
- target_os = "solaris"
-)))]
-#[inline]
-unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
- let mut out = ptr::null_mut();
- // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
- // Since these are all powers of 2, we can just use max.
- let align = layout.align().max(crate::mem::size_of::<usize>());
- let ret = libc::posix_memalign(&mut out, align, layout.size());
- if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+cfg_if::cfg_if! {
+ if #[cfg(any(
+ target_os = "android",
+ target_os = "illumos",
+ 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
+ }
+ } else if #[cfg(target_os = "wasi")] {
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ libc::aligned_alloc(layout.align(), layout.size()) as *mut u8
+ }
+ } else {
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ let mut out = ptr::null_mut();
+ // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
+ // Since these are all powers of 2, we can just use max.
+ let align = layout.align().max(crate::mem::size_of::<usize>());
+ let ret = libc::posix_memalign(&mut out, align, layout.size());
+ if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+ }
+ }
}
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
match self.0 {}
}
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
}
impl DirBuilder {
pub mod mutex;
pub mod net;
pub mod os;
+#[path = "../unix/path.rs"]
pub mod path;
pub mod pipe;
pub mod process;
+++ /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 = '/';
}
impl From<File> for Stdio {
- fn from(file: File) -> Stdio {
- file.diverge()
+ fn from(_file: File) -> Stdio {
+ panic!("unsupported")
}
}
+++ /dev/null
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::alloc::{GlobalAlloc, Layout, System};
-use crate::ptr;
-use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-
-// SAFETY: All methods implemented follow the contract rules defined
-// in `GlobalAlloc`.
-#[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() {
- // SAFETY: `libc::malloc` is guaranteed to be safe, it will allocate
- // `layout.size()` bytes of memory and return a pointer to it
- unsafe { libc::malloc(layout.size()) as *mut u8 }
- } else {
- // SAFETY: `libc::aligned_alloc` is guaranteed to be safe if
- // `layout.size()` is a multiple of `layout.align()`. This
- // constraint can be satisfied if `pad_to_align` is called,
- // which creates a layout by rounding the size of this layout up
- // to a multiple of the layout's alignment
- let aligned_layout = layout.pad_to_align();
- unsafe { libc::aligned_alloc(aligned_layout.align(), aligned_layout.size()) as *mut u8 }
- }
- }
-
- #[inline]
- unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
- // SAFETY: `libc::calloc` is safe as long that `layout.size() * 1`
- // would not result in integer overflow which cannot happen,
- // multiplying by one never overflows
- unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
- } else {
- // SAFETY: The safety contract for `alloc` must be upheld by the caller
- let ptr = unsafe { self.alloc(layout.clone()) };
- if !ptr.is_null() {
- // SAFETY: in the case of the `ptr` being not null
- // it will be properly aligned and a valid ptr
- // which satisfies `ptr::write_bytes` safety constrains
- unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
- }
- ptr
- }
- }
-
- #[inline]
- unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
- // SAFETY: `libc::free` is guaranteed to be safe if `ptr` is allocated
- // by this allocator or if `ptr` is NULL
- unsafe { 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 {
- // SAFETY: `libc::realloc` is safe if `ptr` is allocated by this
- // allocator or NULL
- // - If `new_size` is 0 and `ptr` is not NULL, it will act as `libc::free`
- // - If `new_size` is not 0 and `ptr` is NULL, it will act as `libc::malloc`
- // - Else, it will resize the block accordingly
- unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
- } else {
- // SAFETY: The safety contract for `realloc_fallback` must be upheld by the caller
- unsafe { realloc_fallback(self, ptr, layout, new_size) }
- }
- }
-}
use crate::io as std_io;
use crate::mem;
+#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
#[path = "../unsupported/cmath.rs"]
pub mod os;
pub use crate::sys_common::os_str_bytes as os_str;
pub mod ext;
+#[path = "../unix/path.rs"]
pub mod path;
+#[path = "../unsupported/pipe.rs"]
pub mod pipe;
+#[path = "../unsupported/process.rs"]
pub mod process;
#[path = "../unsupported/rwlock.rs"]
pub mod rwlock;
+++ /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
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
- match p1.0 {}
-}
+++ /dev/null
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
- env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
- pub stdin: Option<AnonPipe>,
- pub stdout: Option<AnonPipe>,
- pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
- Inherit,
- Null,
- MakePipe,
-}
-
-impl Command {
- pub fn new(_program: &OsStr) -> Command {
- Command { env: Default::default() }
- }
-
- pub fn arg(&mut self, _arg: &OsStr) {}
-
- pub fn env_mut(&mut self) -> &mut CommandEnv {
- &mut self.env
- }
-
- pub fn cwd(&mut self, _dir: &OsStr) {}
-
- pub fn stdin(&mut self, _stdin: Stdio) {}
-
- pub fn stdout(&mut self, _stdout: Stdio) {}
-
- pub fn stderr(&mut self, _stderr: Stdio) {}
-
- pub fn spawn(
- &mut self,
- _default: Stdio,
- _needs_stdin: bool,
- ) -> io::Result<(Process, StdioPipes)> {
- unsupported()
- }
-}
-
-impl From<AnonPipe> for Stdio {
- fn from(pipe: AnonPipe) -> Stdio {
- pipe.diverge()
- }
-}
-
-impl From<File> for Stdio {
- fn from(_file: File) -> Stdio {
- panic!("unsupported")
- }
-}
-
-impl fmt::Debug for Command {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
- }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
- pub fn success(&self) -> bool {
- match self.0 {}
- }
-
- pub fn code(&self) -> Option<i32> {
- match self.0 {}
- }
-}
-
-impl Clone for ExitStatus {
- fn clone(&self) -> ExitStatus {
- match self.0 {}
- }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
- fn eq(&self, _other: &ExitStatus) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Display for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
- pub const SUCCESS: ExitCode = ExitCode(false);
- pub const FAILURE: ExitCode = ExitCode(true);
-
- pub fn as_i32(&self) -> i32 {
- self.0 as i32
- }
-}
-
-pub struct Process(Void);
-
-impl Process {
- pub fn id(&self) -> u32 {
- match self.0 {}
- }
-
- pub fn kill(&mut self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn wait(&mut self) -> io::Result<ExitStatus> {
- match self.0 {}
- }
-
- pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
- match self.0 {}
- }
-}
pub mod net;
#[path = "../unsupported/os.rs"]
pub mod os;
-#[path = "../unsupported/path.rs"]
+#[path = "../unix/path.rs"]
pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
// thread_local's, or it is being recursively initialized.
//
// Macos: Inlining this function can cause two `tlv_get_addr` calls to
- // be performed for every call to `Key::get`. The #[cold] hint makes
- // that less likely.
+ // be performed for every call to `Key::get`.
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
- #[cold]
+ #[inline(never)]
unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
if !mem::needs_drop::<T>() || self.try_register_dtor() {
Some(self.inner.initialize(init))
-Subproject commit 78891cdf292c23278ca8723bd543100249159604
+Subproject commit 718175b34a39e4e3d59b40e35930326edc515b87
```
# build the whole compiler
- ./x.py build
+ ./x.py build --stage 2
# build the stage1 compiler
- ./x.py build --stage 1
+ ./x.py build
# build stage0 libstd
./x.py build --stage 0 library/std
that belong to stage n or earlier:
```
- # keep old build products for stage 0 and build stage 1
- ./x.py build --keep-stage 0 --stage 1
+ # build stage 1, keeping old build products for stage 0
+ ./x.py build --keep-stage 0
```
* `test` - a command for executing unit tests. Like the `build` command this
## Incremental builds
-You can configure rustbuild to use incremental compilation. Because
-incremental is new and evolving rapidly, if you want to use it, it is
-recommended that you replace the snapshot with a locally installed
-nightly build of rustc. You will want to keep this up to date.
-
-To follow this course of action, first thing you will want to do is to
-install a nightly, presumably using `rustup`. You will then want to
-configure your directory to use this build, like so:
-
-```sh
-# configure to use local rust instead of downloading a beta.
-# `--local-rust-root` is optional here. If elided, we will
-# use whatever rustc we find on your PATH.
-$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
-```
-
-After that, you can use the `--incremental` flag to actually do
-incremental builds:
+You can configure rustbuild to use incremental compilation with the
+`--incremental` flag:
```sh
$ ./x.py build --incremental
in `build/<host>/stage0-incremental`. Note that we only use incremental
compilation for the stage0 -> stage1 compilation -- this is because
the stage1 compiler is changing, and we don't try to cache and reuse
-incremental artifacts across different versions of the compiler. For
-this reason, `--incremental` defaults to `--stage 1` (though you can
-manually select a higher stage, if you prefer).
+incremental artifacts across different versions of the compiler.
You can always drop the `--incremental` to build as normal (but you
will still be using the local nightly as your bootstrap).
`Config` struct.
* Adding a sanity check? Take a look at `bootstrap/sanity.rs`.
-If you have any questions feel free to reach out on `#infra` channel in the
-[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When
+If you have any questions feel free to reach out on the `#t-infra` channel in
+the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When
you encounter bugs, please file issues on the rust-lang/rust issue tracker.
-[rust-discord]: https://discord.gg/rust-lang
+[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra
}
fn new_internal(build: &Build, kind: Kind, paths: Vec<PathBuf>) -> Builder<'_> {
- let top_stage = if let Some(explicit_stage) = build.config.stage {
- explicit_stage
- } else {
- // See https://github.com/rust-lang/compiler-team/issues/326
- match kind {
- Kind::Doc => 0,
- Kind::Build | Kind::Test => 1,
- Kind::Bench | Kind::Dist | Kind::Install => 2,
- // These are all bootstrap tools, which don't depend on the compiler.
- // The stage we pass shouldn't matter, but use 0 just in case.
- Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0,
- }
- };
-
Builder {
build,
- top_stage,
+ top_stage: build.config.stage,
kind,
cache: Cache::new(),
stack: RefCell::new(Vec::new()),
Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(),
};
- let this = Self::new_internal(build, kind, paths.to_owned());
-
- // CI should always run stage 2 builds, unless it specifically states otherwise
- #[cfg(not(test))]
- if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None {
- match kind {
- Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => {
- assert_eq!(this.top_stage, 2)
- }
- Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {}
- }
- }
-
- this
+ Self::new_internal(build, kind, paths.to_owned())
}
pub fn execute_cli(&self) {
/// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
/// library lookup path.
- pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) {
+ pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
// Windows doesn't need dylib path munging because the dlls for the
// compiler live next to the compiler and the system will find them
// automatically.
return;
}
- add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command);
+ add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
}
/// Gets a path to the compiler specified.
cargo.env(format!("CC_{}", target.triple), &cc);
let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
- cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone());
+ cargo.env(format!("CFLAGS_{}", target.triple), &cflags);
if let Some(ar) = self.ar(target) {
let ranlib = format!("{} s", ar.display());
(out, dur - deps)
};
- if self.config.print_step_timings {
+ if self.config.print_step_timings && !self.config.dry_run {
println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis());
}
self.command.env(key.as_ref(), value.as_ref());
self
}
+
+ pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
+ builder.add_rustc_lib_path(compiler, &mut self.command);
+ }
}
impl From<Cargo> for Command {
use crate::config::{Config, TargetSelection};
use std::thread;
-fn configure(host: &[&str], target: &[&str]) -> Config {
- let mut config = Config::default_opts();
+fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
+ let mut config = Config::parse(&[cmd.to_owned()]);
// don't save toolstates
config.save_toolstates = None;
config.skip_only_host_steps = false;
#[test]
fn build_default() {
- let build = Build::new(configure(&[], &[]));
+ let build = Build::new(configure("build", &[], &[]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
#[test]
fn build_stage_0() {
- let config = Config { stage: Some(0), ..configure(&[], &[]) };
+ let config = Config { stage: 0, ..configure("build", &[], &[]) };
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
#[test]
fn doc_default() {
- let mut config = configure(&[], &[]);
+ let mut config = configure("doc", &[], &[]);
config.compiler_docs = true;
config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
let build = Build::new(config);
use pretty_assertions::assert_eq;
fn configure(host: &[&str], target: &[&str]) -> Config {
- Config { stage: Some(2), ..super::configure(host, target) }
+ Config { stage: 2, ..super::configure("dist", host, target) }
}
#[test]
#[test]
fn test_with_no_doc_stage0() {
let mut config = configure(&[], &[]);
- config.stage = Some(0);
+ config.stage = 0;
config.cmd = Subcommand::Test {
paths: vec!["library/std".into()],
test_args: vec![],
use std::fmt;
use std::fs;
use std::path::{Path, PathBuf};
-use std::process;
use crate::cache::{Interned, INTERNER};
use crate::flags::Flags;
pub skip_only_host_steps: bool,
pub on_fail: Option<String>,
- pub stage: Option<u32>,
+ pub stage: u32,
pub keep_stage: Vec<u32>,
pub src: PathBuf,
pub jobs: Option<u32>,
configure_args: Option<Vec<String>>,
local_rebuild: Option<bool>,
print_step_timings: Option<bool>,
+ doc_stage: Option<u32>,
+ build_stage: Option<u32>,
+ test_stage: Option<u32>,
+ install_stage: Option<u32>,
+ dist_stage: Option<u32>,
+ bench_stage: Option<u32>,
}
/// TOML representation of various global install decisions.
pub fn parse(args: &[String]) -> Config {
let flags = Flags::parse(&args);
- let file = flags.config.clone();
+
let mut config = Config::default_opts();
config.exclude = flags.exclude;
config.rustc_error_format = flags.rustc_error_format;
config.json_output = flags.json_output;
config.on_fail = flags.on_fail;
- config.stage = flags.stage;
config.jobs = flags.jobs.map(threads_from_config);
config.cmd = flags.cmd;
config.incremental = flags.incremental;
config.out = dir;
}
- let toml = file
+ #[cfg(test)]
+ let toml = TomlConfig::default();
+ #[cfg(not(test))]
+ let toml = flags
+ .config
.map(|file| {
+ use std::process;
+
let contents = t!(fs::read_to_string(&file));
match toml::from_str(&contents) {
Ok(table) => table,
})
.unwrap_or_else(TomlConfig::default);
- let build = toml.build.clone().unwrap_or_default();
+ let build = toml.build.unwrap_or_default();
// If --target was specified but --host wasn't specified, don't run any host-only tests.
let has_hosts = build.host.is_some() || flags.host.is_some();
let has_targets = build.target.is_some() || flags.target.is_some();
config.skip_only_host_steps = !has_hosts && has_targets;
- config.hosts = if let Some(arg_host) = flags.host.clone() {
+ config.hosts = if let Some(arg_host) = flags.host {
arg_host
} else if let Some(file_host) = build.host {
file_host.iter().map(|h| TargetSelection::from_user(h)).collect()
} else {
vec![config.build]
};
- config.targets = if let Some(arg_target) = flags.target.clone() {
+ config.targets = if let Some(arg_target) = flags.target {
arg_target
} else if let Some(file_target) = build.target {
file_target.iter().map(|h| TargetSelection::from_user(h)).collect()
set(&mut config.configure_args, build.configure_args);
set(&mut config.local_rebuild, build.local_rebuild);
set(&mut config.print_step_timings, build.print_step_timings);
+
+ // See https://github.com/rust-lang/compiler-team/issues/326
+ config.stage = match config.cmd {
+ Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0),
+ Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1),
+ Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1),
+ Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2),
+ Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2),
+ Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2),
+ // These are all bootstrap tools, which don't depend on the compiler.
+ // The stage we pass shouldn't matter, but use 0 just in case.
+ Subcommand::Clean { .. }
+ | Subcommand::Check { .. }
+ | Subcommand::Clippy { .. }
+ | Subcommand::Fix { .. }
+ | Subcommand::Run { .. }
+ | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
+ };
+
+ // CI should always run stage 2 builds, unless it specifically states otherwise
+ #[cfg(not(test))]
+ if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
+ match config.cmd {
+ Subcommand::Test { .. }
+ | Subcommand::Doc { .. }
+ | Subcommand::Build { .. }
+ | Subcommand::Bench { .. }
+ | Subcommand::Dist { .. }
+ | Subcommand::Install { .. } => assert_eq!(config.stage, 2),
+ Subcommand::Clean { .. }
+ | Subcommand::Check { .. }
+ | Subcommand::Clippy { .. }
+ | Subcommand::Fix { .. }
+ | Subcommand::Run { .. }
+ | Subcommand::Format { .. } => {}
+ }
+ }
+
config.verbose = cmp::max(config.verbose, flags.verbose);
- if let Some(ref install) = toml.install {
- config.prefix = install.prefix.clone().map(PathBuf::from);
- config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from);
- config.datadir = install.datadir.clone().map(PathBuf::from);
- config.docdir = install.docdir.clone().map(PathBuf::from);
- set(&mut config.bindir, install.bindir.clone().map(PathBuf::from));
- config.libdir = install.libdir.clone().map(PathBuf::from);
- config.mandir = install.mandir.clone().map(PathBuf::from);
+ if let Some(install) = toml.install {
+ config.prefix = install.prefix.map(PathBuf::from);
+ config.sysconfdir = install.sysconfdir.map(PathBuf::from);
+ config.datadir = install.datadir.map(PathBuf::from);
+ config.docdir = install.docdir.map(PathBuf::from);
+ set(&mut config.bindir, install.bindir.map(PathBuf::from));
+ config.libdir = install.libdir.map(PathBuf::from);
+ config.mandir = install.mandir.map(PathBuf::from);
}
// We want the llvm-skip-rebuild flag to take precedence over the
let mut optimize = None;
let mut ignore_git = None;
- if let Some(ref llvm) = toml.llvm {
+ if let Some(llvm) = toml.llvm {
match llvm.ccache {
Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()),
Some(StringOrBool::Bool(true)) => {
}
}
- if let Some(ref rust) = toml.rust {
+ if let Some(rust) = toml.rust {
debug = rust.debug;
debug_assertions = rust.debug_assertions;
debug_assertions_std = rust.debug_assertions_std;
set(&mut config.test_compare_mode, rust.test_compare_mode);
set(&mut config.llvm_libunwind, rust.llvm_libunwind);
set(&mut config.backtrace, rust.backtrace);
- set(&mut config.channel, rust.channel.clone());
+ set(&mut config.channel, rust.channel);
set(&mut config.rust_dist_src, rust.dist_src);
set(&mut config.verbose_tests, rust.verbose_tests);
// in the case "false" is set explicitly, do not overwrite the command line args
set(&mut config.lld_enabled, rust.lld);
set(&mut config.llvm_tools_enabled, rust.llvm_tools);
config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
- config.rustc_default_linker = rust.default_linker.clone();
- config.musl_root = rust.musl_root.clone().map(PathBuf::from);
- config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from);
+ config.rustc_default_linker = rust.default_linker;
+ config.musl_root = rust.musl_root.map(PathBuf::from);
+ config.save_toolstates = rust.save_toolstates.map(PathBuf::from);
set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
}
- if let Some(ref t) = toml.target {
+ if let Some(t) = toml.target {
for (triple, cfg) in t {
- let mut target = Target::from_triple(triple);
+ let mut target = Target::from_triple(&triple);
if let Some(ref s) = cfg.llvm_config {
target.llvm_config = Some(config.src.join(s));
if let Some(s) = cfg.no_std {
target.no_std = s;
}
- target.cc = cfg.cc.clone().map(PathBuf::from);
- target.cxx = cfg.cxx.clone().map(PathBuf::from);
- target.ar = cfg.ar.clone().map(PathBuf::from);
- target.ranlib = cfg.ranlib.clone().map(PathBuf::from);
- target.linker = cfg.linker.clone().map(PathBuf::from);
+ target.cc = cfg.cc.map(PathBuf::from);
+ target.cxx = cfg.cxx.map(PathBuf::from);
+ target.ar = cfg.ar.map(PathBuf::from);
+ target.ranlib = cfg.ranlib.map(PathBuf::from);
+ target.linker = cfg.linker.map(PathBuf::from);
target.crt_static = cfg.crt_static;
- target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
- target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from);
- target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from);
- target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);
+ target.musl_root = cfg.musl_root.map(PathBuf::from);
+ target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
+ target.wasi_root = cfg.wasi_root.map(PathBuf::from);
+ target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
- config.target_config.insert(TargetSelection::from_user(triple), target);
+ config.target_config.insert(TargetSelection::from_user(&triple), target);
}
}
build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build)));
}
- if let Some(ref t) = toml.dist {
- config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from);
- config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from);
- config.dist_upload_addr = t.upload_addr.clone();
+ if let Some(t) = toml.dist {
+ config.dist_sign_folder = t.sign_folder.map(PathBuf::from);
+ config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from);
+ config.dist_upload_addr = t.upload_addr;
set(&mut config.rust_dist_src, t.src_tarball);
set(&mut config.missing_tools, t.missing_tools);
}
if builder.config.verbose() {
cmd.arg("--verbose");
}
+ // If the lib directories are in an unusual location (changed in
+ // config.toml), then this needs to explicitly update the dylib search
+ // path.
+ builder.add_rustc_lib_path(self.compiler, &mut cmd);
builder.run(&mut cmd);
// Run rustbook/mdbook to generate the HTML pages.
builder.ensure(RustbookSrc {
eprintln!("./x.py fmt is not supported on this channel");
std::process::exit(1);
});
- let src = build.src.clone();
- let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel();
+ let src = &build.src;
+ let walker = WalkBuilder::new(src).types(matcher).overrides(ignore_fmt).build_parallel();
walker.run(|| {
- let src = src.clone();
- let rustfmt_path = rustfmt_path.clone();
Box::new(move |entry| {
let entry = t!(entry);
if entry.file_type().map_or(false, |t| t.is_file()) {
- rustfmt(&src, &rustfmt_path, &entry.path(), check);
+ rustfmt(src, &rustfmt_path, &entry.path(), check);
}
ignore::WalkState::Continue
})
Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
}
- pub fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
- let cmd: OsString = cmd.as_ref().into();
+ pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
+ let cmd: OsString = cmd.into();
let path = &self.path;
self.cache
.entry(cmd.clone())
&[],
);
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
cargo.arg("--").args(builder.config.cmd.test_args());
if try_run(builder, &mut cargo.into()) {
t!(fs::create_dir_all(&dir));
cargo.env("RUSTFMT_TEST_DIR", dir);
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
if try_run(builder, &mut cargo.into()) {
builder.save_toolstate("rustfmt", ToolState::TestPass);
cargo.arg("--").args(builder.config.cmd.test_args());
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
if !try_run(builder, &mut cargo.into()) {
return;
cargo.arg("--").args(builder.config.cmd.test_args());
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
builder.run(&mut cargo.into());
}
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
-
-cd git-2.10.0
-make configure
-hide_output ./configure --prefix=/rustroot
-hide_output make -j10
-hide_output make install
-
-cd ..
-rm -rf git-2.10.0
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x
-
-cd linux-3.2.84
-hide_output make mrproper
-hide_output make INSTALL_HDR_PATH=dest headers_install
-
-find dest/include \( -name .install -o -name ..install.cmd \) -delete
-yes | cp -fr dest/include/* /usr/include
-
-cd ..
-rm -rf linux-3.2.84
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \
- tar xzf -
-
-cd perl-5.28.0
-
-# Gotta do some hackery to tell python about our custom OpenSSL build, but other
-# than that fairly normal.
-CC=gcc \
-CFLAGS='-I /rustroot/include -fgnu89-inline' \
-LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
- hide_output ./configure.gnu
-hide_output make -j10
-hide_output make install
-
-cd ..
-rm -rf perl-5.28.0
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- # TODO: remove the condition on RUST_CI_TEMP_SKIP_CANCEL_OUTDATED once
- # we remove the `auto-fallible` job.
- if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED
+ if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
<<: *step
- name: collect CPU statistics
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
<<: *job-linux-xl
+ ####################
+ # macOS Builders #
+ ####################
+
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ <<: *job-macos-xl
+
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ - name: x86_64-apple
+ env:
+ SCRIPT: ./x.py --stage 2 test
+ RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ ####################
+ # macOS Builders #
+ ####################
+
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ <<: *job-macos-xl
+
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ - name: x86_64-apple
+ env:
+ SCRIPT: ./x.py --stage 2 test
+ RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
######################
# Windows Builders #
######################
- name: aarch64-gnu
<<: *job-aarch64-linux
- ####################
- # macOS Builders #
- ####################
-
- - name: dist-x86_64-apple
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
-
- # TODO: remove once we move this job away from auto-fallible.
- # Also, remove the variable from the cancel-outdated-builds step
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- <<: *job-macos-xl
-
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
-
- # TODO: remove once we move this job away from auto-fallible.
- # Also, remove the variable from the cancel-outdated-builds step
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- <<: *job-macos-xl
-
- - name: x86_64-apple
- env:
- SCRIPT: ./x.py --stage 2 test
- RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
-
- # TODO: remove once we move this job away from auto-fallible.
- # Also, remove the variable from the cancel-outdated-builds step
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- <<: *job-macos-xl
-
master:
name: master
runs-on: ubuntu-latest
`powerpc64-unknown-linux-musl` | ? | |
`powerpc64-wrs-vxworks` | ? | |
`powerpc64le-unknown-linux-musl` | ? | |
+`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
`sparc64-unknown-openbsd` | ? | |
If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
+## Memory address operands
+
+Sometimes assembly instructions require operands passed via memory addresses/memory locations.
+You have to manually use the memory address syntax specified by the respectively architectures.
+For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]`
+to indicate they are memory operands:
+
+```rust,allow_fail
+# #![feature(asm, llvm_asm)]
+# fn load_fpu_control_word(control: u16) {
+unsafe {
+ asm!("fldcw [{}]", in(reg) &control, options(nostack));
+
+ // Previously this would have been written with the deprecated `llvm_asm!` like this
+ llvm_asm!("fldcw $0" :: "m" (control) :: "volatile");
+}
+# }
+```
+
## Options
By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
Current valid options are:
-1. *volatile* - specifying this is analogous to
+1. `volatile` - specifying this is analogous to
`__asm__ __volatile__ (...)` in gcc/clang.
-2. *alignstack* - certain instructions expect the stack to be
+2. `alignstack` - certain instructions expect the stack to be
aligned a certain way (i.e. SSE) and specifying this indicates to
the compiler to insert its usual stack alignment code
-3. *intel* - use intel syntax instead of the default AT&T.
+3. `intel` - use intel syntax instead of the default AT&T.
```rust
# #![feature(llvm_asm)]
path = "lib.rs"
[dependencies]
-pulldown-cmark = { version = "0.7", default-features = false }
+pulldown-cmark = { version = "0.8", default-features = false }
minifier = "0.0.33"
rayon = { version = "0.3.0", package = "rustc-rayon" }
serde = { version = "1.0", features = ["derive"] }
let mut where_predicates =
where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
- // Type parameters and have a Sized bound by default unless removed with
+ // Type parameters have a Sized bound by default unless removed with
// ?Sized. Scan through the predicates and mark any type parameter with
// a Sized bound, removing the bounds as we find them.
//
use rustc_span::edition::Edition;
use rustc_span::Span;
use std::borrow::Cow;
-use std::cell::RefCell;
use std::collections::VecDeque;
use std::default::Default;
use std::fmt::Write;
use crate::html::highlight;
use crate::html::toc::TocBuilder;
-use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
+use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
#[cfg(test)]
mod tests;
if md.is_empty() {
return String::new();
}
- let replacer = |_: &str, s: &str| {
- if let Some(link) = links.iter().find(|link| &*link.original_text == s) {
- Some((link.href.clone(), link.new_text.clone()))
+ let mut replacer = |broken_link: BrokenLink<'_>| {
+ if let Some(link) =
+ links.iter().find(|link| &*link.original_text == broken_link.reference)
+ {
+ Some((link.href.as_str().into(), link.new_text.as_str().into()))
} else {
None
}
};
- let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer));
+ let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
let mut s = String::with_capacity(md.len() * 3 / 2);
return String::new();
}
- let replacer = |_: &str, s: &str| {
- if let Some(link) = links.iter().find(|link| &*link.original_text == s) {
- Some((link.href.clone(), link.new_text.clone()))
+ let mut replacer = |broken_link: BrokenLink<'_>| {
+ if let Some(link) =
+ links.iter().find(|link| &*link.original_text == broken_link.reference)
+ {
+ Some((link.href.as_str().into(), link.new_text.as_str().into()))
} else {
None
}
let p = Parser::new_with_broken_link_callback(
md,
Options::ENABLE_STRIKETHROUGH,
- Some(&replacer),
+ Some(&mut replacer),
);
let mut s = String::new();
}
let mut links = vec![];
- let shortcut_links = RefCell::new(vec![]);
+ let mut shortcut_links = vec![];
{
let locate = |s: &str| unsafe {
}
};
- let push = |_: &str, s: &str| {
- shortcut_links.borrow_mut().push((s.to_owned(), locate(s)));
+ let mut push = |link: BrokenLink<'_>| {
+ // FIXME: use `link.span` instead of `locate`
+ // (doing it now includes the `[]` as well as the text)
+ shortcut_links.push((link.reference.to_owned(), locate(link.reference)));
None
};
- let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push));
+ let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push));
// There's no need to thread an IdMap through to here because
// the IDs generated aren't going to be emitted anywhere.
}
}
- let mut shortcut_links = shortcut_links.into_inner();
- links.extend(shortcut_links.drain(..));
+ links.append(&mut shortcut_links);
links
}
#[macro_use]
extern crate lazy_static;
+#[macro_use]
+extern crate tracing;
+
+// N.B. these need `extern crate` even in 2018 edition
+// because they're loaded implicitly from the sysroot.
+// The reason they're loaded from the sysroot is because
+// the rustdoc artifacts aren't stored in rustc's cargo target directory.
+// So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates.
+//
+// Dependencies listed in Cargo.toml do not need `extern crate`.
extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_attr;
extern crate rustc_trait_selection;
extern crate rustc_typeck;
extern crate test as testing;
-#[macro_use]
-extern crate tracing;
use std::default::Default;
use std::env;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
-use crate::html::markdown::{find_testable_code, ErrorCodes, LangString};
+use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
use rustc_session::lint;
pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
pub(crate) found_tests: usize,
}
-impl Tests {
- pub(crate) fn new() -> Tests {
- Tests { found_tests: 0 }
- }
-}
-
impl crate::doctest::Tester for Tests {
- fn add_test(&mut self, _: String, _: LangString, _: usize) {
- self.found_tests += 1;
+ fn add_test(&mut self, _: String, config: LangString, _: usize) {
+ if config.rust && config.ignore == Ignore::None {
+ self.found_tests += 1;
+ }
}
}
}
};
- let mut tests = Tests::new();
+ let mut tests = Tests { found_tests: 0 };
find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
--- /dev/null
+// min-llvm-version: 11.0.0
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted when slicing or indexing
+// with an index from `position()` or `rposition()`.
+
+// CHECK-LABEL: @position_slice_to_no_bounds_check
+#[no_mangle]
+pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+ &s[..idx]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @position_slice_from_no_bounds_check
+#[no_mangle]
+pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+ &s[idx..]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @position_index_no_bounds_check
+#[no_mangle]
+pub fn position_index_no_bounds_check(s: &[u8]) -> u8 {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+ s[idx]
+ } else {
+ 42
+ }
+}
+// CHECK-LABEL: @rposition_slice_to_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ &s[..idx]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @rposition_slice_from_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ &s[idx..]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @rposition_index_no_bounds_check
+#[no_mangle]
+pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ s[idx]
+ } else {
+ 42
+ }
+}
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
-| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% |
+| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% |
+-------------------------------------+------------+------------+------------+------------+
-| Total | 4 | 100.0% | 2 | 50.0% |
+| Total | 4 | 100.0% | 1 | 25.0% |
+-------------------------------------+------------+------------+------------+------------+
--- /dev/null
+// check-pass
+
+// regression test for #73264
+// should only give one error
+/// docs [label][with#anchor#error]
+//~^ WARNING multiple anchors
+pub struct S;
--- /dev/null
+warning: `with#anchor#error` contains multiple anchors
+ --> $DIR/intra-link-double-anchor.rs:5:18
+ |
+LL | /// docs [label][with#anchor#error]
+ | ^^^^^^^^^^^^^^^^^ contains invalid anchor
+ |
+ = note: `#[warn(broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+
+#![deny(private_doc_tests)]
+
+mod foo {
+ /// private doc test
+ ///
+ /// ```ignore (used for testing ignored doc tests)
+ /// assert!(false);
+ /// ```
+ fn bar() {}
+}
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/cannot-infer-const-args.rs:12:5
- |
-LL | foo();
- | ^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/cannot-infer-const-args.rs:12:5
- |
-LL | foo();
- | ^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
-
-fn foo<const X: usize>() -> usize {
- 0
-}
-
-fn main() {
- foo(); //~ ERROR type annotations needed
-}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/cannot-infer-const-args.rs:12:5
+ |
+LL | foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/cannot-infer-const-args.rs:12:5
+ |
+LL | foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn foo<const X: usize>() -> usize {
+ 0
+}
+
+fn main() {
+ foo(); //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/method-chain.rs:21:33
+ |
+LL | Foo.bar().bar().bar().bar().baz();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/method-chain.rs:21:33
+ |
+LL | Foo.bar().bar().bar().bar().baz();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct Foo;
+
+impl Foo {
+ fn bar(self) -> Foo {
+ Foo
+ }
+
+ fn baz<const N: usize>(self) -> Foo {
+ println!("baz: {}", N);
+ Foo
+ }
+}
+
+fn main() {
+ Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/uninferred-consts.rs:14:9
+ |
+LL | Foo.foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/uninferred-consts.rs:14:9
+ |
+LL | Foo.foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// Test that we emit an error if we cannot properly infer a constant.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
+struct Foo;
+impl Foo {
+ fn foo<const N: usize>(self) {}
+}
+fn main() {
+ Foo.foo();
+ //~^ ERROR type annotations needed
+}
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
|
- = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: generic parameters must not be used inside of non trivial constant values
--> $DIR/issue-64494.rs:19:38
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
|
- = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error[E0119]: conflicting implementations of trait `MyTrait`:
--> $DIR/issue-64494.rs:19:1
LL | [0u8; mem::size_of::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
|
- = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: aborting due to previous error
--- /dev/null
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-76701-ty-param-in-const.rs:6:21
+ |
+LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-76701-ty-param-in-const.rs:12:37
+ |
+LL | fn const_param<const N: usize>() -> [u8; N + 1] {
+ | ^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/issue-76701-ty-param-in-const.rs:6:46
+ |
+LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+ | ^ non-trivial anonymous constants must not depend on the parameter `T`
+ |
+ = note: type parameters are currently not permitted in anonymous constants
+
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/issue-76701-ty-param-in-const.rs:12:42
+ |
+LL | fn const_param<const N: usize>() -> [u8; N + 1] {
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+ todo!()
+}
+
+fn const_param<const N: usize>() -> [u8; N + 1] {
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+ todo!()
+}
+
+fn main() {}
LL | fn t1() -> [u8; std::mem::size_of::<Self>()];
| ^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
|
- = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/self-ty-in-const-1.rs:14:41
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ non-trivial anonymous constants must not depend on the parameter `T`
|
- = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
#![cfg_attr(min, feature(min_const_generics))]
trait SliceExt<T: Clone> {
- fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>;
+ fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>;
}
impl <T: Clone> SliceExt<T> for [T] {
- fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> {
- ArrayWindows{ idx: 0, slice: &self }
+ fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N> {
+ ArrayWindowsExample{ idx: 0, slice: &self }
}
}
-struct ArrayWindows<'a, T, const N: usize> {
+struct ArrayWindowsExample<'a, T, const N: usize> {
slice: &'a [T],
idx: usize,
}
-impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+impl <'a, T: Clone, const N: usize> Iterator for ArrayWindowsExample<'a, T, N> {
type Item = [T; N];
fn next(&mut self) -> Option<Self::Item> {
// Note: this is unsound for some `T` and not meant as an example
fn main() {
let v: Vec<usize> = vec![0; 100];
- for array in v.as_slice().array_windows::<FOUR>() {
+ for array in v.as_slice().array_windows_example::<FOUR>() {
assert_eq!(array, [0, 0, 0, 0])
}
}
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/uninferred-consts.rs:14:5
- |
-LL | Foo.foo();
- | ^^^^^^^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/uninferred-consts.rs:14:5
- |
-LL | Foo.foo();
- | ^^^^^^^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-// Test that we emit an error if we cannot properly infer a constant.
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
-
-// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
-struct Foo;
-impl Foo {
- fn foo<const N: usize>(self) {}
-}
-fn main() {
- Foo.foo();
- //~^ ERROR type annotations needed
-}
+++ /dev/null
-// run-pass
-
-#![feature(const_panic)]
-#![feature(duration_consts_2)]
-#![feature(div_duration)]
-#![feature(duration_saturating_ops)]
-
-use std::time::Duration;
-
-fn duration() {
- const ZERO : Duration = Duration::new(0, 0);
- assert_eq!(ZERO, Duration::from_secs(0));
-
- const ONE : Duration = Duration::new(0, 1);
- assert_eq!(ONE, Duration::from_nanos(1));
-
- const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
-
- const MAX_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
- assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX));
-
- const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
- assert_eq!(MAX_CHECKED_ADD_ONE, None);
-
- const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
- assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO));
-
- const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
- assert_eq!(ZERO_CHECKED_SUB_ONE, None);
-
- const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
- assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE));
-
- const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
- assert_eq!(MAX_CHECKED_MUL_TWO, None);
-
- const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1);
- assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE));
-
- const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
- assert_eq!(ONE_CHECKED_DIV_ZERO, None);
-
- const MAX_AS_F32 : f32 = MAX.as_secs_f32();
- assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
-
- const MAX_AS_F64 : f64 = MAX.as_secs_f64();
- assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64);
-
- const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE);
- assert_eq!(ONE_AS_F32, 1.0_f32);
-
- const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
- assert_eq!(ONE_AS_F64, 1.0_f64);
-
- const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE);
- assert_eq!(MAX_SATURATING_ADD_ONE, MAX);
-
- const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE);
- assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO);
-
- const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2);
- assert_eq!(MAX_SATURATING_MUL_TWO, MAX);
-}
-
-fn main() {
- duration();
-}
LL | fn deref(&self) -> &Baz {
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
LL | self.as_ref()
- | ---- recursive call site
+ | ------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
--- /dev/null
+use std::ops::Deref;
+
+struct NotCopy {
+ inner: bool
+}
+
+impl NotCopy {
+ fn inner_method(&self) {}
+}
+
+struct Foo {
+ first: NotCopy,
+ second: NotCopy
+}
+
+impl Deref for Foo {
+ type Target = NotCopy;
+ fn deref(&self) -> &NotCopy {
+ &self.second
+ }
+}
+
+fn use_field(val: Foo) {
+ let _val = val.first;
+ val.inner; //~ ERROR borrow of
+}
+
+fn use_method(val: Foo) {
+ let _val = val.first;
+ val.inner_method(); //~ ERROR borrow of
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: borrow of partially moved value: `val`
+ --> $DIR/move-deref-coercion.rs:25:5
+ |
+LL | let _val = val.first;
+ | --------- value partially moved here
+LL | val.inner;
+ | ^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
+ = note: borrow occurs due to deref coercion to `NotCopy`
+note: deref defined here
+ --> $DIR/move-deref-coercion.rs:17:5
+ |
+LL | type Target = NotCopy;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0382]: borrow of partially moved value: `val`
+ --> $DIR/move-deref-coercion.rs:30:5
+ |
+LL | let _val = val.first;
+ | --------- value partially moved here
+LL | val.inner_method();
+ | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
+ = note: borrow occurs due to deref coercion to `NotCopy`
+note: deref defined here
+ --> $DIR/move-deref-coercion.rs:17:5
+ |
+LL | type Target = NotCopy;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
error[E0382]: borrow of moved value: `arc_v`
- --> $DIR/no-capture-arc.rs:14:18
+ --> $DIR/no-capture-arc.rs:14:16
|
LL | let arc_v = Arc::new(v);
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
| ----- variable moved due to use in closure
...
LL | assert_eq!((*arc_v)[2], 3);
- | ^^^^^ value borrowed here after move
+ | ^^^^^^^^ value borrowed here after move
+ |
+ = note: borrow occurs due to deref coercion to `Vec<i32>`
+note: deref defined here
+ --> $SRC_DIR/alloc/src/sync.rs:LL:COL
+ |
+LL | type Target = T;
+ | ^^^^^^^^^^^^^^^^
error: aborting due to previous error
error[E0382]: borrow of moved value: `arc_v`
- --> $DIR/no-reuse-move-arc.rs:12:18
+ --> $DIR/no-reuse-move-arc.rs:12:16
|
LL | let arc_v = Arc::new(v);
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
| ----- variable moved due to use in closure
...
LL | assert_eq!((*arc_v)[2], 3);
- | ^^^^^ value borrowed here after move
+ | ^^^^^^^^ value borrowed here after move
+ |
+ = note: borrow occurs due to deref coercion to `Vec<i32>`
+note: deref defined here
+ --> $SRC_DIR/alloc/src/sync.rs:LL:COL
+ |
+LL | type Target = T;
+ | ^^^^^^^^^^^^^^^^
error: aborting due to previous error
+++ /dev/null
-// run-pass
-
-
-pub fn main() {
- let a: isize = 10;
- println!("{}", a);
- assert_eq!(a * (a - 1), 90);
-}
+++ /dev/null
-// run-pass
-
-
-pub fn main() {
- let i32_a: isize = 10;
- assert_eq!(i32_a, 10);
- assert_eq!(i32_a - 10, 0);
- assert_eq!(i32_a / 10, 1);
- assert_eq!(i32_a - 20, -10);
- assert_eq!(i32_a << 10, 10240);
- assert_eq!(i32_a << 16, 655360);
- assert_eq!(i32_a * 16, 160);
- assert_eq!(i32_a * i32_a * i32_a, 1000);
- assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
- assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
- assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
- let i32_b: isize = 0x10101010;
- assert_eq!(i32_b + 1 - 1, i32_b);
- assert_eq!(i32_b << 1, i32_b << 1);
- assert_eq!(i32_b >> 1, i32_b >> 1);
- assert_eq!(i32_b & i32_b << 1, 0);
- println!("{}", i32_b | i32_b << 1);
- assert_eq!(i32_b | i32_b << 1, 0x30303030);
-}
+++ /dev/null
-// run-pass
-
-
-
-pub fn main() {
- let i32_c: isize = 0x10101010;
- assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
- i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3));
-}
--- /dev/null
+#![crate_type="lib"]
+fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut`
+
+macro_rules! mac {
+ ($lt:lifetime) => {
+ fn w<$lt>(w: &mut $lt i32) {}
+ //~^ ERROR lifetime must precede `mut`
+ }
+}
+
+mac!('a);
+
+// avoid false positives
+fn y<'a>(y: &mut 'a + Send) {
+ //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
+ //~| WARNING trait objects without an explicit `dyn` are deprecated
+ //~| ERROR at least one trait is required for an object type
+ let z = y as &mut 'a + Send;
+ //~^ ERROR expected value, found trait `Send`
+ //~| WARNING trait objects without an explicit `dyn` are deprecated
+}
--- /dev/null
+error: lifetime must precede `mut`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:2:13
+ |
+LL | fn x<'a>(x: &mut 'a i32){}
+ | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut`
+
+error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:14:13
+ |
+LL | fn y<'a>(y: &mut 'a + Send) {
+ | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)`
+
+error: lifetime must precede `mut`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:6:22
+ |
+LL | fn w<$lt>(w: &mut $lt i32) {}
+ | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut`
+...
+LL | mac!('a);
+ | --------- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0423]: expected value, found trait `Send`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:18:28
+ |
+LL | let z = y as &mut 'a + Send;
+ | ^^^^ not a value
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
+ |
+LL | fn y<'a>(y: &mut 'a + Send) {
+ | ^^ help: use `dyn`: `dyn 'a`
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-73568-lifetime-after-mut.rs:18:23
+ |
+LL | let z = y as &mut 'a + Send;
+ | ^^ help: use `dyn`: `dyn 'a`
+
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
+ |
+LL | fn y<'a>(y: &mut 'a + Send) {
+ | ^^
+
+error: aborting due to 5 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0178, E0224, E0423.
+For more information about an error, try `rustc --explain E0178`.
+++ /dev/null
-// run-pass
-
-pub fn main() {
- let a: String = "this \
-is a test".to_string();
- let b: String =
- "this \
- is \
- another \
- test".to_string();
- assert_eq!(a, "this is a test".to_string());
- assert_eq!(b, "this is another test".to_string());
-}
+++ /dev/null
-// run-pass
-
-fn main() {
- let x = "\\\\\
- ";
- assert_eq!(x, r"\\"); // extraneous whitespace stripped
-}
--- /dev/null
+// run-rustfix
+
+#[allow(unused)]
+use std::fmt::Debug;
+// Rustfix should add this, or use `std::fmt::Debug` instead.
+
+#[allow(dead_code)]
+struct ConstrainedStruct<X: Copy> {
+ x: X
+}
+
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
+ fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+ //~^ ERROR the trait bound `X: Copy` is not satisfied
+ ConstrainedStruct { x }
+ }
+}
+
+pub fn main() { }
--- /dev/null
+// run-rustfix
+
+#[allow(unused)]
+use std::fmt::Debug;
+// Rustfix should add this, or use `std::fmt::Debug` instead.
+
+#[allow(dead_code)]
+struct ConstrainedStruct<X: Copy> {
+ x: X
+}
+
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGeneric<X=()> {
+ fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+ //~^ ERROR the trait bound `X: Copy` is not satisfied
+ ConstrainedStruct { x }
+ }
+}
+
+pub fn main() { }
--- /dev/null
+error[E0277]: the trait bound `X: Copy` is not satisfied
+ --> $DIR/trait-impl-bound-suggestions.rs:14:52
+ |
+LL | struct ConstrainedStruct<X: Copy> {
+ | ---- required by this bound in `ConstrainedStruct`
+...
+LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X`
+ |
+help: consider further restricting type parameter `X`
+ |
+LL | trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
|
help: consider further restricting type parameter `T`
|
-LL | trait Base<T = String>: Super<T>, T: Copy { }
- | ^^^^^^^^^
+LL | trait Base<T = String>: Super<T> where T: Copy { }
+ | ^^^^^^^^^^^^^
error[E0277]: cannot add `u8` to `i32`
--> $DIR/type-check-defaults.rs:24:66
-Subproject commit 875e0123259b0b6299903fe4aea0a12ecde9324f
+Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110
None => {
let rendered: Vec<&str> =
msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+ let non_json: Vec<&str> =
+ stderr.lines().filter(|line| !line.starts_with('{')).collect();
Err(format!(
- "did not find lint `{}` in output of example, got:\n{}",
+ "did not find lint `{}` in output of example, got:\n{}\n{}",
name,
+ non_json.join("\n"),
rendered.join("\n")
)
.into())
-Subproject commit 0275b08d1521606fa733f76fe5d5707717456fb4
+Subproject commit 0d03fe6ef57d3956e92382e0e1f1a916015191cb