Auto merge of #76786 - Dylan-DPC:rollup-x6p60m6, r=Dylan-DPC
Rollup of 10 pull requests Successful merges: - #76669 (Prefer asm! over llvm_asm! in core) - #76675 (Small improvements to asm documentation) - #76681 (remove orphaned files) - #76694 (Introduce a PartitioningCx struct) - #76695 (fix syntax error in suggesting generic constraint in trait parameter) - #76699 (improve const infer error) - #76707 (Simplify iter flatten struct doc) - #76710 (⬆️ rust-analyzer) - #76714 (Small docs improvements) - #76717 (Fix generating rustc docs with non-default lib directory.) Failed merges: r? `@ghost`
This commit is contained in:
commit
7bb106fe63
@ -6,9 +6,10 @@
|
||||
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;
|
||||
@ -569,14 +570,26 @@ pub fn need_type_info_err_const(
|
||||
local_visitor.visit_expr(expr);
|
||||
}
|
||||
|
||||
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 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
|
||||
};
|
||||
|
||||
err.note("unable to infer the value of a const parameter");
|
||||
let error_code = error_code.into();
|
||||
let mut err =
|
||||
self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ pub struct ConstVariableOrigin {
|
||||
pub enum ConstVariableOriginKind {
|
||||
MiscVariable,
|
||||
ConstInference,
|
||||
// FIXME(const_generics): Consider storing the `DefId` of the param here.
|
||||
ConstParameterDefinition(Symbol),
|
||||
SubstitutionPlaceholder,
|
||||
}
|
||||
|
@ -2285,8 +2285,8 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
/// 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> {
|
||||
|
@ -66,8 +66,8 @@
|
||||
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(());
|
||||
|
@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param(
|
||||
// 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1233,13 +1233,13 @@ pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx>
|
||||
/// 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
|
||||
|
@ -11,6 +11,7 @@
|
||||
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::{
|
||||
@ -22,35 +23,36 @@
|
||||
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,
|
||||
@ -65,7 +67,7 @@ fn place_root_mono_items(
|
||||
|
||||
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,
|
||||
@ -97,17 +99,16 @@ fn place_root_mono_items(
|
||||
|
||||
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();
|
||||
@ -124,7 +125,7 @@ fn place_inlined_mono_items(
|
||||
// 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());
|
||||
@ -198,9 +199,8 @@ fn follow_inlining<'tcx>(
|
||||
|
||||
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
|
||||
@ -218,7 +218,7 @@ fn internalize_symbols(
|
||||
// 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);
|
||||
}
|
||||
|
@ -3,17 +3,16 @@
|
||||
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
|
||||
@ -32,7 +31,7 @@ pub fn merge_codegen_units<'tcx>(
|
||||
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();
|
||||
@ -56,9 +55,9 @@ pub fn merge_codegen_units<'tcx>(
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
@ -84,7 +83,7 @@ pub fn merge_codegen_units<'tcx>(
|
||||
|
||||
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
|
||||
|
@ -108,31 +108,35 @@
|
||||
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>,
|
||||
);
|
||||
}
|
||||
|
||||
@ -157,12 +161,13 @@ pub fn partition<'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));
|
||||
@ -172,7 +177,7 @@ pub fn partition<'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());
|
||||
}
|
||||
|
||||
@ -182,7 +187,7 @@ pub fn partition<'tcx>(
|
||||
// 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));
|
||||
@ -193,7 +198,7 @@ pub fn partition<'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.
|
||||
|
@ -111,7 +111,7 @@ pub fn spin_loop() {
|
||||
#[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
|
||||
@ -121,7 +121,8 @@ pub fn black_box<T>(dummy: T) -> T {
|
||||
#[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
|
||||
|
@ -7,11 +7,8 @@
|
||||
/// 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> {
|
||||
|
@ -60,12 +60,19 @@ mod fpu_precision {
|
||||
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>() {
|
||||
@ -78,7 +85,14 @@ pub fn set_precision<T>() -> FPUControlWord {
|
||||
// `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.
|
||||
|
@ -683,7 +683,7 @@ pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path {
|
||||
|
||||
/// 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.
|
||||
@ -691,7 +691,7 @@ pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) {
|
||||
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.
|
||||
@ -1488,6 +1488,10 @@ pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut
|
||||
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 {
|
||||
|
@ -766,6 +766,10 @@ fn run(self, builder: &Builder<'_>) {
|
||||
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 {
|
||||
|
@ -270,7 +270,7 @@ fn run(self, builder: &Builder<'_>) {
|
||||
&[],
|
||||
);
|
||||
|
||||
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()) {
|
||||
@ -328,7 +328,7 @@ fn run(self, builder: &Builder<'_>) {
|
||||
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);
|
||||
@ -449,7 +449,7 @@ fn run(self, builder: &Builder<'_>) {
|
||||
|
||||
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;
|
||||
@ -554,7 +554,7 @@ fn run(self, builder: &Builder<'_>) {
|
||||
|
||||
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());
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
#!/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
|
@ -1,16 +0,0 @@
|
||||
#!/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
|
@ -1,21 +0,0 @@
|
||||
#!/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
|
@ -345,6 +345,25 @@ The `h` modifier will emit the register name for the high byte of that register
|
||||
|
||||
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.
|
||||
|
@ -159,12 +159,12 @@ specify some extra info about the inline assembly:
|
||||
|
||||
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)]
|
||||
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed
|
||||
LL | foo();
|
||||
| ^^^
|
||||
|
|
||||
= note: unable to infer the value of a const parameter
|
||||
= note: cannot infer the value of the const parameter `X`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed
|
||||
LL | foo();
|
||||
| ^^^
|
||||
|
|
||||
= note: unable to infer the value of a const parameter
|
||||
= note: cannot infer the value of the const parameter `X`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
11
src/test/ui/const-generics/infer/method-chain.full.stderr
Normal file
11
src/test/ui/const-generics/infer/method-chain.full.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
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`.
|
11
src/test/ui/const-generics/infer/method-chain.min.stderr
Normal file
11
src/test/ui/const-generics/infer/method-chain.min.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
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`.
|
22
src/test/ui/const-generics/infer/method-chain.rs
Normal file
22
src/test/ui/const-generics/infer/method-chain.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/uninferred-consts.rs:14:5
|
||||
--> $DIR/uninferred-consts.rs:14:9
|
||||
|
|
||||
LL | Foo.foo();
|
||||
| ^^^^^^^^^
|
||||
| ^^^
|
||||
|
|
||||
= note: unable to infer the value of a const parameter
|
||||
= note: cannot infer the value of the const parameter `N`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/uninferred-consts.rs:14:5
|
||||
--> $DIR/uninferred-consts.rs:14:9
|
||||
|
|
||||
LL | Foo.foo();
|
||||
| ^^^^^^^^^
|
||||
| ^^^
|
||||
|
|
||||
= note: unable to infer the value of a const parameter
|
||||
= note: cannot infer the value of the const parameter `N`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
20
src/test/ui/trait-impl-bound-suggestions.fixed
Normal file
20
src/test/ui/trait-impl-bound-suggestions.fixed
Normal file
@ -0,0 +1,20 @@
|
||||
// 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() { }
|
20
src/test/ui/trait-impl-bound-suggestions.rs
Normal file
20
src/test/ui/trait-impl-bound-suggestions.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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() { }
|
17
src/test/ui/trait-impl-bound-suggestions.stderr
Normal file
17
src/test/ui/trait-impl-bound-suggestions.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
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`.
|
@ -56,8 +56,8 @@ LL | trait Base<T = String>: Super<T> { }
|
||||
|
|
||||
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
|
||||
|
@ -402,9 +402,12 @@ fn generate_lint_output(
|
||||
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())
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 0275b08d1521606fa733f76fe5d5707717456fb4
|
||||
Subproject commit 0d03fe6ef57d3956e92382e0e1f1a916015191cb
|
Loading…
Reference in New Issue
Block a user