Auto merge of #125349 - matthiaskrgr:rollup-p2mbdxi, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #124050 (Remove libc from MSVC targets)
 - #124283 (Note for E0599 if shadowed bindings has the method.)
 - #125123 (Fix `read_exact` and `read_buf_exact` for `&[u8]` and `io:Cursor`)
 - #125158 (hir pretty: fix block indent)
 - #125308 (track cycle participants per root)
 - #125332 (Update books)
 - #125333 (switch to the default implementation of `write_vectored`)
 - #125346 (Remove some `Path::to_str` from `rustc_codegen_llvm`)

Failed merges:

 - #125310 (Move ~100 tests from tests/ui to subdirs)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-05-21 00:46:30 +00:00
commit 8e7517d99a
61 changed files with 777 additions and 362 deletions

View File

@ -200,21 +200,20 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
_ => panic!("unsupported arch {}", sess.target.arch),
};
let mut dlltool_cmd = std::process::Command::new(&dlltool);
dlltool_cmd.args([
"-d",
def_file_path.to_str().unwrap(),
"-D",
lib_name,
"-l",
output_path.to_str().unwrap(),
"-m",
dlltool_target_arch,
"-f",
dlltool_target_bitness,
"--no-leading-underscore",
"--temp-prefix",
temp_prefix.to_str().unwrap(),
]);
dlltool_cmd
.arg("-d")
.arg(def_file_path)
.arg("-D")
.arg(lib_name)
.arg("-l")
.arg(&output_path)
.arg("-m")
.arg(dlltool_target_arch)
.arg("-f")
.arg(dlltool_target_bitness)
.arg("--no-leading-underscore")
.arg("--temp-prefix")
.arg(temp_prefix);
match dlltool_cmd.output() {
Err(e) => {

View File

@ -1454,7 +1454,7 @@ impl<'a> State<'a> {
self.word_space(":");
}
// containing cbox, will be closed by print-block at `}`
self.cbox(INDENT_UNIT);
self.cbox(0);
// head-box, will be closed by print-block after `{`
self.ibox(0);
self.print_block(blk);

View File

@ -1346,6 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if segment.ident.name != kw::Empty {
if let Some(err) = self.report_method_error(
span,
Some(rcvr),
rcvr_t,
segment.ident,
SelfSource::MethodCall(rcvr),

View File

@ -834,6 +834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if item_name.name != kw::Empty {
if let Some(e) = self.report_method_error(
span,
None,
ty.normalized,
item_name,
SelfSource::QPath(qself),

View File

@ -7,6 +7,7 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
use crate::Expectation;
use crate::FnCtxt;
use core::ops::ControlFlow;
use hir::Expr;
use rustc_ast::ast::Mutability;
use rustc_attr::parse_confusables;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@ -19,7 +20,6 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::PatKind::Binding;
use rustc_hir::PathSegment;
use rustc_hir::{ExprKind, Node, QPath};
use rustc_infer::infer::{self, RegionVariableOrigin};
@ -46,7 +46,7 @@ use std::borrow::Cow;
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{self, Visitor};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn report_method_error(
&self,
span: Span,
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
@ -212,6 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
MethodError::NoMatch(mut no_match_data) => {
return self.report_no_match_method_error(
span,
rcvr_opt,
rcvr_ty,
item_name,
source,
@ -356,9 +358,197 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err
}
pub fn suggest_use_shadowed_binding_with_method(
&self,
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
method_name: Ident,
ty_str_reported: &str,
err: &mut Diag<'_>,
) {
#[derive(Debug)]
struct LetStmt {
ty_hir_id_opt: Option<hir::HirId>,
binding_id: hir::HirId,
span: Span,
init_hir_id: hir::HirId,
}
// Used for finding suggest binding.
// ```rust
// earlier binding for suggesting:
// let y = vec![1, 2];
// now binding:
// if let Some(y) = x {
// y.push(y);
// }
// ```
struct LetVisitor<'a, 'tcx> {
// Error binding which don't have `method_name`.
binding_name: Symbol,
binding_id: hir::HirId,
// Used for check if the suggest binding has `method_name`.
fcx: &'a FnCtxt<'a, 'tcx>,
call_expr: &'tcx Expr<'tcx>,
method_name: Ident,
// Suggest the binding which is shallowed.
sugg_let: Option<LetStmt>,
}
impl<'a, 'tcx> LetVisitor<'a, 'tcx> {
// Check scope of binding.
fn is_sub_scope(&self, sub_id: hir::ItemLocalId, super_id: hir::ItemLocalId) -> bool {
let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_id);
if let Some(sub_var_scope) = scope_tree.var_scope(sub_id)
&& let Some(super_var_scope) = scope_tree.var_scope(super_id)
&& scope_tree.is_subscope_of(sub_var_scope, super_var_scope)
{
return true;
}
false
}
// Check if an earlier shadowed binding make `the receiver` of a MethodCall has the method.
// If it does, record the earlier binding for subsequent notes.
fn check_and_add_sugg_binding(&mut self, binding: LetStmt) -> bool {
if !self.is_sub_scope(self.binding_id.local_id, binding.binding_id.local_id) {
return false;
}
// Get the earlier shadowed binding'ty and use it to check the method.
if let Some(ty_hir_id) = binding.ty_hir_id_opt
&& let Some(tyck_ty) = self.fcx.node_ty_opt(ty_hir_id)
{
if self
.fcx
.lookup_probe_for_diagnostic(
self.method_name,
tyck_ty,
self.call_expr,
ProbeScope::TraitsInScope,
None,
)
.is_ok()
{
self.sugg_let = Some(binding);
return true;
} else {
return false;
}
}
// If the shadowed binding has an an itializer expression,
// use the initializer expression'ty to try to find the method again.
// For example like: `let mut x = Vec::new();`,
// `Vec::new()` is the itializer expression.
if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
&& self
.fcx
.lookup_probe_for_diagnostic(
self.method_name,
self_ty,
self.call_expr,
ProbeScope::TraitsInScope,
None,
)
.is_ok()
{
self.sugg_let = Some(binding);
return true;
}
return false;
}
}
impl<'v> Visitor<'v> for LetVisitor<'_, '_> {
type Result = ControlFlow<()>;
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
if let hir::StmtKind::Let(&hir::LetStmt { pat, ty, init, .. }) = ex.kind
&& let hir::PatKind::Binding(_, binding_id, binding_name, ..) = pat.kind
&& let Some(init) = init
&& binding_name.name == self.binding_name
&& binding_id != self.binding_id
{
if self.check_and_add_sugg_binding(LetStmt {
ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
binding_id: binding_id,
span: pat.span,
init_hir_id: init.hir_id,
}) {
return ControlFlow::Break(());
}
ControlFlow::Continue(())
} else {
hir::intravisit::walk_stmt(self, ex)
}
}
// Used for find the error binding.
// When the visitor reaches this point, all the shadowed bindings
// have been found, so the visitor ends.
fn visit_pat(&mut self, p: &'v hir::Pat<'v>) -> Self::Result {
match p.kind {
hir::PatKind::Binding(_, binding_id, binding_name, _) => {
if binding_name.name == self.binding_name && binding_id == self.binding_id {
return ControlFlow::Break(());
}
}
_ => {
intravisit::walk_pat(self, p);
}
}
ControlFlow::Continue(())
}
}
if let Some(rcvr) = rcvr_opt
&& let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind
&& let hir::def::Res::Local(recv_id) = path.res
&& let Some(segment) = path.segments.first()
{
let map = self.infcx.tcx.hir();
let body_id = self.tcx.hir().body_owned_by(self.body_id);
let body = map.body(body_id);
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) {
let mut let_visitor = LetVisitor {
fcx: self,
call_expr,
binding_name: segment.ident.name,
binding_id: recv_id,
method_name,
sugg_let: None,
};
let_visitor.visit_body(body);
if let Some(sugg_let) = let_visitor.sugg_let
&& let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id)
{
let _sm = self.infcx.tcx.sess.source_map();
let rcvr_name = segment.ident.name;
let mut span = MultiSpan::from_span(sugg_let.span);
span.push_span_label(sugg_let.span,
format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
span.push_span_label(
self.tcx.hir().span(recv_id),
format!(
"earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
),
);
err.span_note(
span,
format!(
"there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
that has method `{method_name}` available"
),
);
}
}
}
}
pub fn report_no_match_method_error(
&self,
mut span: Span,
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
@ -451,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
} else {
tcx.dcx().create_err(NoAssociatedItem {
let mut err = tcx.dcx().create_err(NoAssociatedItem {
span,
item_kind,
item_name,
@ -461,9 +651,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
rcvr_ty.prefix_string(self.tcx)
},
ty_str: ty_str_reported,
ty_str: ty_str_reported.clone(),
trait_missing_method,
})
});
if is_method {
self.suggest_use_shadowed_binding_with_method(
rcvr_opt,
item_name,
&ty_str_reported,
&mut err,
);
}
err
};
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
@ -2240,7 +2441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
&& let Binding(_, _, ident, ..) = pat.kind
&& let hir::PatKind::Binding(_, _, ident, ..) = pat.kind
&& ident.name == self.ident_name
{
ControlFlow::Break(init)

View File

@ -14,11 +14,11 @@ pub struct EvaluationCache<'tcx> {
map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
}
#[derive(PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
pub struct CacheData<'tcx> {
pub result: QueryResult<'tcx>,
pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
pub reached_depth: usize,
pub additional_depth: usize,
pub encountered_overflow: bool,
}
@ -29,7 +29,7 @@ impl<'tcx> EvaluationCache<'tcx> {
tcx: TyCtxt<'tcx>,
key: CanonicalInput<'tcx>,
proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
reached_depth: usize,
additional_depth: usize,
encountered_overflow: bool,
cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
dep_node: DepNodeIndex,
@ -40,17 +40,17 @@ impl<'tcx> EvaluationCache<'tcx> {
let data = WithDepNode::new(dep_node, QueryData { result, proof_tree });
entry.cycle_participants.extend(cycle_participants);
if encountered_overflow {
entry.with_overflow.insert(reached_depth, data);
entry.with_overflow.insert(additional_depth, data);
} else {
entry.success = Some(Success { data, reached_depth });
entry.success = Some(Success { data, additional_depth });
}
if cfg!(debug_assertions) {
drop(map);
if Some(CacheData { result, proof_tree, reached_depth, encountered_overflow })
!= self.get(tcx, key, |_| false, Limit(reached_depth))
{
bug!("unable to retrieve inserted element from cache: {key:?}");
let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow };
let actual = self.get(tcx, key, [], Limit(additional_depth));
if !actual.as_ref().is_some_and(|actual| expected == *actual) {
bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}");
}
}
}
@ -63,23 +63,25 @@ impl<'tcx> EvaluationCache<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
key: CanonicalInput<'tcx>,
cycle_participant_in_stack: impl FnOnce(&FxHashSet<CanonicalInput<'tcx>>) -> bool,
stack_entries: impl IntoIterator<Item = CanonicalInput<'tcx>>,
available_depth: Limit,
) -> Option<CacheData<'tcx>> {
let map = self.map.borrow();
let entry = map.get(&key)?;
if cycle_participant_in_stack(&entry.cycle_participants) {
return None;
for stack_entry in stack_entries {
if entry.cycle_participants.contains(&stack_entry) {
return None;
}
}
if let Some(ref success) = entry.success {
if available_depth.value_within_limit(success.reached_depth) {
if available_depth.value_within_limit(success.additional_depth) {
let QueryData { result, proof_tree } = success.data.get(tcx);
return Some(CacheData {
result,
proof_tree,
reached_depth: success.reached_depth,
additional_depth: success.additional_depth,
encountered_overflow: false,
});
}
@ -90,7 +92,7 @@ impl<'tcx> EvaluationCache<'tcx> {
CacheData {
result,
proof_tree,
reached_depth: available_depth.0,
additional_depth: available_depth.0,
encountered_overflow: true,
}
})
@ -99,7 +101,7 @@ impl<'tcx> EvaluationCache<'tcx> {
struct Success<'tcx> {
data: WithDepNode<QueryData<'tcx>>,
reached_depth: usize,
additional_depth: usize,
}
#[derive(Clone, Copy)]

View File

@ -47,20 +47,39 @@ struct StackEntry<I: Interner> {
/// Whether this entry is a non-root cycle participant.
///
/// We must not move the result of non-root cycle participants to the
/// global cache. See [SearchGraph::cycle_participants] for more details.
/// We store the highest stack depth of a head of a cycle this goal is involved
/// in. This necessary to soundly cache its provisional result.
/// global cache. We store the highest stack depth of a head of a cycle
/// this goal is involved in. This necessary to soundly cache its
/// provisional result.
non_root_cycle_participant: Option<StackDepth>,
encountered_overflow: bool,
has_been_used: HasBeenUsed,
/// We put only the root goal of a coinductive cycle into the global cache.
///
/// If we were to use that result when later trying to prove another cycle
/// participant, we can end up with unstable query results.
///
/// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
/// an example of where this is needed.
///
/// There can be multiple roots on the same stack, so we need to track
/// cycle participants per root:
/// ```plain
/// A :- B
/// B :- A, C
/// C :- D
/// D :- C
/// ```
cycle_participants: FxHashSet<CanonicalInput<I>>,
/// Starts out as `None` and gets set when rerunning this
/// goal in case we encounter a cycle.
provisional_result: Option<QueryResult<I>>,
}
/// The provisional result for a goal which is not on the stack.
#[derive(Debug)]
struct DetachedEntry<I: Interner> {
/// The head of the smallest non-trivial cycle involving this entry.
///
@ -110,40 +129,17 @@ pub(super) struct SearchGraph<I: Interner> {
/// An element is *deeper* in the stack if its index is *lower*.
stack: IndexVec<StackDepth, StackEntry<I>>,
provisional_cache: FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
/// We put only the root goal of a coinductive cycle into the global cache.
///
/// If we were to use that result when later trying to prove another cycle
/// participant, we can end up with unstable query results.
///
/// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
/// an example of where this is needed.
cycle_participants: FxHashSet<CanonicalInput<I>>,
}
impl<I: Interner> SearchGraph<I> {
pub(super) fn new(mode: SolverMode) -> SearchGraph<I> {
Self {
mode,
stack: Default::default(),
provisional_cache: Default::default(),
cycle_participants: Default::default(),
}
Self { mode, stack: Default::default(), provisional_cache: Default::default() }
}
pub(super) fn solver_mode(&self) -> SolverMode {
self.mode
}
/// Update the stack and reached depths on cache hits.
#[instrument(level = "trace", skip(self))]
fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
let reached_depth = self.stack.next_index().plus(additional_depth);
if let Some(last) = self.stack.raw.last_mut() {
last.reached_depth = last.reached_depth.max(reached_depth);
last.encountered_overflow |= encountered_overflow;
}
}
/// Pops the highest goal from the stack, lazily updating the
/// the next goal in the stack.
///
@ -159,13 +155,7 @@ impl<I: Interner> SearchGraph<I> {
}
pub(super) fn is_empty(&self) -> bool {
if self.stack.is_empty() {
debug_assert!(self.provisional_cache.is_empty());
debug_assert!(self.cycle_participants.is_empty());
true
} else {
false
}
self.stack.is_empty()
}
/// Returns the remaining depth allowed for nested goals.
@ -215,15 +205,26 @@ impl<I: Interner> SearchGraph<I> {
// their result does not get moved to the global cache.
fn tag_cycle_participants(
stack: &mut IndexVec<StackDepth, StackEntry<I>>,
cycle_participants: &mut FxHashSet<CanonicalInput<I>>,
usage_kind: HasBeenUsed,
head: StackDepth,
) {
stack[head].has_been_used |= usage_kind;
debug_assert!(!stack[head].has_been_used.is_empty());
for entry in &mut stack.raw[head.index() + 1..] {
// The current root of these cycles. Note that this may not be the final
// root in case a later goal depends on a goal higher up the stack.
let mut current_root = head;
while let Some(parent) = stack[current_root].non_root_cycle_participant {
current_root = parent;
debug_assert!(!stack[current_root].has_been_used.is_empty());
}
let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1);
let current_cycle_root = &mut stack[current_root.as_usize()];
for entry in cycle_participants {
entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
cycle_participants.insert(entry.input);
current_cycle_root.cycle_participants.insert(entry.input);
current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants));
}
}
@ -266,6 +267,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
&mut ProofTreeBuilder<TyCtxt<'tcx>>,
) -> QueryResult<TyCtxt<'tcx>>,
) -> QueryResult<TyCtxt<'tcx>> {
self.check_invariants();
// Check for overflow.
let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else {
if let Some(last) = self.stack.raw.last_mut() {
@ -276,37 +278,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
return Self::response_no_constraints(tcx, input, Certainty::overflow(true));
};
// Try to fetch the goal from the global cache.
'global: {
let Some(CacheData { result, proof_tree, reached_depth, encountered_overflow }) =
self.global_cache(tcx).get(
tcx,
input,
|cycle_participants| {
self.stack.iter().any(|entry| cycle_participants.contains(&entry.input))
},
available_depth,
)
else {
break 'global;
};
// If we're building a proof tree and the current cache entry does not
// contain a proof tree, we do not use the entry but instead recompute
// the goal. We simply overwrite the existing entry once we're done,
// caching the proof tree.
if !inspect.is_noop() {
if let Some(revisions) = proof_tree {
inspect.goal_evaluation_kind(
inspect::WipCanonicalGoalEvaluationKind::Interned { revisions },
);
} else {
break 'global;
}
}
self.on_cache_hit(reached_depth, encountered_overflow);
debug!("global cache hit");
if let Some(result) = self.lookup_global_cache(tcx, input, available_depth, inspect) {
return result;
}
@ -332,12 +304,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
// already set correctly while computing the cache entry.
inspect
.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::ProvisionalCacheHit);
Self::tag_cycle_participants(
&mut self.stack,
&mut self.cycle_participants,
HasBeenUsed::empty(),
entry.head,
);
Self::tag_cycle_participants(&mut self.stack, HasBeenUsed::empty(), entry.head);
return entry.result;
} else if let Some(stack_depth) = cache_entry.stack_depth {
debug!("encountered cycle with depth {stack_depth:?}");
@ -354,12 +321,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
} else {
HasBeenUsed::INDUCTIVE_CYCLE
};
Self::tag_cycle_participants(
&mut self.stack,
&mut self.cycle_participants,
usage_kind,
stack_depth,
);
Self::tag_cycle_participants(&mut self.stack, usage_kind, stack_depth);
// Return the provisional result or, if we're in the first iteration,
// start with no constraints.
@ -380,6 +342,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
non_root_cycle_participant: None,
encountered_overflow: false,
has_been_used: HasBeenUsed::empty(),
cycle_participants: Default::default(),
provisional_result: None,
};
assert_eq!(self.stack.push(entry), depth);
@ -388,63 +351,16 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
// This is for global caching, so we properly track query dependencies.
// Everything that affects the `result` should be performed within this
// `with_anon_task` closure.
// `with_anon_task` closure. If computing this goal depends on something
// not tracked by the cache key and from outside of this anon task, it
// must not be added to the global cache. Notably, this is the case for
// trait solver cycles participants.
let ((final_entry, result), dep_node) =
tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || {
// When we encounter a coinductive cycle, we have to fetch the
// result of that cycle while we are still computing it. Because
// of this we continuously recompute the cycle until the result
// of the previous iteration is equal to the final result, at which
// point we are done.
for _ in 0..FIXPOINT_STEP_LIMIT {
let result = prove_goal(self, inspect);
let stack_entry = self.pop_stack();
debug_assert_eq!(stack_entry.input, input);
// If the current goal is not the root of a cycle, we are done.
if stack_entry.has_been_used.is_empty() {
return (stack_entry, result);
}
// If it is a cycle head, we have to keep trying to prove it until
// we reach a fixpoint. We need to do so for all cycle heads,
// not only for the root.
//
// See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
// for an example.
// Start by clearing all provisional cache entries which depend on this
// the current goal.
Self::clear_dependent_provisional_results(
&mut self.provisional_cache,
self.stack.next_index(),
);
// Check whether we reached a fixpoint, either because the final result
// is equal to the provisional result of the previous iteration, or because
// this was only the root of either coinductive or inductive cycles, and the
// final result is equal to the initial response for that case.
let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
r == result
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
== result
} else {
false
};
// If we did not reach a fixpoint, update the provisional result and reevaluate.
if reached_fixpoint {
return (stack_entry, result);
} else {
let depth = self.stack.push(StackEntry {
has_been_used: HasBeenUsed::empty(),
provisional_result: Some(result),
..stack_entry
});
debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) {
StepResult::Done(final_entry, result) => return (final_entry, result),
StepResult::HasChanged => {}
}
}
@ -473,14 +389,13 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
} else {
self.provisional_cache.remove(&input);
let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len();
let cycle_participants = mem::take(&mut self.cycle_participants);
// When encountering a cycle, both inductive and coinductive, we only
// move the root into the global cache. We also store all other cycle
// participants involved.
//
// We must not use the global cache entry of a root goal if a cycle
// participant is on the stack. This is necessary to prevent unstable
// results. See the comment of `SearchGraph::cycle_participants` for
// results. See the comment of `StackEntry::cycle_participants` for
// more details.
self.global_cache(tcx).insert(
tcx,
@ -488,15 +403,129 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
proof_tree,
reached_depth,
final_entry.encountered_overflow,
cycle_participants,
final_entry.cycle_participants,
dep_node,
result,
)
}
self.check_invariants();
result
}
/// Try to fetch a previously computed result from the global cache,
/// making sure to only do so if it would match the result of reevaluating
/// this goal.
fn lookup_global_cache(
&mut self,
tcx: TyCtxt<'tcx>,
input: CanonicalInput<TyCtxt<'tcx>>,
available_depth: Limit,
inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
) -> Option<QueryResult<TyCtxt<'tcx>>> {
let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self
.global_cache(tcx)
.get(tcx, input, self.stack.iter().map(|e| e.input), available_depth)?;
// If we're building a proof tree and the current cache entry does not
// contain a proof tree, we do not use the entry but instead recompute
// the goal. We simply overwrite the existing entry once we're done,
// caching the proof tree.
if !inspect.is_noop() {
if let Some(revisions) = proof_tree {
let kind = inspect::WipCanonicalGoalEvaluationKind::Interned { revisions };
inspect.goal_evaluation_kind(kind);
} else {
return None;
}
}
// Update the reached depth of the current goal to make sure
// its state is the same regardless of whether we've used the
// global cache or not.
let reached_depth = self.stack.next_index().plus(additional_depth);
if let Some(last) = self.stack.raw.last_mut() {
last.reached_depth = last.reached_depth.max(reached_depth);
last.encountered_overflow |= encountered_overflow;
}
Some(result)
}
}
enum StepResult<I: Interner> {
Done(StackEntry<I>, QueryResult<I>),
HasChanged,
}
impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
/// When we encounter a coinductive cycle, we have to fetch the
/// result of that cycle while we are still computing it. Because
/// of this we continuously recompute the cycle until the result
/// of the previous iteration is equal to the final result, at which
/// point we are done.
fn fixpoint_step_in_task<F>(
&mut self,
tcx: TyCtxt<'tcx>,
input: CanonicalInput<TyCtxt<'tcx>>,
inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
prove_goal: &mut F,
) -> StepResult<TyCtxt<'tcx>>
where
F: FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>,
{
let result = prove_goal(self, inspect);
let stack_entry = self.pop_stack();
debug_assert_eq!(stack_entry.input, input);
// If the current goal is not the root of a cycle, we are done.
if stack_entry.has_been_used.is_empty() {
return StepResult::Done(stack_entry, result);
}
// If it is a cycle head, we have to keep trying to prove it until
// we reach a fixpoint. We need to do so for all cycle heads,
// not only for the root.
//
// See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
// for an example.
// Start by clearing all provisional cache entries which depend on this
// the current goal.
Self::clear_dependent_provisional_results(
&mut self.provisional_cache,
self.stack.next_index(),
);
// Check whether we reached a fixpoint, either because the final result
// is equal to the provisional result of the previous iteration, or because
// this was only the root of either coinductive or inductive cycles, and the
// final result is equal to the initial response for that case.
let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
r == result
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
Self::response_no_constraints(tcx, input, Certainty::overflow(false)) == result
} else {
false
};
// If we did not reach a fixpoint, update the provisional result and reevaluate.
if reached_fixpoint {
StepResult::Done(stack_entry, result)
} else {
let depth = self.stack.push(StackEntry {
has_been_used: HasBeenUsed::empty(),
provisional_result: Some(result),
..stack_entry
});
debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
StepResult::HasChanged
}
}
fn response_no_constraints(
tcx: TyCtxt<'tcx>,
goal: CanonicalInput<TyCtxt<'tcx>>,
@ -505,3 +534,77 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty))
}
}
impl<I: Interner> SearchGraph<I> {
#[allow(rustc::potential_query_instability)]
fn check_invariants(&self) {
if !cfg!(debug_assertions) {
return;
}
let SearchGraph { mode: _, stack, provisional_cache } = self;
if stack.is_empty() {
assert!(provisional_cache.is_empty());
}
for (depth, entry) in stack.iter_enumerated() {
let StackEntry {
input,
available_depth: _,
reached_depth: _,
non_root_cycle_participant,
encountered_overflow: _,
has_been_used,
ref cycle_participants,
provisional_result,
} = *entry;
let cache_entry = provisional_cache.get(&entry.input).unwrap();
assert_eq!(cache_entry.stack_depth, Some(depth));
if let Some(head) = non_root_cycle_participant {
assert!(head < depth);
assert!(cycle_participants.is_empty());
assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
let mut current_root = head;
while let Some(parent) = stack[current_root].non_root_cycle_participant {
current_root = parent;
}
assert!(stack[current_root].cycle_participants.contains(&input));
}
if !cycle_participants.is_empty() {
assert!(provisional_result.is_some() || !has_been_used.is_empty());
for entry in stack.iter().take(depth.as_usize()) {
assert_eq!(cycle_participants.get(&entry.input), None);
}
}
}
for (&input, entry) in &self.provisional_cache {
let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } =
entry;
assert!(
stack_depth.is_some()
|| with_coinductive_stack.is_some()
|| with_inductive_stack.is_some()
);
if let &Some(stack_depth) = stack_depth {
assert_eq!(stack[stack_depth].input, input);
}
let check_detached = |detached_entry: &DetachedEntry<I>| {
let DetachedEntry { head, result: _ } = *detached_entry;
assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
};
if let Some(with_coinductive_stack) = with_coinductive_stack {
check_detached(with_coinductive_stack);
}
if let Some(with_inductive_stack) = with_inductive_stack {
check_detached(with_inductive_stack);
}
}
}
}

View File

@ -33,9 +33,6 @@ addr2line = { version = "0.21.0", optional = true, default-features = false }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
[target.'cfg(all(windows, target_env = "msvc"))'.dependencies]
libc = { version = "0.2.153", default-features = false }
[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }

View File

@ -328,7 +328,7 @@ where
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
let prev_written = cursor.written();
Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
Read::read_buf(&mut self.remaining_slice(), cursor.reborrow())?;
self.pos += (cursor.written() - prev_written) as u64;
@ -352,17 +352,24 @@ where
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
let n = buf.len();
Read::read_exact(&mut self.remaining_slice(), buf)?;
self.pos += n as u64;
Ok(())
let result = Read::read_exact(&mut self.remaining_slice(), buf);
match result {
Ok(_) => self.pos += buf.len() as u64,
// The only possible error condition is EOF, so place the cursor at "EOF"
Err(_) => self.pos = self.inner.as_ref().len() as u64,
}
result
}
fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
let n = cursor.capacity();
Read::read_buf_exact(&mut self.remaining_slice(), cursor)?;
self.pos += n as u64;
Ok(())
fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
let prev_written = cursor.written();
let result = Read::read_buf_exact(&mut self.remaining_slice(), cursor.reborrow());
self.pos += (cursor.written() - prev_written) as u64;
result
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {

View File

@ -287,6 +287,9 @@ impl Read for &[u8] {
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
// `read_exact` makes no promise about the content of `buf` if it
// fails so don't bother about that.
*self = &self[self.len()..];
return Err(io::Error::READ_EXACT_EOF);
}
let (a, b) = self.split_at(buf.len());
@ -307,6 +310,9 @@ impl Read for &[u8] {
#[inline]
fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
if cursor.capacity() > self.len() {
// Append everything we can to the cursor.
cursor.append(*self);
*self = &self[self.len()..];
return Err(io::Error::READ_EXACT_EOF);
}
let (a, b) = self.split_at(cursor.capacity());

View File

@ -653,6 +653,38 @@ fn test_take_wrong_length() {
let _ = reader.read(&mut buffer[..]);
}
#[test]
fn slice_read_exact_eof() {
let slice = &b"123456"[..];
let mut r = slice;
assert!(r.read_exact(&mut [0; 10]).is_err());
assert!(r.is_empty());
let mut r = slice;
let buf = &mut [0; 10];
let mut buf = BorrowedBuf::from(buf.as_mut_slice());
assert!(r.read_buf_exact(buf.unfilled()).is_err());
assert!(r.is_empty());
assert_eq!(buf.filled(), b"123456");
}
#[test]
fn cursor_read_exact_eof() {
let slice = Cursor::new(b"123456");
let mut r = slice.clone();
assert!(r.read_exact(&mut [0; 10]).is_err());
assert!(r.is_empty());
let mut r = slice;
let buf = &mut [0; 10];
let mut buf = BorrowedBuf::from(buf.as_mut_slice());
assert!(r.read_buf_exact(buf.unfilled()).is_err());
assert!(r.is_empty());
assert_eq!(buf.filled(), b"123456");
}
#[bench]
fn bench_take_read(b: &mut test::Bencher) {
b.iter(|| {

View File

@ -435,6 +435,7 @@ extern crate alloc as alloc_crate;
// so include it here even if it's unused.
#[doc(masked)]
#[allow(unused_extern_crates)]
#[cfg(not(all(windows, target_env = "msvc")))]
extern crate libc;
// We always need an unwinder currently for backtraces

View File

@ -1,3 +1,5 @@
#![cfg(not(all(windows, target_env = "msvc")))]
use crate::any::TypeId;
macro_rules! ok {

View File

@ -175,23 +175,12 @@ impl Socket {
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut size: isize = 0;
for i in bufs.iter_mut() {
let ret: isize =
cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
if ret != 0 {
size += ret;
}
}
Ok(size.try_into().unwrap())
crate::io::default_read_vectored(|b| self.read(b), bufs)
}
#[inline]
pub fn is_read_vectored(&self) -> bool {
true
false
}
fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
@ -225,17 +214,11 @@ impl Socket {
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut size: isize = 0;
for i in bufs.iter() {
size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
}
Ok(size.try_into().unwrap())
crate::io::default_write_vectored(|b| self.write(b), bufs)
}
pub fn is_write_vectored(&self) -> bool {
true
false
}
pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {

@ -1 +1 @@
Subproject commit bebcf527e67755a989a1739b7cfaa8f0e6b30040
Subproject commit 5e9051f71638aa941cd5dda465e25c61cde9594f

@ -1 +1 @@
Subproject commit 17842ebb050f62e40a4618edeb8e8ee86e758707
Subproject commit dd962bb82865a5284f2404e5234f1e3222b9c022

@ -1 +1 @@
Subproject commit 51817951d0d213a0011f82b62aae02c3b3f2472e
Subproject commit e356977fceaa8591c762312d8d446769166d4b3e

@ -1 +1 @@
Subproject commit 229ad13b64d919b12e548d560f06d88963b25cd3
Subproject commit 20482893d1a502df72f76762c97aed88854cdf81

@ -1 +1 @@
Subproject commit 2d1947ff34d50ca46dfe242ad75531a4c429bb52
Subproject commit b6d4a4940bab85cc91eec70cc2e3096dd48da62d

View File

@ -1,38 +1,21 @@
// Test what happens we save incremental compilation state that makes
// use of foreign items. This used to ICE (#34991).
//@ ignore-sgx no libc
//@ revisions: rpass1
#![feature(rustc_private)]
extern crate libc;
use std::ffi::CString;
mod mlibc {
use libc::{c_char, c_long, c_longlong};
extern "C" {
pub fn atol(x: *const c_char) -> c_long;
pub fn atoll(x: *const c_char) -> c_longlong;
// strlen is provided either by an external library or compiler-builtins as a fallback
pub fn strlen(x: *const std::ffi::c_char) -> usize;
}
}
fn atol(s: String) -> isize {
fn strlen(s: String) -> usize {
let c = CString::new(s).unwrap();
unsafe { mlibc::atol(c.as_ptr()) as isize }
}
fn atoll(s: String) -> i64 {
let c = CString::new(s).unwrap();
unsafe { mlibc::atoll(c.as_ptr()) as i64 }
unsafe { mlibc::strlen(c.as_ptr()) }
}
pub fn main() {
assert_eq!(atol("1024".to_string()) * 10, atol("10240".to_string()));
assert_eq!(
(atoll("11111111111111111".to_string()) * 10),
atoll("111111111111111110".to_string())
);
assert_eq!(strlen("1024".to_string()), strlen("2048".to_string()));
}

View File

@ -11,15 +11,15 @@ extern crate std;
fn foo(_: [i32; (3 as usize)]) ({ } as ())
fn bar() ({
const FOO: usize = ((5 as usize) - (4 as usize) as usize);
let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
const FOO: usize = ((5 as usize) - (4 as usize) as usize);
let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
let _ =
(((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as
&[i32; 3]) as *const _ as *const [i32; 3]) as
*const [i32; (3 as usize)] as *const [i32; 3]);
let _ =
(((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3])
as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)]
as *const [i32; 3]);
@ -29,17 +29,17 @@ fn bar() ({
({
let res =
((::alloc::fmt::format as
for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
as
fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
as String);
(res as String)
} as String);
} as ())
({
let res =
((::alloc::fmt::format as
for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
as
fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
as String);
(res as String)
} as String);
} as ())
type Foo = [i32; (3 as usize)];
struct Bar {
x: [i32; (3 as usize)],
@ -48,9 +48,9 @@ struct TupleBar([i32; (4 as usize)]);
enum Baz { BazVariant([i32; (5 as usize)]), }
fn id<T>(x: T) -> T ({ (x as T) } as T)
fn use_id() ({
let _ =
((id::<[i32; (3 as usize)]> as
fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
(2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
} as ())
let _ =
((id::<[i32; (3 as usize)]> as
fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
(2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
} as ())
fn main() ({ } as ())

View File

@ -1,10 +1,7 @@
#![crate_type = "staticlib"]
#![feature(c_variadic)]
#![feature(rustc_private)]
extern crate libc;
use libc::{c_char, c_double, c_int, c_long, c_longlong};
use std::ffi::{c_char, c_double, c_int, c_long, c_longlong};
use std::ffi::VaList;
use std::ffi::{CString, CStr};

View File

@ -1,10 +1,8 @@
#![feature(rustc_private)]
extern crate libc;
use std::ffi::c_int;
#[link(name = "foo", kind = "static")]
extern "C" {
fn should_return_one() -> libc::c_int;
fn should_return_one() -> c_int;
}
fn main() {

View File

@ -26,6 +26,14 @@ error[E0599]: no method named `push` found for struct `VecDeque` in the current
LL | x.push(1);
| ^^^^ method not found in `VecDeque<_>`
|
note: there's an earlier shadowed binding `x` of type `Vec<_>` that has method `push` available
--> $DIR/rustc_confusables_std_cases.rs:8:9
|
LL | let mut x = Vec::new();
| ^^^^^ `x` of type `Vec<_>` that has method `push` defined earlier here
...
LL | let mut x = VecDeque::new();
| ----- earlier `x` shadowed here with type `VecDeque`
help: you might have meant to use `push_back`
|
LL | x.push_back(1);

View File

@ -10,6 +10,14 @@ LL | struct NonCopy;
LL | _ = x.clone();
| ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds
|
note: there's an earlier shadowed binding `x` of type `Foo<u32>` that has method `clone` available
--> $DIR/deriving-with-repr-packed-2.rs:13:9
|
LL | let x: Foo<u32> = Foo(1, 2, 3);
| ^ `x` of type `Foo<u32>` that has method `clone` defined earlier here
...
LL | let x: Foo<NonCopy> = Foo(NonCopy, NonCopy, NonCopy);
| - earlier `x` shadowed here with type `Foo<NonCopy>`
note: the following trait bounds were not satisfied:
`NonCopy: Clone`
`NonCopy: Copy`

View File

@ -1,21 +1,15 @@
// Ensure that env::vars() does not panic if environ is null.
// Regression test for rust-lang/rust#53200
//@ run-pass
#![allow(unused_imports)]
//@ ignore-windows
// issue-53200
#![feature(rustc_private)]
extern crate libc;
use std::env;
// FIXME: more platforms?
#[cfg(target_os = "linux")]
fn main() {
extern crate libc;
unsafe { libc::clearenv(); }
assert_eq!(env::vars().count(), 0);
assert_eq!(std::env::vars().count(), 0);
}
#[cfg(not(target_os = "linux"))]

View File

@ -1,8 +1,8 @@
#![feature(rustc_private)]
#![feature(test)]
extern crate alloc;
extern crate libc as alloc;
extern crate test as alloc;
//~^ ERROR E0259
fn main() {}

View File

@ -4,13 +4,13 @@ error[E0259]: the name `alloc` is defined multiple times
LL | extern crate alloc;
| ------------------- previous import of the extern crate `alloc` here
LL |
LL | extern crate libc as alloc;
LL | extern crate test as alloc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `alloc` reimported here
|
= note: `alloc` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
LL | extern crate libc as other_alloc;
LL | extern crate test as other_alloc;
|
error: aborting due to 1 previous error

View File

@ -1,5 +1,5 @@
// gate-test-rustc_private
extern crate libc; //~ ERROR use of unstable library feature 'rustc_private'
extern crate cfg_if; //~ ERROR use of unstable library feature 'rustc_private'
fn main() {}

View File

@ -1,8 +1,8 @@
error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
--> $DIR/rustc-private.rs:3:1
|
LL | extern crate libc;
| ^^^^^^^^^^^^^^^^^^
LL | extern crate cfg_if;
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
= help: add `#![feature(rustc_private)]` to the crate attributes to enable

View File

@ -1,20 +1,14 @@
//@ run-pass
//@ ignore-sgx no libc
// Ensure no false positive on "unused extern crate" lint
#![deny(unused_extern_crates)]
#![feature(rustc_private)]
extern crate libc;
use std::ffi::CString;
mod mlibc {
use libc::{c_char, size_t};
use std::ffi::c_char;
extern "C" {
#[link_name = "strlen"]
pub fn my_strlen(str: *const c_char) -> size_t;
pub fn my_strlen(str: *const c_char) -> usize;
}
}

View File

@ -1,9 +1,8 @@
//@ run-pass
#![allow(dead_code)]
//@ pretty-expanded FIXME #23616
#![feature(rustc_private)]
extern crate libc;
#![allow(dead_code)]
#![feature(rustc_private)]
mod bar {
extern "C" {}
@ -13,14 +12,37 @@ mod zed {
extern "C" {}
}
#[cfg(not(windows))]
mod mlibc {
use libc::{c_int, c_void, size_t, ssize_t};
extern crate libc;
use self::libc::{c_int, c_void, size_t, ssize_t};
extern "C" {
pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t;
}
}
#[cfg(windows)]
mod mlibc {
#![allow(non_snake_case)]
use std::ffi::c_void;
pub type BOOL = i32;
pub type HANDLE = *mut c_void;
#[link(name = "ntdll")]
extern "system" {
pub fn WriteFile(
hfile: HANDLE,
lpbuffer: *const u8,
nnumberofbytestowrite: u32,
lpnumberofbyteswritten: *mut u32,
lpoverlapped: *mut c_void,
) -> BOOL;
}
}
mod baz {
extern "C" {}
}

View File

@ -1,4 +1,4 @@
fn main() {
extern crate libc; //~ ERROR use of unstable
use libc::*; //~ ERROR unresolved import
extern crate test; //~ ERROR use of unstable
use test::*; //~ ERROR unresolved import
}

View File

@ -1,19 +1,19 @@
error[E0432]: unresolved import `libc`
error[E0432]: unresolved import `test`
--> $DIR/issue-37887.rs:3:9
|
LL | use libc::*;
| ^^^^ maybe a missing crate `libc`?
LL | use test::*;
| ^^^^ maybe a missing crate `test`?
|
= help: consider adding `extern crate libc` to use the `libc` crate
= help: consider adding `extern crate test` to use the `test` crate
error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
error[E0658]: use of unstable library feature 'test'
--> $DIR/issue-37887.rs:2:5
|
LL | extern crate libc;
LL | extern crate test;
| ^^^^^^^^^^^^^^^^^^
|
= note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
= help: add `#![feature(rustc_private)]` to the crate attributes to enable
= note: see issue #50297 <https://github.com/rust-lang/rust/issues/50297> for more information
= help: add `#![feature(test)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors

View File

@ -1,12 +1,12 @@
//@ edition:2018
#![deny(unused_extern_crates)]
#![feature(test, rustc_private)]
#![feature(test)]
extern crate libc;
extern crate core;
//~^ ERROR unused extern crate
//~| HELP remove
extern crate libc as x;
extern crate core as x;
//~^ ERROR unused extern crate
//~| HELP remove
@ -28,11 +28,11 @@ mod foo {
pub(super) extern crate alloc as d;
extern crate libc;
extern crate core;
//~^ ERROR unused extern crate
//~| HELP remove
extern crate libc as x;
extern crate core as x;
//~^ ERROR unused extern crate
//~| HELP remove
@ -41,11 +41,11 @@ mod foo {
pub extern crate test as y;
mod bar {
extern crate libc;
extern crate core;
//~^ ERROR unused extern crate
//~| HELP remove
extern crate libc as x;
extern crate core as x;
//~^ ERROR unused extern crate
//~| HELP remove

View File

@ -1,7 +1,7 @@
error: unused extern crate
--> $DIR/unnecessary-extern-crate.rs:6:1
|
LL | extern crate libc;
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: remove it
|
note: the lint level is defined here
@ -13,31 +13,31 @@ LL | #![deny(unused_extern_crates)]
error: unused extern crate
--> $DIR/unnecessary-extern-crate.rs:9:1
|
LL | extern crate libc as x;
LL | extern crate core as x;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
error: unused extern crate
--> $DIR/unnecessary-extern-crate.rs:31:5
|
LL | extern crate libc;
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: remove it
error: unused extern crate
--> $DIR/unnecessary-extern-crate.rs:35:5
|
LL | extern crate libc as x;
LL | extern crate core as x;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
error: unused extern crate
--> $DIR/unnecessary-extern-crate.rs:44:9
|
LL | extern crate libc;
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: remove it
error: unused extern crate
--> $DIR/unnecessary-extern-crate.rs:48:9
|
LL | extern crate libc as x;
LL | extern crate core as x;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
error: aborting due to 6 previous errors

View File

@ -7,10 +7,10 @@ extern crate std;
//@ check-pass
fn main() ({
(if (true as bool)
({ } as
()) else if (let Some(a) =
((Some as
fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
Option<i32>) as bool) ({ } as ()) as ())
} as ())
(if (true as bool)
({ } as
()) else if (let Some(a) =
((Some as
fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
Option<i32>) as bool) ({ } as ()) as ())
} as ())

View File

@ -1,5 +1,6 @@
// Test that `download-rustc` doesn't put duplicate copies of libc in the sysroot.
//@ check-pass
//@ ignore-windows doesn't necessarily have the libc crate
#![crate_type = "lib"]
#![no_std]
#![feature(rustc_private)]

View File

@ -0,0 +1,7 @@
fn main() {
let x = Some(3);
let y = vec![1, 2];
if let Some(y) = x {
y.push(y); //~ ERROR E0599
}
}

View File

@ -0,0 +1,17 @@
error[E0599]: no method named `push` found for type `{integer}` in the current scope
--> $DIR/account-for-shadowed-bindings-issue-123558.rs:5:11
|
LL | y.push(y);
| ^^^^ method not found in `{integer}`
|
note: there's an earlier shadowed binding `y` of type `Vec<{integer}>` that has method `push` available
--> $DIR/account-for-shadowed-bindings-issue-123558.rs:3:9
|
LL | let y = vec![1, 2];
| ^ `y` of type `Vec<{integer}>` that has method `push` defined earlier here
LL | if let Some(y) = x {
| - earlier `y` shadowed here with type `{integer}`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View File

@ -5,11 +5,13 @@
#![feature(rustc_private)]
#[cfg(unix)]
extern crate libc;
use std::process::{Command, Stdio};
use std::env;
use std::ffi::c_int;
use std::io::{self, Read, Write};
use std::process::{Command, Stdio};
#[cfg(unix)]
unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
@ -36,14 +38,14 @@ unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
}
#[cfg(unix)]
fn assert_fd_is_valid(fd: libc::c_int) {
fn assert_fd_is_valid(fd: c_int) {
if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } {
panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error());
}
}
#[cfg(windows)]
fn assert_fd_is_valid(_fd: libc::c_int) {}
fn assert_fd_is_valid(_fd: c_int) {}
#[cfg(windows)]
unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {

View File

@ -1,6 +1,7 @@
//@ run-pass
//@ aux-build:sigpipe-utils.rs
//@ compile-flags: -Zon-broken-pipe=error
//@ only-unix because SIGPIPE is a unix thing
fn main() {
extern crate sigpipe_utils;

View File

@ -4,6 +4,7 @@
//@ aux-bin: assert-inherit-sig_ign.rs
//@ run-pass
//@ compile-flags: -Zon-broken-pipe=kill
//@ only-unix because SIGPIPE is a unix thing
#![feature(rustc_private)]

View File

@ -1,6 +1,7 @@
//@ run-pass
//@ aux-build:sigpipe-utils.rs
//@ compile-flags: -Zon-broken-pipe=kill
//@ only-unix because SIGPIPE is a unix thing
fn main() {
extern crate sigpipe_utils;

View File

@ -1,5 +1,6 @@
//@ run-pass
//@ aux-build:sigpipe-utils.rs
//@ only-unix because SIGPIPE is a unix thing
fn main() {
extern crate sigpipe_utils;

View File

@ -1,6 +1,7 @@
//@ run-pass
//@ aux-build:sigpipe-utils.rs
//@ compile-flags: -Zon-broken-pipe=kill
//@ only-unix because SIGPIPE is a unix thing
#![feature(rustc_attrs)]

View File

@ -8,21 +8,16 @@
//@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590)
//@ ignore-nto no stack overflow handler used (no alternate stack available)
#![feature(core_intrinsics)]
#![feature(rustc_private)]
#[cfg(unix)]
extern crate libc;
use std::env;
use std::hint::black_box;
use std::process::Command;
use std::thread;
// Inlining to avoid llvm turning the recursive functions into tail calls,
// which doesn't consume stack.
#[inline(always)]
pub fn black_box<T>(dummy: T) { std::intrinsics::black_box(dummy); }
fn silent_recurse() {
let buf = [0u8; 1000];
black_box(buf);

View File

@ -1,6 +1,7 @@
//@ run-pass
//@ check-run-results
//@ ignore-emscripten
//@ only-unix
// Emscripten doesn't flush its own stdout buffers on exit, which would fail
// this test. So this test is disabled on this platform.

View File

@ -0,0 +1,20 @@
//@ run-pass
//@ check-run-results
//@ only-windows
struct Bye;
impl Drop for Bye {
fn drop(&mut self) {
print!(", world!");
}
}
fn main() {
thread_local!{
static BYE: Bye = Bye;
}
BYE.with(|_| {
print!("hello");
});
}

View File

@ -0,0 +1 @@
hello, world!

View File

@ -25,8 +25,8 @@ LL + let str::as_bytes;
|
error[E0533]: expected unit struct, unit variant or constant, found associated function `str<{
fn str() { let (/*ERROR*/); }
}, T>::as_bytes`
fn str() { let (/*ERROR*/); }
}, T>::as_bytes`
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:9
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;

View File

@ -1,3 +1,4 @@
//@ revisions: with without
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
@ -56,6 +57,7 @@ where
X: IncompleteGuidance<u32, i8>,
X: IncompleteGuidance<u32, i16>,
{
#[cfg(with)]
impls_trait::<B<X>, _, _, _>(); // entering the cycle from `B` works
// entering the cycle from `A` fails, but would work if we were to use the cache

View File

@ -1,12 +1,12 @@
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
--> $DIR/incompleteness-unstable-result.rs:63:19
--> $DIR/incompleteness-unstable-result.rs:65:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
|
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
--> $DIR/incompleteness-unstable-result.rs:32:50
--> $DIR/incompleteness-unstable-result.rs:33:50
|
LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^
@ -16,7 +16,7 @@ LL | A<T>: Trait<U, D, V>,
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
--> $DIR/incompleteness-unstable-result.rs:51:28
--> $DIR/incompleteness-unstable-result.rs:52:28
|
LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`

View File

@ -0,0 +1,26 @@
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
--> $DIR/incompleteness-unstable-result.rs:65:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
|
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
--> $DIR/incompleteness-unstable-result.rs:33:50
|
LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^
...
LL | A<T>: Trait<U, D, V>,
| -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
--> $DIR/incompleteness-unstable-result.rs:52:28
|
LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -10,5 +10,5 @@ extern crate std;
trait Animal { }
fn main() {
type ServeFut = /*impl Trait*/;
}
type ServeFut = /*impl Trait*/;
}

View File

@ -7,5 +7,5 @@ extern crate std;
// In #100948 this caused an ICE with -Zunpretty=hir.
fn main() {
<bad-literal>;
}
<bad-literal>;
}

View File

@ -8,7 +8,7 @@ use ::std::prelude::rust_2015::*;
extern crate std;
fn main() {
let _ =
#[rustc_box]
Box::new(1);
}
let _ =
#[rustc_box]
Box::new(1);
}

View File

@ -6,10 +6,10 @@ extern crate std;
//@ check-pass
fn main() {
let x = 1;
// Should flatten to println!("a 123 b {x} xyz\n"):
{
::std::io::_print(format_arguments::new_v1(&["a 123 b ",
" xyz\n"], &[format_argument::new_display(&x)]));
};
}
let x = 1;
// Should flatten to println!("a 123 b {x} xyz\n"):
{
::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"],
&[format_argument::new_display(&x)]));
};
}

View File

@ -9,10 +9,10 @@ extern crate std;
fn foo(x:
Option<u32>) {
let Some(_) = x else
{
let Some(_) = x else
{
{ ::std::rt::begin_panic("explicit panic") }
};
}
{ ::std::rt::begin_panic("explicit panic") }
};
}
fn main() { }

View File

@ -7,8 +7,6 @@
#![feature(rustc_private)]
extern crate libc;
use std::process::Command;
// The output from "ps -A -o pid,ppid,args" should look like this:
@ -28,6 +26,7 @@ use std::process::Command;
#[cfg(unix)]
fn find_zombies() {
extern crate libc;
let my_pid = unsafe { libc::getpid() };
// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html