Auto merge of #131372 - workingjubilee:rollup-4tyqgx2, r=workingjubilee
Rollup of 7 pull requests Successful merges: - #128721 (Don't allow the `#[pointee]` attribute where it doesn't belong) - #130479 (skip in-tree compiler build for llvm-bitcode-linker if ci-rustc is on) - #130899 (Couple of changes to make it easier to compile rustc for wasm) - #131225 (`rustc_borrowck` memory management tweaks) - #131351 (Remove valgrind test suite and support from compiletest, bootstrap and opt-dist) - #131359 (Fix used_underscore_binding in rustc_serialize) - #131367 (Mark Boxy as on vacation) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
baaf3e65ab
47 changed files with 254 additions and 703 deletions
|
|
@ -1,7 +1,5 @@
|
|||
//! This file provides API for compiler consumers.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::{Body, Promoted};
|
||||
|
|
@ -65,10 +63,10 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
/// The mir bodies of promoteds.
|
||||
pub promoted: IndexVec<Promoted, Body<'tcx>>,
|
||||
/// The set of borrows occurring in `body` with data about them.
|
||||
pub borrow_set: Rc<BorrowSet<'tcx>>,
|
||||
pub borrow_set: BorrowSet<'tcx>,
|
||||
/// Context generated during borrowck, intended to be passed to
|
||||
/// [`calculate_borrows_out_of_scope_at_location`].
|
||||
pub region_inference_context: Rc<RegionInferenceContext<'tcx>>,
|
||||
pub region_inference_context: RegionInferenceContext<'tcx>,
|
||||
/// The table that maps Polonius points to locations in the table.
|
||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
|
|
@ -79,7 +77,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
pub input_facts: Option<Box<PoloniusInput>>,
|
||||
/// Polonius output facts. Populated when using
|
||||
/// [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
pub output_facts: Option<Rc<PoloniusOutput>>,
|
||||
pub output_facts: Option<Box<PoloniusOutput>>,
|
||||
}
|
||||
|
||||
/// This function computes borrowck facts for the given body. The [`ConsumerOptions`]
|
||||
|
|
|
|||
|
|
@ -708,9 +708,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// for the branching codepaths that aren't covered, to point at them.
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body = map.body_owned_by(self.mir_def_id());
|
||||
let mut visitor =
|
||||
ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
|
||||
let mut visitor = ConditionVisitor { tcx: self.infcx.tcx, spans, name, errors: vec![] };
|
||||
visitor.visit_body(&body);
|
||||
let spans = visitor.spans;
|
||||
|
||||
let mut show_assign_sugg = false;
|
||||
let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
|
||||
|
|
@ -4465,20 +4465,20 @@ impl<'hir> Visitor<'hir> for BreakFinder {
|
|||
|
||||
/// Given a set of spans representing statements initializing the relevant binding, visit all the
|
||||
/// function expressions looking for branching code paths that *do not* initialize the binding.
|
||||
struct ConditionVisitor<'b, 'tcx> {
|
||||
struct ConditionVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
spans: &'b [Span],
|
||||
name: &'b str,
|
||||
spans: Vec<Span>,
|
||||
name: String,
|
||||
errors: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
||||
impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
match ex.kind {
|
||||
hir::ExprKind::If(cond, body, None) => {
|
||||
// `if` expressions with no `else` that initialize the binding might be missing an
|
||||
// `else` arm.
|
||||
if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() {
|
||||
if ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break() {
|
||||
self.errors.push((
|
||||
cond.span,
|
||||
format!(
|
||||
|
|
@ -4495,8 +4495,8 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
hir::ExprKind::If(cond, body, Some(other)) => {
|
||||
// `if` expressions where the binding is only initialized in one of the two arms
|
||||
// might be missing a binding initialization.
|
||||
let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break();
|
||||
let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break();
|
||||
let a = ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break();
|
||||
let b = ReferencedStatementsVisitor(&self.spans).visit_expr(other).is_break();
|
||||
match (a, b) {
|
||||
(true, true) | (false, false) => {}
|
||||
(true, false) => {
|
||||
|
|
@ -4536,7 +4536,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
|
|||
// arms might be missing an initialization.
|
||||
let results: Vec<bool> = arms
|
||||
.iter()
|
||||
.map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break())
|
||||
.map(|arm| ReferencedStatementsVisitor(&self.spans).visit_arm(arm).is_break())
|
||||
.collect();
|
||||
if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
|
||||
for (arm, seen) in arms.iter().zip(results) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
||||
|
|
@ -11,7 +10,7 @@ use crate::region_infer::{Cause, RegionInferenceContext};
|
|||
|
||||
pub(crate) fn find<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &Rc<RegionInferenceContext<'tcx>>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
|
|
@ -23,7 +22,7 @@ pub(crate) fn find<'tcx>(
|
|||
|
||||
struct UseFinder<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
regioncx: &'a Rc<RegionInferenceContext<'tcx>>,
|
||||
regioncx: &'a RegionInferenceContext<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_vid: RegionVid,
|
||||
start_point: Location,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use std::cell::RefCell;
|
|||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
|
@ -200,8 +199,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
.into_results_cursor(body);
|
||||
|
||||
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
|
||||
let borrow_set =
|
||||
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data));
|
||||
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
|
||||
|
||||
// Compute non-lexical lifetimes.
|
||||
let nll::NllOutput {
|
||||
|
|
@ -245,8 +243,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
// usage significantly on some benchmarks.
|
||||
drop(flow_inits);
|
||||
|
||||
let regioncx = Rc::new(regioncx);
|
||||
|
||||
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set)
|
||||
.into_engine(tcx, body)
|
||||
.pass_name("borrowck")
|
||||
|
|
@ -288,10 +284,10 @@ fn do_mir_borrowck<'tcx>(
|
|||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
regioncx: regioncx.clone(),
|
||||
regioncx: ®ioncx,
|
||||
used_mut: Default::default(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
borrow_set: Rc::clone(&borrow_set),
|
||||
borrow_set: &borrow_set,
|
||||
upvars: &[],
|
||||
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
|
||||
region_names: RefCell::default(),
|
||||
|
|
@ -329,10 +325,10 @@ fn do_mir_borrowck<'tcx>(
|
|||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
regioncx: Rc::clone(®ioncx),
|
||||
regioncx: ®ioncx,
|
||||
used_mut: Default::default(),
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
borrow_set: Rc::clone(&borrow_set),
|
||||
borrow_set: &borrow_set,
|
||||
upvars: tcx.closure_captures(def),
|
||||
local_names,
|
||||
region_names: RefCell::default(),
|
||||
|
|
@ -569,10 +565,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
|
||||
/// Region inference context. This contains the results from region inference and lets us e.g.
|
||||
/// find out which CFG points are contained in each borrow region.
|
||||
regioncx: Rc<RegionInferenceContext<'tcx>>,
|
||||
regioncx: &'a RegionInferenceContext<'tcx>,
|
||||
|
||||
/// The set of borrows extracted from the MIR
|
||||
borrow_set: Rc<BorrowSet<'tcx>>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
|
||||
/// Information about upvars not necessarily preserved in types or MIR
|
||||
upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
|
||||
|
|
@ -588,7 +584,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
next_region_name: RefCell<usize>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
|
||||
diags: diags::BorrowckDiags<'infcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
|
|
@ -800,9 +796,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||
TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
|
||||
if self.movable_coroutine {
|
||||
// Look for any active borrows to locals
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &borrow_set[i];
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_local_borrow(borrow, span);
|
||||
}
|
||||
}
|
||||
|
|
@ -816,9 +811,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &borrow_set[i];
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
}
|
||||
}
|
||||
|
|
@ -1037,13 +1031,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
) -> bool {
|
||||
let mut error_reported = false;
|
||||
let borrow_set = Rc::clone(&self.borrow_set);
|
||||
|
||||
// Use polonius output if it has been enabled.
|
||||
let mut polonius_output;
|
||||
let borrows_in_scope = if let Some(polonius) = &self.polonius_output {
|
||||
let location = self.location_table.start_index(location);
|
||||
polonius_output = BitSet::new_empty(borrow_set.len());
|
||||
polonius_output = BitSet::new_empty(self.borrow_set.len());
|
||||
for &idx in polonius.errors_at(location) {
|
||||
polonius_output.insert(idx);
|
||||
}
|
||||
|
|
@ -1057,7 +1050,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
self.infcx.tcx,
|
||||
self.body,
|
||||
(sd, place_span.0),
|
||||
&borrow_set,
|
||||
self.borrow_set,
|
||||
|borrow_index| borrows_in_scope.contains(borrow_index),
|
||||
|this, borrow_index, borrow| match (rw, borrow.kind) {
|
||||
// Obviously an activation is compatible with its own
|
||||
|
|
@ -1580,9 +1573,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// Two-phase borrow support: For each activation that is newly
|
||||
// generated at this statement, check if it interferes with
|
||||
// another borrow.
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
for &borrow_index in borrow_set.activations_at_location(location) {
|
||||
let borrow = &borrow_set[borrow_index];
|
||||
for &borrow_index in self.borrow_set.activations_at_location(location) {
|
||||
let borrow = &self.borrow_set[borrow_index];
|
||||
|
||||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub(crate) struct NllOutput<'tcx> {
|
|||
pub regioncx: RegionInferenceContext<'tcx>,
|
||||
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
pub polonius_input: Option<Box<AllFacts>>,
|
||||
pub polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
pub polonius_output: Option<Box<PoloniusOutput>>,
|
||||
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||
pub nll_errors: RegionErrors<'tcx>,
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
|
||||
let universal_regions = Rc::new(universal_regions);
|
||||
|
||||
let elements = &Rc::new(DenseLocationMap::new(body));
|
||||
let elements = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
|
||||
|
|
@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
param_env,
|
||||
body,
|
||||
promoted,
|
||||
&universal_regions,
|
||||
universal_regions.clone(),
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut all_facts,
|
||||
flow_inits,
|
||||
move_data,
|
||||
elements,
|
||||
elements.clone(),
|
||||
upvars,
|
||||
);
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
universe_causes,
|
||||
type_tests,
|
||||
liveness_constraints,
|
||||
elements,
|
||||
elements.clone(),
|
||||
);
|
||||
|
||||
// If requested: dump NLL facts, and run legacy polonius analysis.
|
||||
|
|
@ -184,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
let algorithm = Algorithm::from_str(&algorithm).unwrap();
|
||||
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
|
||||
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
|
||||
Some(Rc::new(Output::compute(all_facts, algorithm, false)))
|
||||
Some(Box::new(Output::compute(all_facts, algorithm, false)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
liveness_constraints: LivenessValues,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
) -> Self {
|
||||
debug!("universal_regions: {:#?}", universal_regions);
|
||||
debug!("outlives constraints: {:#?}", outlives_constraints);
|
||||
|
|
@ -430,7 +430,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
let mut scc_values =
|
||||
RegionValues::new(elements, universal_regions.len(), &placeholder_indices);
|
||||
RegionValues::new(elements, universal_regions.len(), placeholder_indices);
|
||||
|
||||
for region in liveness_constraints.regions() {
|
||||
let scc = constraint_sccs.scc(region);
|
||||
|
|
@ -637,7 +637,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
|
||||
let mir_def_id = body.source.def_id();
|
||||
self.propagate_constraints();
|
||||
|
|
@ -663,7 +663,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.check_polonius_subset_errors(
|
||||
outlives_requirements.as_mut(),
|
||||
&mut errors_buffer,
|
||||
polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
|
||||
polonius_output
|
||||
.as_ref()
|
||||
.expect("Polonius output is unavailable despite `-Z polonius`"),
|
||||
);
|
||||
} else {
|
||||
self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
|
|
@ -1411,7 +1413,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
&self,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
polonius_output: Rc<PoloniusOutput>,
|
||||
polonius_output: &PoloniusOutput,
|
||||
) {
|
||||
debug!(
|
||||
"check_polonius_subset_errors: {} subset_errors",
|
||||
|
|
|
|||
|
|
@ -275,15 +275,16 @@ impl<N: Idx> RegionValues<N> {
|
|||
/// Each of the regions in num_region_variables will be initialized with an
|
||||
/// empty set of points and no causal information.
|
||||
pub(crate) fn new(
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
num_universal_regions: usize,
|
||||
placeholder_indices: &Rc<PlaceholderIndices>,
|
||||
placeholder_indices: Rc<PlaceholderIndices>,
|
||||
) -> Self {
|
||||
let num_points = elements.num_points();
|
||||
let num_placeholders = placeholder_indices.len();
|
||||
Self {
|
||||
elements: elements.clone(),
|
||||
points: SparseIntervalMatrix::new(elements.num_points()),
|
||||
placeholder_indices: placeholder_indices.clone(),
|
||||
elements,
|
||||
points: SparseIntervalMatrix::new(num_points),
|
||||
placeholder_indices,
|
||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||
placeholders: SparseBitMatrix::new(num_placeholders),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub(crate) fn create<'tcx>(
|
|||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
|
|
@ -62,7 +62,7 @@ pub(crate) fn create<'tcx>(
|
|||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
universal_regions,
|
||||
region_bound_pairs: Default::default(),
|
||||
outlives: Default::default(),
|
||||
inverse_outlives: Default::default(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::mir::visit::{TyContext, Visitor};
|
||||
|
|
@ -33,7 +31,7 @@ mod trace;
|
|||
pub(super) fn generate<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: &DenseLocationMap,
|
||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::interval::IntervalSet;
|
||||
|
|
@ -40,7 +38,7 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
|
|||
pub(super) fn trace<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: &DenseLocationMap,
|
||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_locals: Vec<Local>,
|
||||
|
|
|
|||
|
|
@ -121,13 +121,13 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
location_table: &LocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
upvars: &[&ty::CapturedPlace<'tcx>],
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||
|
|
@ -150,14 +150,14 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
universal_regions.clone(),
|
||||
&mut constraints,
|
||||
);
|
||||
|
||||
debug!(?normalized_inputs_and_output);
|
||||
|
||||
let mut borrowck_context = BorrowCheckContext {
|
||||
universal_regions,
|
||||
universal_regions: &universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
all_facts,
|
||||
|
|
@ -181,10 +181,10 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
verifier.visit_body(body);
|
||||
|
||||
checker.typeck_mir(body);
|
||||
checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output);
|
||||
checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output);
|
||||
checker.check_signature_annotation(body);
|
||||
|
||||
liveness::generate(&mut checker, body, elements, flow_inits, move_data);
|
||||
liveness::generate(&mut checker, body, &elements, flow_inits, move_data);
|
||||
|
||||
translate_outlives_facts(&mut checker);
|
||||
let opaque_type_values = infcx.take_opaque_types();
|
||||
|
|
|
|||
|
|
@ -235,6 +235,8 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
|||
.label = declared `#[non_exhaustive]` here
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
|
||||
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ use rustc_span::symbol::{Ident, sym};
|
|||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
macro_rules! path {
|
||||
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
|
||||
}
|
||||
|
|
@ -25,6 +27,8 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
push: &mut dyn FnMut(Annotatable),
|
||||
_is_const: bool,
|
||||
) {
|
||||
item.visit_with(&mut DetectNonGenericPointeeAttr { cx });
|
||||
|
||||
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
|
||||
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
|
||||
{
|
||||
|
|
@ -396,3 +400,63 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DetectNonGenericPointeeAttr<'a, 'b> {
|
||||
cx: &'a ExtCtxt<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
|
||||
if attr.has_name(sym::pointee) {
|
||||
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result {
|
||||
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
|
||||
|
||||
match ¶m.kind {
|
||||
GenericParamKind::Type { default } => {
|
||||
// The `default` may end up containing a block expression.
|
||||
// The problem is block expressions may define structs with generics.
|
||||
// A user may attach a #[pointee] attribute to one of these generics
|
||||
// We want to catch that. The simple solution is to just
|
||||
// always raise a `NonGenericPointee` error when this happens.
|
||||
//
|
||||
// This solution does reject valid rust programs but,
|
||||
// such a code would have to, in order:
|
||||
// - Define a smart pointer struct.
|
||||
// - Somewhere in this struct definition use a type with a const generic argument.
|
||||
// - Calculate this const generic in a expression block.
|
||||
// - Define a new smart pointer type in this block.
|
||||
// - Have this smart pointer type have more than 1 generic type.
|
||||
// In this case, the inner smart pointer derive would be complaining that it
|
||||
// needs a pointer attribute. Meanwhile, the outer macro would be complaining
|
||||
// that we attached a #[pointee] to a generic type argument while helpfully
|
||||
// informing the user that #[pointee] can only be attached to generic pointer arguments
|
||||
rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default);
|
||||
}
|
||||
|
||||
GenericParamKind::Const { .. } | GenericParamKind::Lifetime => {
|
||||
rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result {
|
||||
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
|
||||
error_on_pointee.visit_ty(t)
|
||||
}
|
||||
}
|
||||
|
||||
struct AlwaysErrorOnGenericParam<'a, 'b> {
|
||||
cx: &'a ExtCtxt<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
|
||||
if attr.has_name(sym::pointee) {
|
||||
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -940,3 +940,10 @@ pub(crate) struct NakedFunctionTestingAttribute {
|
|||
#[label]
|
||||
pub testing_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_generic_pointee)]
|
||||
pub(crate) struct NonGenericPointee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,13 +29,12 @@ use std::path::PathBuf;
|
|||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::{Duration, Instant, SystemTime};
|
||||
use std::time::{Instant, SystemTime};
|
||||
use std::{env, str};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenErrors, CodegenResults};
|
||||
use rustc_const_eval::CTRL_C_RECEIVED;
|
||||
use rustc_data_structures::profiling::{
|
||||
TimePassesFormat, get_resident_set_size, print_time_passes_entry,
|
||||
};
|
||||
|
|
@ -1577,8 +1576,8 @@ pub fn install_ctrlc_handler() {
|
|||
// time to check CTRL_C_RECEIVED and run its own shutdown logic, but after a short amount
|
||||
// of time exit the process. This sleep+exit ensures that even if nobody is checking
|
||||
// CTRL_C_RECEIVED, the compiler exits reasonably promptly.
|
||||
CTRL_C_RECEIVED.store(true, Ordering::Relaxed);
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
rustc_const_eval::CTRL_C_RECEIVED.store(true, Ordering::Relaxed);
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
std::process::exit(1);
|
||||
})
|
||||
.expect("Unable to install ctrlc handler");
|
||||
|
|
|
|||
|
|
@ -76,10 +76,14 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, all(target_os = "wasi", target_env = "p1")))]
|
||||
pub fn path_to_c_string(p: &Path) -> CString {
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
#[cfg(all(target_os = "wasi", target_env = "p1"))]
|
||||
use std::os::wasi::ffi::OsStrExt;
|
||||
|
||||
let p: &OsStr = p.as_ref();
|
||||
CString::new(p.as_bytes()).unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -437,10 +437,10 @@ impl IntEncodedWithFixedSize {
|
|||
impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
|
||||
#[inline]
|
||||
fn encode(&self, e: &mut FileEncoder) {
|
||||
let _start_pos = e.position();
|
||||
let start_pos = e.position();
|
||||
e.write_array(self.0.to_le_bytes());
|
||||
let _end_pos = e.position();
|
||||
debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
|
||||
let end_pos = e.position();
|
||||
debug_assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1394,12 +1394,6 @@ default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" });
|
|||
|
||||
default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" });
|
||||
|
||||
default_test!(RunPassValgrind {
|
||||
path: "tests/run-pass-valgrind",
|
||||
mode: "run-pass-valgrind",
|
||||
suite: "run-pass-valgrind"
|
||||
});
|
||||
|
||||
default_test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen" });
|
||||
|
||||
default_test!(CodegenUnits {
|
||||
|
|
|
|||
|
|
@ -872,8 +872,11 @@ impl Step for LlvmBitcodeLinker {
|
|||
fn run(self, builder: &Builder<'_>) -> PathBuf {
|
||||
let bin_name = "llvm-bitcode-linker";
|
||||
|
||||
builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
|
||||
builder.ensure(compile::Rustc::new(self.compiler, self.target));
|
||||
// If enabled, use ci-rustc and skip building the in-tree compiler.
|
||||
if !builder.download_rustc() {
|
||||
builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
|
||||
builder.ensure(compile::Rustc::new(self.compiler, self.target));
|
||||
}
|
||||
|
||||
let cargo = prepare_tool_cargo(
|
||||
builder,
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@ const PATH_REMAP: &[(&str, &[&str])] = &[
|
|||
"tests/mir-opt",
|
||||
"tests/pretty",
|
||||
"tests/run-make",
|
||||
"tests/run-pass-valgrind",
|
||||
"tests/rustdoc",
|
||||
"tests/rustdoc-gui",
|
||||
"tests/rustdoc-js",
|
||||
|
|
@ -852,7 +851,6 @@ impl<'a> Builder<'a> {
|
|||
test::Tidy,
|
||||
test::Ui,
|
||||
test::Crashes,
|
||||
test::RunPassValgrind,
|
||||
test::Coverage,
|
||||
test::CoverageMap,
|
||||
test::CoverageRun,
|
||||
|
|
@ -1687,10 +1685,24 @@ impl<'a> Builder<'a> {
|
|||
match mode {
|
||||
Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
|
||||
Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
|
||||
// Build proc macros both for the host and the target
|
||||
// Build proc macros both for the host and the target unless proc-macros are not
|
||||
// supported by the target.
|
||||
if target != compiler.host && cmd_kind != Kind::Check {
|
||||
cargo.arg("-Zdual-proc-macros");
|
||||
rustflags.arg("-Zdual-proc-macros");
|
||||
let error = command(self.rustc(compiler))
|
||||
.arg("--target")
|
||||
.arg(target.rustc_target_arg())
|
||||
.arg("--print=file-names")
|
||||
.arg("--crate-type=proc-macro")
|
||||
.arg("-")
|
||||
.run_capture(self)
|
||||
.stderr();
|
||||
let not_supported = error
|
||||
.lines()
|
||||
.any(|line| line.contains("unsupported crate type `proc-macro`"));
|
||||
if !not_supported {
|
||||
cargo.arg("-Zdual-proc-macros");
|
||||
rustflags.arg("-Zdual-proc-macros");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ pub fn exe(name: &str, target: &str) -> String {
|
|||
format!("{name}.exe")
|
||||
} else if target.contains("uefi") {
|
||||
format!("{name}.efi")
|
||||
} else if target.contains("wasm") {
|
||||
format!("{name}.wasm")
|
||||
} else {
|
||||
name.to_string()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ macro_rules! string_enum {
|
|||
string_enum! {
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum Mode {
|
||||
RunPassValgrind => "run-pass-valgrind",
|
||||
Pretty => "pretty",
|
||||
DebugInfo => "debuginfo",
|
||||
Codegen => "codegen",
|
||||
|
|
@ -207,13 +206,6 @@ pub struct Config {
|
|||
/// Path to LLVM's bin directory.
|
||||
pub llvm_bin_dir: Option<PathBuf>,
|
||||
|
||||
/// The valgrind path.
|
||||
pub valgrind_path: Option<String>,
|
||||
|
||||
/// Whether to fail if we can't run run-pass-valgrind tests under valgrind
|
||||
/// (or, alternatively, to silently run them like regular run-pass tests).
|
||||
pub force_valgrind: bool,
|
||||
|
||||
/// The path to the Clang executable to run Clang-based tests with. If
|
||||
/// `None` then these tests will be ignored.
|
||||
pub run_clang_based_tests_with: Option<String>,
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
.reqopt("", "python", "path to python to use for doc tests", "PATH")
|
||||
.optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
|
||||
.optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
|
||||
.optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
|
||||
.optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
|
||||
.optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
|
||||
.optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR")
|
||||
.reqopt("", "src-base", "directory to scan for test files", "PATH")
|
||||
|
|
@ -65,7 +63,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
"",
|
||||
"mode",
|
||||
"which sort of compile tests to run",
|
||||
"run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
|
||||
"pretty | debug-info | codegen | rustdoc \
|
||||
| rustdoc-json | codegen-units | incremental | run-make | ui \
|
||||
| js-doc-test | mir-opt | assembly | crashes",
|
||||
)
|
||||
|
|
@ -269,8 +267,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
python: matches.opt_str("python").unwrap(),
|
||||
jsondocck_path: matches.opt_str("jsondocck-path"),
|
||||
jsondoclint_path: matches.opt_str("jsondoclint-path"),
|
||||
valgrind_path: matches.opt_str("valgrind-path"),
|
||||
force_valgrind: matches.opt_present("force-valgrind"),
|
||||
run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
|
||||
llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
|
||||
llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ fn main() {
|
|||
|
||||
let config = Arc::new(parse_config(env::args().collect()));
|
||||
|
||||
if config.valgrind_path.is_none() && config.force_valgrind {
|
||||
panic!("Can't find Valgrind to run Valgrind tests");
|
||||
}
|
||||
|
||||
if !config.has_tidy && config.mode == Mode::Rustdoc {
|
||||
eprintln!("warning: `tidy` is not installed; diffs will not be generated");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ use tracing::*;
|
|||
use crate::common::{
|
||||
Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes,
|
||||
DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, Pretty, RunMake,
|
||||
RunPassValgrind, Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR,
|
||||
UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path,
|
||||
incremental_dir, output_base_dir, output_base_name, output_testname_unique,
|
||||
Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
|
||||
UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
|
||||
output_base_dir, output_base_name, output_testname_unique,
|
||||
};
|
||||
use crate::compute_diff::{write_diff, write_filtered_diff};
|
||||
use crate::errors::{self, Error, ErrorKind};
|
||||
|
|
@ -49,7 +49,6 @@ mod run_make;
|
|||
mod rustdoc;
|
||||
mod rustdoc_json;
|
||||
mod ui;
|
||||
mod valgrind;
|
||||
// tidy-alphabet-end
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -253,7 +252,6 @@ impl<'test> TestCx<'test> {
|
|||
self.fatal("cannot use should-ice in a test that is not cfail");
|
||||
}
|
||||
match self.config.mode {
|
||||
RunPassValgrind => self.run_valgrind_test(),
|
||||
Pretty => self.run_pretty_test(),
|
||||
DebugInfo => self.run_debuginfo_test(),
|
||||
Codegen => self.run_codegen_test(),
|
||||
|
|
@ -1500,8 +1498,7 @@ impl<'test> TestCx<'test> {
|
|||
Crashes => {
|
||||
set_mir_dump_dir(&mut rustc);
|
||||
}
|
||||
RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
|
||||
| CodegenUnits | JsDocTest => {
|
||||
Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest => {
|
||||
// do not use JSON output
|
||||
}
|
||||
}
|
||||
|
|
@ -2655,33 +2652,6 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(jieyouxu): `run_rpass_test` is hoisted out here and not in incremental because
|
||||
// apparently valgrind test falls back to `run_rpass_test` if valgrind isn't available, which
|
||||
// seems highly questionable to me.
|
||||
fn run_rpass_test(&self) {
|
||||
let emit_metadata = self.should_emit_metadata(self.pass_mode());
|
||||
let should_run = self.run_if_enabled();
|
||||
let proc_res = self.compile_test(should_run, emit_metadata);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
|
||||
// FIXME(#41968): Move this check to tidy?
|
||||
if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
|
||||
self.fatal("run-pass tests with expected warnings should be moved to ui/");
|
||||
}
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let proc_res = self.exec_compiled_test();
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
}
|
||||
|
||||
fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
|
||||
for e in path.read_dir()? {
|
||||
let entry = e?;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
use super::{TestCx, WillExecute};
|
||||
use crate::errors;
|
||||
|
||||
// FIXME(jieyouxu): `run_rpass_test` got hoisted out of this because apparently valgrind falls back
|
||||
// to `run_rpass_test` if valgrind isn't available, which is questionable, but keeping it for
|
||||
// refactoring changes to preserve current behavior.
|
||||
|
||||
impl TestCx<'_> {
|
||||
pub(super) fn run_incremental_test(&self) {
|
||||
// Basic plan for a test incremental/foo/bar.rs:
|
||||
|
|
@ -73,6 +69,30 @@ impl TestCx<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_rpass_test(&self) {
|
||||
let emit_metadata = self.should_emit_metadata(self.pass_mode());
|
||||
let should_run = self.run_if_enabled();
|
||||
let proc_res = self.compile_test(should_run, emit_metadata);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
|
||||
// FIXME(#41968): Move this check to tidy?
|
||||
if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
|
||||
self.fatal("run-pass tests with expected warnings should be moved to ui/");
|
||||
}
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let proc_res = self.exec_compiled_test();
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_cfail_test(&self) {
|
||||
let pm = self.pass_mode();
|
||||
let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));
|
||||
|
|
@ -115,12 +135,6 @@ impl TestCx<'_> {
|
|||
|
||||
let proc_res = self.exec_compiled_test();
|
||||
|
||||
// The value our Makefile configures valgrind to return on failure
|
||||
const VALGRIND_ERR: i32 = 100;
|
||||
if proc_res.status.code() == Some(VALGRIND_ERR) {
|
||||
self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
|
||||
}
|
||||
|
||||
let output_to_check = self.get_output(&proc_res);
|
||||
self.check_correct_failure_status(&proc_res);
|
||||
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
use super::{Emit, TestCx, WillExecute};
|
||||
|
||||
impl TestCx<'_> {
|
||||
pub(super) fn run_valgrind_test(&self) {
|
||||
assert!(self.revision.is_none(), "revisions not relevant here");
|
||||
|
||||
// FIXME(jieyouxu): does this really make any sense? If a valgrind test isn't testing
|
||||
// valgrind, what is it even testing?
|
||||
if self.config.valgrind_path.is_none() {
|
||||
assert!(!self.config.force_valgrind);
|
||||
return self.run_rpass_test();
|
||||
}
|
||||
|
||||
let should_run = self.run_if_enabled();
|
||||
let mut proc_res = self.compile_test(should_run, Emit::None);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut new_config = self.config.clone();
|
||||
new_config.runner = new_config.valgrind_path.clone();
|
||||
let new_cx = TestCx { config: &new_config, ..*self };
|
||||
proc_res = new_cx.exec_compiled_test();
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,6 @@ llvm-config = "{llvm_config}"
|
|||
"tests/incremental",
|
||||
"tests/mir-opt",
|
||||
"tests/pretty",
|
||||
"tests/run-pass-valgrind",
|
||||
"tests/ui",
|
||||
"tests/crashes",
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
#![allow(dead_code, cenum_impl_drop_cast)]
|
||||
|
||||
// check dtor calling order when casting enums.
|
||||
|
||||
use std::mem;
|
||||
use std::sync::atomic;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
enum E {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
}
|
||||
|
||||
static FLAG: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
|
||||
impl Drop for E {
|
||||
fn drop(&mut self) {
|
||||
// avoid dtor loop
|
||||
unsafe { mem::forget(mem::replace(self, E::B)) };
|
||||
|
||||
FLAG.store(FLAG.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 0);
|
||||
{
|
||||
let e = E::C;
|
||||
assert_eq!(e as u32, 2);
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// This would previously leak the Box<Trait> because we wouldn't
|
||||
// schedule cleanups when auto borrowing trait objects.
|
||||
// This program should be valgrind clean.
|
||||
|
||||
static mut DROP_RAN: bool = false;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
impl Trait for Foo {}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: &Trait = &*(Box::new(Foo) as Box<Trait>);
|
||||
}
|
||||
unsafe {
|
||||
assert!(DROP_RAN);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
let _ = std::io::stdin();
|
||||
let _ = std::io::stdout();
|
||||
let _ = std::io::stderr();
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Check that coercions are propagated through match and if expressions.
|
||||
|
||||
//@ pretty-expanded FIXME #23616
|
||||
|
||||
use std::boxed::Box;
|
||||
|
||||
pub fn main() {
|
||||
let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
|
||||
|
||||
let _: Box<[isize]> = match true {
|
||||
true => Box::new([1, 2, 3]),
|
||||
false => Box::new([1]),
|
||||
};
|
||||
|
||||
// Check we don't get over-keen at propagating coercions in the case of casts.
|
||||
let x = if true { 42 } else { 42u8 } as u16;
|
||||
let x = match true {
|
||||
true => 42,
|
||||
false => 42u8,
|
||||
} as u16;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
// Check that coercions are propagated through match and if expressions.
|
||||
|
||||
//@ pretty-expanded FIXME #23616
|
||||
|
||||
pub fn main() {
|
||||
let _: Box<[isize]> = if true {
|
||||
let b: Box<_> = Box::new([1, 2, 3]);
|
||||
b
|
||||
} else {
|
||||
let b: Box<_> = Box::new([1]);
|
||||
b
|
||||
};
|
||||
|
||||
let _: Box<[isize]> = match true {
|
||||
true => {
|
||||
let b: Box<_> = Box::new([1, 2, 3]);
|
||||
b
|
||||
}
|
||||
false => {
|
||||
let b: Box<_> = Box::new([1]);
|
||||
b
|
||||
}
|
||||
};
|
||||
|
||||
// Check we don't get over-keen at propagating coercions in the case of casts.
|
||||
let x = if true { 42 } else { 42u8 } as u16;
|
||||
let x = match true {
|
||||
true => 42,
|
||||
false => 42u8,
|
||||
} as u16;
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
//@ ignore-emscripten
|
||||
|
||||
thread_local!(static FOO: Foo = Foo);
|
||||
thread_local!(static BAR: Bar = Bar(1));
|
||||
thread_local!(static BAZ: Baz = Baz);
|
||||
|
||||
static mut HIT: bool = false;
|
||||
|
||||
struct Foo;
|
||||
struct Bar(i32);
|
||||
struct Baz;
|
||||
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
BAR.with(|_| {});
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Bar {
|
||||
fn drop(&mut self) {
|
||||
assert_eq!(self.0, 1);
|
||||
self.0 = 2;
|
||||
BAZ.with(|_| {});
|
||||
assert_eq!(self.0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Baz {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HIT = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
std::thread::spawn(|| {
|
||||
FOO.with(|_| {});
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
assert!(unsafe { HIT });
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
static mut DROP_RAN: bool = false;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
impl Trait for Foo {}
|
||||
|
||||
struct Fat<T: ?Sized> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<Fat<Trait>> = Box::<Fat<Foo>>::new(Fat { f: Foo });
|
||||
}
|
||||
unsafe {
|
||||
assert!(DROP_RAN);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
static mut DROP_RAN: isize = 0;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Fat<T: ?Sized> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<Fat<[Foo]>> = Box::<Fat<[Foo; 3]>>::new(Fat { f: [Foo, Foo, Foo] });
|
||||
}
|
||||
unsafe {
|
||||
assert_eq!(DROP_RAN, 3);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#![feature(unsized_tuple_coercion)]
|
||||
|
||||
static mut DROP_RAN: bool = false;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
impl Trait for Foo {}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<(i32, Trait)> = Box::<(i32, Foo)>::new((42, Foo));
|
||||
}
|
||||
unsafe {
|
||||
assert!(DROP_RAN);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#![feature(unsized_tuple_coercion)]
|
||||
|
||||
static mut DROP_RAN: isize = 0;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<(i32, [Foo])> = Box::<(i32, [Foo; 3])>::new((42, [Foo, Foo, Foo]));
|
||||
}
|
||||
unsafe {
|
||||
assert_eq!(DROP_RAN, 3);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
//@ ignore-wasm32 no subprocess support
|
||||
//@ ignore-sgx no processes
|
||||
//@ ignore-apple this needs valgrind 3.11 or higher; see
|
||||
// https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679
|
||||
|
||||
use std::env;
|
||||
use std::process::{Command, exit};
|
||||
|
||||
fn main() {
|
||||
if env::args().len() > 1 {
|
||||
print!("hello!");
|
||||
exit(0);
|
||||
} else {
|
||||
let out = Command::new(env::args().next().unwrap()).arg("foo").output().unwrap();
|
||||
assert!(out.status.success());
|
||||
assert_eq!(String::from_utf8(out.stdout).unwrap(), "hello!");
|
||||
assert_eq!(String::from_utf8(out.stderr).unwrap(), "");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
use std::alloc::System;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: System = System;
|
||||
|
||||
fn main() {
|
||||
let mut deque = VecDeque::with_capacity(32);
|
||||
deque.push_front(0);
|
||||
deque.reserve(31);
|
||||
deque.push_back(0);
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#![feature(unsized_locals)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(tuple_trait)]
|
||||
|
||||
pub trait FnOnce<Args: std::marker::Tuple> {
|
||||
type Output;
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl FnOnce<()> for A {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
struct B(i32);
|
||||
|
||||
impl FnOnce<()> for B {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
format!("{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct C(String);
|
||||
|
||||
impl FnOnce<()> for C {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct D(Box<String>);
|
||||
|
||||
impl FnOnce<()> for D {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = *(Box::new(A) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("hello"));
|
||||
let x = *(Box::new(B(42)) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("42"));
|
||||
let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("jumping fox"));
|
||||
let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("lazy dog"));
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
#![feature(unsized_locals)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(tuple_trait)]
|
||||
|
||||
pub trait FnOnce<Args: std::marker::Tuple> {
|
||||
type Output;
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for A {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
struct B(i32);
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for B {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
format!("{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct C(String);
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for C {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct D(Box<String>);
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for D {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(A) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("hello"));
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(B(42)) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("42"));
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(C(format!("jumping fox")))
|
||||
as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("jumping fox"));
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(D(Box::new(format!("lazy dog"))))
|
||||
as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("lazy dog"));
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#![feature(unsized_locals)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(self) -> String;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl Foo for A {
|
||||
fn foo(self) -> String {
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
struct B(i32);
|
||||
|
||||
impl Foo for B {
|
||||
fn foo(self) -> String {
|
||||
format!("{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct C(String);
|
||||
|
||||
impl Foo for C {
|
||||
fn foo(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct D(Box<String>);
|
||||
|
||||
impl Foo for D {
|
||||
fn foo(self) -> String {
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = *(Box::new(A) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("hello"));
|
||||
let x = *(Box::new(B(42)) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("42"));
|
||||
let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("jumping fox"));
|
||||
let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("lazy dog"));
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
use std::fmt;
|
||||
|
||||
fn gen_foo() -> Box<fmt::Display> {
|
||||
Box::new(Box::new("foo"))
|
||||
}
|
||||
|
||||
fn foo(x: fmt::Display) {
|
||||
assert_eq!(x.to_string(), "foo");
|
||||
}
|
||||
|
||||
fn foo_indirect(x: fmt::Display) {
|
||||
foo(x);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo(*gen_foo());
|
||||
foo_indirect(*gen_foo());
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
foo(x);
|
||||
}
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
let y: fmt::Display = *gen_foo();
|
||||
foo(x);
|
||||
foo(y);
|
||||
}
|
||||
|
||||
{
|
||||
let mut cnt: usize = 3;
|
||||
let x = loop {
|
||||
let x: fmt::Display = *gen_foo();
|
||||
if cnt == 0 {
|
||||
break x;
|
||||
} else {
|
||||
cnt -= 1;
|
||||
}
|
||||
};
|
||||
foo(x);
|
||||
}
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
let x = if true { x } else { *gen_foo() };
|
||||
foo(x);
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,39 @@ struct NoMaybeSized<'a, #[pointee] T> {
|
|||
ptr: &'a T,
|
||||
}
|
||||
|
||||
#[derive(SmartPointer)]
|
||||
#[repr(transparent)]
|
||||
struct PointeeOnField<'a, #[pointee] T: ?Sized> {
|
||||
#[pointee]
|
||||
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||
ptr: &'a T
|
||||
}
|
||||
|
||||
#[derive(SmartPointer)]
|
||||
#[repr(transparent)]
|
||||
struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
|
||||
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||
ptr: &'a T,
|
||||
}
|
||||
|
||||
#[derive(SmartPointer)]
|
||||
#[repr(transparent)]
|
||||
struct PointeeInConstConstBlock<
|
||||
'a,
|
||||
T: ?Sized,
|
||||
const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
|
||||
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||
{
|
||||
ptr: &'a T,
|
||||
}
|
||||
|
||||
#[derive(SmartPointer)]
|
||||
#[repr(transparent)]
|
||||
struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
|
||||
ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
|
||||
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||
}
|
||||
|
||||
// However, reordering attributes should work nevertheless.
|
||||
#[repr(transparent)]
|
||||
#[derive(SmartPointer)]
|
||||
|
|
|
|||
|
|
@ -58,6 +58,30 @@ error: `derive(SmartPointer)` requires T to be marked `?Sized`
|
|||
LL | struct NoMaybeSized<'a, #[pointee] T> {
|
||||
| ^
|
||||
|
||||
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||
--> $DIR/deriving-smart-pointer-neg.rs:59:5
|
||||
|
|
||||
LL | #[pointee]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||
--> $DIR/deriving-smart-pointer-neg.rs:66:74
|
||||
|
|
||||
LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||
--> $DIR/deriving-smart-pointer-neg.rs:76:34
|
||||
|
|
||||
LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||
--> $DIR/deriving-smart-pointer-neg.rs:85:56
|
||||
|
|
||||
LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0392]: lifetime parameter `'a` is never used
|
||||
--> $DIR/deriving-smart-pointer-neg.rs:15:16
|
||||
|
|
||||
|
|
@ -90,6 +114,6 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
|
|||
|
|
||||
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0392`.
|
||||
|
|
|
|||
|
|
@ -921,6 +921,7 @@ cc = ["@kobzol"]
|
|||
warn_non_default_branch = true
|
||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||
users_on_vacation = [
|
||||
"BoxyUwU",
|
||||
"fmease",
|
||||
"jhpratt",
|
||||
"jyn514",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue