mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 20:46:48 +00:00
Auto merge of #123455 - matthiaskrgr:rollup-b6nu296, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #121546 (Error out of layout calculation if a non-last struct field is unsized) - #122448 (Port hir-tree run-make test to ui test) - #123212 (CFI: Change type transformation to use TypeFolder) - #123218 (Add test for getting parent HIR for synthetic HIR node) - #123324 (match lowering: make false edges more precise) - #123389 (Avoid panicking unnecessarily on startup) - #123397 (Fix diagnostic for qualifier in extern block) - #123431 (Stabilize `proc_macro_byte_character` and `proc_macro_c_str_literals`) - #123439 (coverage: Remove useless constants) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
96eaf553e5
@ -2484,6 +2484,14 @@ pub enum CoroutineKind {
|
||||
}
|
||||
|
||||
impl CoroutineKind {
|
||||
pub fn span(self) -> Span {
|
||||
match self {
|
||||
CoroutineKind::Async { span, .. } => span,
|
||||
CoroutineKind::Gen { span, .. } => span,
|
||||
CoroutineKind::AsyncGen { span, .. } => span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_async(self) -> bool {
|
||||
matches!(self, CoroutineKind::Async { .. })
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ ast_passes_extern_block_suggestion = if you meant to declare an externally defin
|
||||
|
||||
ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
|
||||
.label = in this `extern` block
|
||||
.suggestion = remove the qualifiers
|
||||
.suggestion = remove this qualifier
|
||||
|
||||
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
|
||||
.label = in this `extern` block
|
||||
|
@ -514,13 +514,32 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
|
||||
/// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
|
||||
fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
|
||||
if header.has_qualifiers() {
|
||||
fn check_foreign_fn_headerless(
|
||||
&self,
|
||||
// Deconstruct to ensure exhaustiveness
|
||||
FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader,
|
||||
) {
|
||||
let report_err = |span| {
|
||||
self.dcx().emit_err(errors::FnQualifierInExtern {
|
||||
span: ident.span,
|
||||
span: span,
|
||||
block: self.current_extern_span(),
|
||||
sugg_span: span.until(ident.span.shrink_to_lo()),
|
||||
});
|
||||
};
|
||||
match unsafety {
|
||||
Unsafe::Yes(span) => report_err(span),
|
||||
Unsafe::No => (),
|
||||
}
|
||||
match coroutine_kind {
|
||||
Some(knd) => report_err(knd.span()),
|
||||
None => (),
|
||||
}
|
||||
match constness {
|
||||
Const::Yes(span) => report_err(span),
|
||||
Const::No => (),
|
||||
}
|
||||
match ext {
|
||||
Extern::None => (),
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1145,7 +1164,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
|
@ -270,11 +270,10 @@ pub struct FnBodyInExtern {
|
||||
#[diag(ast_passes_extern_fn_qualifiers)]
|
||||
pub struct FnQualifierInExtern {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub block: Span,
|
||||
#[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub sugg_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -24,8 +24,6 @@ pub(crate) mod ffi;
|
||||
pub(crate) mod map_data;
|
||||
pub mod mapgen;
|
||||
|
||||
const VAR_ALIGN: Align = Align::EIGHT;
|
||||
|
||||
/// A context object for maintaining all state needed by the coverageinfo module.
|
||||
pub struct CrateCoverageContext<'ll, 'tcx> {
|
||||
/// Coverage data for each instrumented function identified by DefId.
|
||||
@ -226,7 +224,8 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(llglobal, &covmap_section_name);
|
||||
llvm::set_alignment(llglobal, VAR_ALIGN);
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
||||
@ -256,7 +255,8 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
||||
llvm::set_section(llglobal, covfun_section_name);
|
||||
llvm::set_alignment(llglobal, VAR_ALIGN);
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
@ -33,10 +33,6 @@ rustc_index::newtype_index! {
|
||||
pub struct CounterId {}
|
||||
}
|
||||
|
||||
impl CounterId {
|
||||
pub const START: Self = Self::ZERO;
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// ID of a coverage-counter expression. Values ascend from 0.
|
||||
///
|
||||
@ -55,10 +51,6 @@ rustc_index::newtype_index! {
|
||||
pub struct ExpressionId {}
|
||||
}
|
||||
|
||||
impl ExpressionId {
|
||||
pub const START: Self = Self::ZERO;
|
||||
}
|
||||
|
||||
/// Enum that can hold a constant zero value, the ID of an physical coverage
|
||||
/// counter, or the ID of a coverage-counter expression.
|
||||
///
|
||||
|
@ -214,12 +214,77 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
///
|
||||
/// ## False edges
|
||||
///
|
||||
/// We don't want to have the exact structure of the decision tree be
|
||||
/// visible through borrow checking. False edges ensure that the CFG as
|
||||
/// seen by borrow checking doesn't encode this. False edges are added:
|
||||
/// We don't want to have the exact structure of the decision tree be visible through borrow
|
||||
/// checking. Specifically we want borrowck to think that:
|
||||
/// - at any point, any or none of the patterns and guards seen so far may have been tested;
|
||||
/// - after the match, any of the patterns may have matched.
|
||||
///
|
||||
/// * From each pre-binding block to the next pre-binding block.
|
||||
/// * From each otherwise block to the next pre-binding block.
|
||||
/// For example, all of these would fail to error if borrowck could see the real CFG (examples
|
||||
/// taken from `tests/ui/nll/match-cfg-fake-edges.rs`):
|
||||
/// ```ignore (too many errors, this is already in the test suite)
|
||||
/// let x = String::new();
|
||||
/// let _ = match true {
|
||||
/// _ => {},
|
||||
/// _ => drop(x),
|
||||
/// };
|
||||
/// // Borrowck must not know the second arm is never run.
|
||||
/// drop(x); //~ ERROR use of moved value
|
||||
///
|
||||
/// let x;
|
||||
/// # let y = true;
|
||||
/// match y {
|
||||
/// _ if { x = 2; true } => {},
|
||||
/// // Borrowck must not know the guard is always run.
|
||||
/// _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
|
||||
/// };
|
||||
///
|
||||
/// let x = String::new();
|
||||
/// # let y = true;
|
||||
/// match y {
|
||||
/// false if { drop(x); true } => {},
|
||||
/// // Borrowck must not know the guard is not run in the `true` case.
|
||||
/// true => drop(x), //~ ERROR use of moved value: `x`
|
||||
/// false => {},
|
||||
/// };
|
||||
///
|
||||
/// # let mut y = (true, true);
|
||||
/// let r = &mut y.1;
|
||||
/// match y {
|
||||
/// //~^ ERROR cannot use `y.1` because it was mutably borrowed
|
||||
/// (false, true) => {}
|
||||
/// // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
|
||||
/// (true, _) => drop(r),
|
||||
/// (false, _) => {}
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// We add false edges to act as if we were naively matching each arm in order. What we need is
|
||||
/// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding
|
||||
/// block to next candidate D's pre-binding block. For maximum precision (needed for deref
|
||||
/// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to
|
||||
/// avoid loops).
|
||||
///
|
||||
/// This turns out to be easy to compute: that block is the `start_block` of the first call to
|
||||
/// `match_candidates` where D is the first candidate in the list.
|
||||
///
|
||||
/// For example:
|
||||
/// ```rust
|
||||
/// # let (x, y) = (true, true);
|
||||
/// match (x, y) {
|
||||
/// (true, true) => 1,
|
||||
/// (false, true) => 2,
|
||||
/// (true, false) => 3,
|
||||
/// _ => 4,
|
||||
/// }
|
||||
/// # ;
|
||||
/// ```
|
||||
/// In this example, the pre-binding block of arm 1 has a false edge to the block for result
|
||||
/// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks
|
||||
/// of the next arm.
|
||||
///
|
||||
/// On top of this, we also add a false edge from the otherwise_block of each guard to the
|
||||
/// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which
|
||||
/// guards may have run.
|
||||
#[instrument(level = "debug", skip(self, arms))]
|
||||
pub(crate) fn match_expr(
|
||||
&mut self,
|
||||
@ -365,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
for candidate in candidates {
|
||||
candidate.visit_leaves(|leaf_candidate| {
|
||||
if let Some(ref mut prev) = previous_candidate {
|
||||
prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
|
||||
assert!(leaf_candidate.false_edge_start_block.is_some());
|
||||
prev.next_candidate_start_block = leaf_candidate.false_edge_start_block;
|
||||
}
|
||||
previous_candidate = Some(leaf_candidate);
|
||||
});
|
||||
@ -1010,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
|
||||
|
||||
/// The block before the `bindings` have been established.
|
||||
pre_binding_block: Option<BasicBlock>,
|
||||
/// The pre-binding block of the next candidate.
|
||||
next_candidate_pre_binding_block: Option<BasicBlock>,
|
||||
|
||||
/// The earliest block that has only candidates >= this one as descendents. Used for false
|
||||
/// edges, see the doc for [`Builder::match_expr`].
|
||||
false_edge_start_block: Option<BasicBlock>,
|
||||
/// The `false_edge_start_block` of the next candidate.
|
||||
next_candidate_start_block: Option<BasicBlock>,
|
||||
}
|
||||
|
||||
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
||||
@ -1033,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
||||
or_span: None,
|
||||
otherwise_block: None,
|
||||
pre_binding_block: None,
|
||||
next_candidate_pre_binding_block: None,
|
||||
false_edge_start_block: None,
|
||||
next_candidate_start_block: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1325,6 +1396,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
otherwise_block: BasicBlock,
|
||||
candidates: &mut [&mut Candidate<'_, 'tcx>],
|
||||
) {
|
||||
if let [first, ..] = candidates {
|
||||
if first.false_edge_start_block.is_none() {
|
||||
first.false_edge_start_block = Some(start_block);
|
||||
}
|
||||
}
|
||||
|
||||
match candidates {
|
||||
[] => {
|
||||
// If there are no candidates that still need testing, we're done. Since all matches are
|
||||
@ -1545,6 +1622,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
.into_iter()
|
||||
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
|
||||
.collect();
|
||||
candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
|
||||
}
|
||||
|
||||
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
|
||||
@ -1564,6 +1642,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let any_matches = self.cfg.start_new_block();
|
||||
let or_span = candidate.or_span.take().unwrap();
|
||||
let source_info = self.source_info(or_span);
|
||||
if candidate.false_edge_start_block.is_none() {
|
||||
candidate.false_edge_start_block =
|
||||
candidate.subcandidates[0].false_edge_start_block;
|
||||
}
|
||||
for subcandidate in mem::take(&mut candidate.subcandidates) {
|
||||
let or_block = subcandidate.pre_binding_block.unwrap();
|
||||
self.cfg.goto(or_block, source_info, any_matches);
|
||||
@ -1979,12 +2061,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
let mut block = candidate.pre_binding_block.unwrap();
|
||||
|
||||
if candidate.next_candidate_pre_binding_block.is_some() {
|
||||
if candidate.next_candidate_start_block.is_some() {
|
||||
let fresh_block = self.cfg.start_new_block();
|
||||
self.false_edges(
|
||||
block,
|
||||
fresh_block,
|
||||
candidate.next_candidate_pre_binding_block,
|
||||
candidate.next_candidate_start_block,
|
||||
candidate_source_info,
|
||||
);
|
||||
block = fresh_block;
|
||||
@ -2132,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.false_edges(
|
||||
otherwise_post_guard_block,
|
||||
otherwise_block,
|
||||
candidate.next_candidate_pre_binding_block,
|
||||
candidate.next_candidate_start_block,
|
||||
source_info,
|
||||
);
|
||||
|
||||
|
@ -59,7 +59,7 @@ fn coverage_ids_info<'tcx>(
|
||||
_ => None,
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(CounterId::START);
|
||||
.unwrap_or(CounterId::ZERO);
|
||||
|
||||
CoverageIdsInfo { max_counter_id }
|
||||
}
|
||||
|
@ -11,13 +11,14 @@ use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
|
||||
TermKind, Ty, TyCtxt, UintTy,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
|
||||
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::sym;
|
||||
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
|
||||
@ -182,14 +183,15 @@ fn encode_fnsig<'tcx>(
|
||||
// Encode the return type
|
||||
let transform_ty_options = TransformTyOptions::from_bits(options.bits())
|
||||
.unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
|
||||
let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options);
|
||||
let mut type_folder = TransformTy::new(tcx, transform_ty_options);
|
||||
let ty = fn_sig.output().fold_with(&mut type_folder);
|
||||
s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
|
||||
|
||||
// Encode the parameter types
|
||||
let tys = fn_sig.inputs();
|
||||
if !tys.is_empty() {
|
||||
for ty in tys {
|
||||
let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options);
|
||||
let ty = ty.fold_with(&mut type_folder);
|
||||
s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
|
||||
}
|
||||
|
||||
@ -523,15 +525,9 @@ fn encode_ty<'tcx>(
|
||||
|
||||
ty::Array(ty0, len) => {
|
||||
// A<array-length><element-type>
|
||||
let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
|
||||
let mut s = String::from("A");
|
||||
let _ = write!(
|
||||
s,
|
||||
"{}",
|
||||
&len.try_to_scalar()
|
||||
.unwrap()
|
||||
.to_target_usize(&tcx.data_layout)
|
||||
.expect("Array lens are defined in usize")
|
||||
);
|
||||
let _ = write!(s, "{}", &len);
|
||||
s.push_str(&encode_ty(tcx, *ty0, dict, options));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
@ -756,278 +752,208 @@ fn encode_ty<'tcx>(
|
||||
typeid
|
||||
}
|
||||
|
||||
/// Transforms predicates for being encoded and used in the substitution dictionary.
|
||||
fn transform_predicates<'tcx>(
|
||||
struct TransformTy<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| {
|
||||
match predicate.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(trait_ref) => {
|
||||
let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id);
|
||||
Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
|
||||
)))
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(..) => None,
|
||||
ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
|
||||
}
|
||||
}))
|
||||
options: TransformTyOptions,
|
||||
parents: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
/// Transforms args for being encoded and used in the substitution dictionary.
|
||||
fn transform_args<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
parents: &mut Vec<Ty<'tcx>>,
|
||||
options: TransformTyOptions,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
let args = args.iter().map(|arg| match arg.unpack() {
|
||||
GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(),
|
||||
GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(),
|
||||
_ => arg,
|
||||
});
|
||||
tcx.mk_args_from_iter(args)
|
||||
impl<'tcx> TransformTy<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
|
||||
TransformTy { tcx, options, parents: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
|
||||
// c_void types into unit types unconditionally, generalizes pointers if
|
||||
// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
|
||||
// TransformTyOptions::NORMALIZE_INTEGERS option is set.
|
||||
fn transform_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut ty: Ty<'tcx>,
|
||||
parents: &mut Vec<Ty<'tcx>>,
|
||||
options: TransformTyOptions,
|
||||
) -> Ty<'tcx> {
|
||||
match ty.kind() {
|
||||
ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {}
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
|
||||
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms
|
||||
// all c_void types into unit types unconditionally, generalizes pointers if
|
||||
// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
|
||||
// TransformTyOptions::NORMALIZE_INTEGERS option is set.
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match t.kind() {
|
||||
ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Float(..)
|
||||
| ty::FnDef(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Never
|
||||
| ty::Slice(..)
|
||||
| ty::Str
|
||||
| ty::Tuple(..) => t.super_fold_with(self),
|
||||
|
||||
ty::Bool => {
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Note: on all platforms that Rust's currently supports, its size and alignment are
|
||||
// 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
|
||||
//
|
||||
// Clang represents bool as an 8-bit unsigned integer.
|
||||
ty = tcx.types.u8;
|
||||
}
|
||||
}
|
||||
|
||||
ty::Char => {
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Since #118032, char is guaranteed to have the same size, alignment, and function
|
||||
// call ABI as u32 on all platforms.
|
||||
ty = tcx.types.u32;
|
||||
}
|
||||
}
|
||||
|
||||
ty::Int(..) | ty::Uint(..) => {
|
||||
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
|
||||
// All platforms we currently support have a C platform, and as a consequence,
|
||||
// isize/usize are at least 16-bit wide for all of them.
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
|
||||
match ty.kind() {
|
||||
ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
|
||||
16 => ty = tcx.types.i16,
|
||||
32 => ty = tcx.types.i32,
|
||||
64 => ty = tcx.types.i64,
|
||||
128 => ty = tcx.types.i128,
|
||||
_ => bug!(
|
||||
"transform_ty: unexpected pointer width `{}`",
|
||||
tcx.sess.target.pointer_width
|
||||
),
|
||||
},
|
||||
ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
|
||||
16 => ty = tcx.types.u16,
|
||||
32 => ty = tcx.types.u32,
|
||||
64 => ty = tcx.types.u64,
|
||||
128 => ty = tcx.types.u128,
|
||||
_ => bug!(
|
||||
"transform_ty: unexpected pointer width `{}`",
|
||||
tcx.sess.target.pointer_width
|
||||
),
|
||||
},
|
||||
_ => (),
|
||||
ty::Bool => {
|
||||
if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Note: on all platforms that Rust's currently supports, its size and alignment
|
||||
// are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
|
||||
//
|
||||
// Clang represents bool as an 8-bit unsigned integer.
|
||||
self.tcx.types.u8
|
||||
} else {
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ if ty.is_unit() => {}
|
||||
|
||||
ty::Tuple(tys) => {
|
||||
ty = Ty::new_tup_from_iter(
|
||||
tcx,
|
||||
tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)),
|
||||
);
|
||||
}
|
||||
|
||||
ty::Array(ty0, len) => {
|
||||
let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
|
||||
|
||||
ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len);
|
||||
}
|
||||
|
||||
ty::Slice(ty0) => {
|
||||
ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options));
|
||||
}
|
||||
|
||||
ty::Adt(adt_def, args) => {
|
||||
if ty.is_c_void(tcx) {
|
||||
ty = Ty::new_unit(tcx);
|
||||
} else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
|
||||
{
|
||||
ty = Ty::new_adt(tcx, *adt_def, ty::List::empty());
|
||||
} else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty)
|
||||
{
|
||||
// Don't transform repr(transparent) types with an user-defined CFI encoding to
|
||||
// preserve the user-defined CFI encoding.
|
||||
if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
|
||||
return ty;
|
||||
ty::Char => {
|
||||
if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Since #118032, char is guaranteed to have the same size, alignment, and
|
||||
// function call ABI as u32 on all platforms.
|
||||
self.tcx.types.u32
|
||||
} else {
|
||||
t
|
||||
}
|
||||
let variant = adt_def.non_enum_variant();
|
||||
let param_env = tcx.param_env(variant.def_id);
|
||||
let field = variant.fields.iter().find(|field| {
|
||||
let ty = tcx.type_of(field.did).instantiate_identity();
|
||||
let is_zst =
|
||||
tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst());
|
||||
!is_zst
|
||||
});
|
||||
if let Some(field) = field {
|
||||
let ty0 = tcx.type_of(field.did).instantiate(tcx, args);
|
||||
// Generalize any repr(transparent) user-defined type that is either a pointer
|
||||
// or reference, and either references itself or any other type that contains or
|
||||
// references itself, to avoid a reference cycle.
|
||||
}
|
||||
|
||||
// If the self reference is not through a pointer, for example, due
|
||||
// to using `PhantomData`, need to skip normalizing it if we hit it again.
|
||||
parents.push(ty);
|
||||
if ty0.is_any_ptr() && ty0.contains(ty) {
|
||||
ty = transform_ty(
|
||||
tcx,
|
||||
ty0,
|
||||
parents,
|
||||
options | TransformTyOptions::GENERALIZE_POINTERS,
|
||||
);
|
||||
} else {
|
||||
ty = transform_ty(tcx, ty0, parents, options);
|
||||
ty::Int(..) | ty::Uint(..) => {
|
||||
if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
|
||||
// Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
|
||||
// wide. All platforms we currently support have a C platform, and as a
|
||||
// consequence, isize/usize are at least 16-bit wide for all of them.
|
||||
//
|
||||
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
|
||||
match t.kind() {
|
||||
ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
|
||||
16 => self.tcx.types.i16,
|
||||
32 => self.tcx.types.i32,
|
||||
64 => self.tcx.types.i64,
|
||||
128 => self.tcx.types.i128,
|
||||
_ => bug!(
|
||||
"fold_ty: unexpected pointer width `{}`",
|
||||
self.tcx.sess.target.pointer_width
|
||||
),
|
||||
},
|
||||
ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
|
||||
16 => self.tcx.types.u16,
|
||||
32 => self.tcx.types.u32,
|
||||
64 => self.tcx.types.u64,
|
||||
128 => self.tcx.types.u128,
|
||||
_ => bug!(
|
||||
"fold_ty: unexpected pointer width `{}`",
|
||||
self.tcx.sess.target.pointer_width
|
||||
),
|
||||
},
|
||||
_ => t,
|
||||
}
|
||||
parents.pop();
|
||||
} else {
|
||||
// Transform repr(transparent) types without non-ZST field into ()
|
||||
ty = Ty::new_unit(tcx);
|
||||
}
|
||||
} else {
|
||||
ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options));
|
||||
}
|
||||
}
|
||||
|
||||
ty::FnDef(def_id, args) => {
|
||||
ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options));
|
||||
}
|
||||
|
||||
ty::Closure(def_id, args) => {
|
||||
ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options));
|
||||
}
|
||||
|
||||
ty::CoroutineClosure(def_id, args) => {
|
||||
ty = Ty::new_coroutine_closure(
|
||||
tcx,
|
||||
*def_id,
|
||||
transform_args(tcx, args, parents, options),
|
||||
);
|
||||
}
|
||||
|
||||
ty::Coroutine(def_id, args) => {
|
||||
ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options));
|
||||
}
|
||||
|
||||
ty::Ref(region, ty0, ..) => {
|
||||
if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
|
||||
if ty.is_mutable_ptr() {
|
||||
ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
|
||||
} else {
|
||||
ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
|
||||
}
|
||||
} else {
|
||||
if ty.is_mutable_ptr() {
|
||||
ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
|
||||
} else {
|
||||
ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options));
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::RawPtr(ptr_ty, _) => {
|
||||
if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
|
||||
if ty.is_mutable_ptr() {
|
||||
ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
|
||||
ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
|
||||
|
||||
ty::Adt(adt_def, args) => {
|
||||
if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
|
||||
{
|
||||
// Don't transform repr(transparent) types with an user-defined CFI encoding to
|
||||
// preserve the user-defined CFI encoding.
|
||||
if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
|
||||
return t;
|
||||
}
|
||||
let variant = adt_def.non_enum_variant();
|
||||
let param_env = self.tcx.param_env(variant.def_id);
|
||||
let field = variant.fields.iter().find(|field| {
|
||||
let ty = self.tcx.type_of(field.did).instantiate_identity();
|
||||
let is_zst = self
|
||||
.tcx
|
||||
.layout_of(param_env.and(ty))
|
||||
.is_ok_and(|layout| layout.is_zst());
|
||||
!is_zst
|
||||
});
|
||||
if let Some(field) = field {
|
||||
let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args);
|
||||
// Generalize any repr(transparent) user-defined type that is either a
|
||||
// pointer or reference, and either references itself or any other type that
|
||||
// contains or references itself, to avoid a reference cycle.
|
||||
|
||||
// If the self reference is not through a pointer, for example, due
|
||||
// to using `PhantomData`, need to skip normalizing it if we hit it again.
|
||||
self.parents.push(t);
|
||||
let ty = if ty0.is_any_ptr() && ty0.contains(t) {
|
||||
let options = self.options;
|
||||
self.options |= TransformTyOptions::GENERALIZE_POINTERS;
|
||||
let ty = ty0.fold_with(self);
|
||||
self.options = options;
|
||||
ty
|
||||
} else {
|
||||
ty0.fold_with(self)
|
||||
};
|
||||
self.parents.pop();
|
||||
ty
|
||||
} else {
|
||||
// Transform repr(transparent) types without non-ZST field into ()
|
||||
self.tcx.types.unit
|
||||
}
|
||||
} else {
|
||||
ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
|
||||
}
|
||||
} else {
|
||||
if ty.is_mutable_ptr() {
|
||||
ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
|
||||
} else {
|
||||
ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options));
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::FnPtr(fn_sig) => {
|
||||
if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
|
||||
ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
|
||||
} else {
|
||||
let parameters: Vec<Ty<'tcx>> = fn_sig
|
||||
.skip_binder()
|
||||
.inputs()
|
||||
.iter()
|
||||
.map(|ty| transform_ty(tcx, *ty, parents, options))
|
||||
.collect();
|
||||
let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options);
|
||||
ty = Ty::new_fn_ptr(
|
||||
tcx,
|
||||
ty::Binder::bind_with_vars(
|
||||
tcx.mk_fn_sig(
|
||||
parameters,
|
||||
output,
|
||||
fn_sig.c_variadic(),
|
||||
fn_sig.unsafety(),
|
||||
fn_sig.abi(),
|
||||
),
|
||||
fn_sig.bound_vars(),
|
||||
),
|
||||
ty::Ref(..) => {
|
||||
if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
|
||||
if t.is_mutable_ptr() {
|
||||
Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
|
||||
} else {
|
||||
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
|
||||
}
|
||||
} else {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
ty::RawPtr(..) => {
|
||||
if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
|
||||
if t.is_mutable_ptr() {
|
||||
Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
|
||||
} else {
|
||||
Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
|
||||
}
|
||||
} else {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
ty::FnPtr(..) => {
|
||||
if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
|
||||
Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
|
||||
} else {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
ty::Dynamic(predicates, _region, kind) => {
|
||||
let predicates = self.tcx.mk_poly_existential_predicates_from_iter(
|
||||
predicates.iter().filter_map(|predicate| match predicate.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(trait_ref) => {
|
||||
let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id);
|
||||
Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
|
||||
ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref),
|
||||
)))
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(..) => None,
|
||||
ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
|
||||
}),
|
||||
);
|
||||
|
||||
Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind)
|
||||
}
|
||||
}
|
||||
|
||||
ty::Dynamic(predicates, _region, kind) => {
|
||||
ty = Ty::new_dynamic(
|
||||
tcx,
|
||||
transform_predicates(tcx, predicates),
|
||||
tcx.lifetimes.re_erased,
|
||||
*kind,
|
||||
);
|
||||
}
|
||||
ty::Alias(..) => {
|
||||
self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
|
||||
}
|
||||
|
||||
ty::Alias(..) => {
|
||||
ty = transform_ty(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty),
|
||||
parents,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
|
||||
bug!("transform_ty: unexpected `{:?}`", ty.kind());
|
||||
ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
|
||||
bug!("fold_ty: unexpected `{:?}`", t.kind());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
|
||||
@ -1068,7 +994,8 @@ pub fn typeid_for_fnabi<'tcx>(
|
||||
// Encode the return type
|
||||
let transform_ty_options = TransformTyOptions::from_bits(options.bits())
|
||||
.unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
|
||||
let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options);
|
||||
let mut type_folder = TransformTy::new(tcx, transform_ty_options);
|
||||
let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
|
||||
typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
|
||||
|
||||
// Encode the parameter types
|
||||
@ -1080,7 +1007,7 @@ pub fn typeid_for_fnabi<'tcx>(
|
||||
let mut pushed_arg = false;
|
||||
for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
|
||||
pushed_arg = true;
|
||||
let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options);
|
||||
let ty = arg.layout.ty.fold_with(&mut type_folder);
|
||||
typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
|
||||
}
|
||||
if !pushed_arg {
|
||||
@ -1093,8 +1020,7 @@ pub fn typeid_for_fnabi<'tcx>(
|
||||
if fn_abi.args[n].mode == PassMode::Ignore {
|
||||
continue;
|
||||
}
|
||||
let ty =
|
||||
transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options);
|
||||
let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
|
||||
typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,9 @@ use rustc_middle::ty::layout::{
|
||||
IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
|
||||
};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::Symbol;
|
||||
@ -506,6 +508,40 @@ fn layout_of_uncached<'tcx>(
|
||||
));
|
||||
}
|
||||
|
||||
let err_if_unsized = |field: &FieldDef, err_msg: &str| {
|
||||
let field_ty = tcx.type_of(field.did);
|
||||
let is_unsized = tcx
|
||||
.try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty)
|
||||
.map(|f| !f.is_sized(tcx, cx.param_env))
|
||||
.map_err(|e| {
|
||||
error(
|
||||
cx,
|
||||
LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e),
|
||||
)
|
||||
})?;
|
||||
|
||||
if is_unsized {
|
||||
cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
|
||||
Err(error(cx, LayoutError::Unknown(ty)))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
if def.is_struct() {
|
||||
if let Some((_, fields_except_last)) =
|
||||
def.non_enum_variant().fields.raw.split_last()
|
||||
{
|
||||
for f in fields_except_last {
|
||||
err_if_unsized(f, "only the last field of a struct can be unsized")?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for f in def.all_fields() {
|
||||
err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?;
|
||||
}
|
||||
}
|
||||
|
||||
let get_discriminant_type =
|
||||
|min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
|
||||
|
||||
|
@ -1360,7 +1360,7 @@ impl Literal {
|
||||
}
|
||||
|
||||
/// Byte character literal.
|
||||
#[unstable(feature = "proc_macro_byte_character", issue = "115268")]
|
||||
#[stable(feature = "proc_macro_byte_character", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn byte_character(byte: u8) -> Literal {
|
||||
let string = [byte].escape_ascii().to_string();
|
||||
Literal::new(bridge::LitKind::Byte, &string, None)
|
||||
@ -1374,7 +1374,7 @@ impl Literal {
|
||||
}
|
||||
|
||||
/// C string literal.
|
||||
#[unstable(feature = "proc_macro_c_str_literals", issue = "119750")]
|
||||
#[stable(feature = "proc_macro_c_str_literals", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn c_string(string: &CStr) -> Literal {
|
||||
let string = string.to_bytes().escape_ascii().to_string();
|
||||
Literal::new(bridge::LitKind::CStr, &string, None)
|
||||
|
@ -3,21 +3,12 @@
|
||||
use crate::sys::c;
|
||||
use crate::thread;
|
||||
|
||||
use super::api;
|
||||
|
||||
pub struct Handler;
|
||||
|
||||
impl Handler {
|
||||
pub unsafe fn new() -> Handler {
|
||||
// This API isn't available on XP, so don't panic in that case and just
|
||||
// pray it works out ok.
|
||||
if c::SetThreadStackGuarantee(&mut 0x5000) == 0
|
||||
&& api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED
|
||||
{
|
||||
panic!("failed to reserve stack space for exception handling");
|
||||
}
|
||||
Handler
|
||||
}
|
||||
/// Reserve stack space for use in stack overflow exceptions.
|
||||
pub unsafe fn reserve_stack() {
|
||||
let result = c::SetThreadStackGuarantee(&mut 0x5000);
|
||||
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
|
||||
// We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
|
||||
debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
|
||||
}
|
||||
|
||||
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG {
|
||||
@ -36,9 +27,10 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
if c::AddVectoredExceptionHandler(0, Some(vectored_handler)).is_null() {
|
||||
panic!("failed to install exception handler");
|
||||
}
|
||||
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
|
||||
// Similar to the above, adding the stack overflow handler is allowed to fail
|
||||
// but a debug assert is used so CI will still test that it normally works.
|
||||
debug_assert!(!result.is_null(), "failed to install exception handler");
|
||||
// Set the thread stack guarantee for the main thread.
|
||||
let _h = Handler::new();
|
||||
reserve_stack();
|
||||
}
|
||||
|
@ -1,11 +1,4 @@
|
||||
#![cfg_attr(test, allow(dead_code))]
|
||||
|
||||
pub struct Handler;
|
||||
|
||||
impl Handler {
|
||||
pub fn new() -> Handler {
|
||||
Handler
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn reserve_stack() {}
|
||||
pub unsafe fn init() {}
|
||||
|
@ -48,9 +48,8 @@ impl Thread {
|
||||
|
||||
extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
|
||||
unsafe {
|
||||
// Next, set up our stack overflow handler which may get triggered if we run
|
||||
// out of stack.
|
||||
let _handler = stack_overflow::Handler::new();
|
||||
// Next, reserve some stack space for if we otherwise run out of stack.
|
||||
stack_overflow::reserve_stack();
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ run-make/foreign-exceptions/Makefile
|
||||
run-make/foreign-rust-exceptions/Makefile
|
||||
run-make/fpic/Makefile
|
||||
run-make/glibc-staticlib-args/Makefile
|
||||
run-make/hir-tree/Makefile
|
||||
run-make/inaccessible-temp-dir/Makefile
|
||||
run-make/include_bytes_deps/Makefile
|
||||
run-make/incr-add-rust-src-component/Makefile
|
||||
|
@ -48,7 +48,7 @@ fn main() -> () {
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb15, imaginary: bb6];
|
||||
falseEdge -> [real: bb15, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
@ -40,7 +40,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb4: {
|
||||
falseEdge -> [real: bb12, imaginary: bb9];
|
||||
falseEdge -> [real: bb12, imaginary: bb7];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
@ -48,7 +48,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb6: {
|
||||
falseEdge -> [real: bb16, imaginary: bb3];
|
||||
falseEdge -> [real: bb16, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
@ -60,7 +60,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb9: {
|
||||
falseEdge -> [real: bb15, imaginary: bb6];
|
||||
falseEdge -> [real: bb15, imaginary: bb5];
|
||||
}
|
||||
|
||||
bb10: {
|
||||
@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
|
||||
|
||||
bb14: {
|
||||
StorageDead(_10);
|
||||
falseEdge -> [real: bb5, imaginary: bb9];
|
||||
falseEdge -> [real: bb5, imaginary: bb7];
|
||||
}
|
||||
|
||||
bb15: {
|
||||
|
@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb9, imaginary: bb4];
|
||||
falseEdge -> [real: bb9, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
}
|
||||
|
||||
bb4: {
|
||||
falseEdge -> [real: bb12, imaginary: bb6];
|
||||
falseEdge -> [real: bb12, imaginary: bb5];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
@ -69,7 +69,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
|
||||
|
||||
bb11: {
|
||||
StorageDead(_8);
|
||||
falseEdge -> [real: bb1, imaginary: bb4];
|
||||
falseEdge -> [real: bb1, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb12: {
|
||||
|
@ -60,11 +60,11 @@
|
||||
}
|
||||
|
||||
- bb5: {
|
||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
||||
- falseEdge -> [real: bb13, imaginary: bb2];
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
- falseEdge -> [real: bb8, imaginary: bb5];
|
||||
- falseEdge -> [real: bb8, imaginary: bb1];
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
@ -127,7 +127,7 @@
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb1, imaginary: bb5];
|
||||
- falseEdge -> [real: bb1, imaginary: bb1];
|
||||
+ goto -> bb1;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@
|
||||
StorageDead(_12);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
||||
- falseEdge -> [real: bb2, imaginary: bb2];
|
||||
+ goto -> bb2;
|
||||
}
|
||||
|
||||
|
@ -60,11 +60,11 @@
|
||||
}
|
||||
|
||||
- bb5: {
|
||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
||||
- falseEdge -> [real: bb13, imaginary: bb2];
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
- falseEdge -> [real: bb8, imaginary: bb5];
|
||||
- falseEdge -> [real: bb8, imaginary: bb1];
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
@ -127,7 +127,7 @@
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb1, imaginary: bb5];
|
||||
- falseEdge -> [real: bb1, imaginary: bb1];
|
||||
+ goto -> bb1;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@
|
||||
StorageDead(_12);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
||||
- falseEdge -> [real: bb2, imaginary: bb2];
|
||||
+ goto -> bb2;
|
||||
}
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
include ../tools.mk
|
||||
|
||||
# Test that hir-tree output doesn't crash and includes
|
||||
# the string constant we would expect to see.
|
||||
|
||||
all:
|
||||
$(RUSTC) -o $(TMPDIR)/input.hir -Z unpretty=hir-tree input.rs
|
||||
$(CGREP) '"Hello, Rustaceans!\n"' < $(TMPDIR)/input.hir
|
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, Rustaceans!");
|
||||
}
|
9
tests/ui/extern/issue-95829.stderr
vendored
9
tests/ui/extern/issue-95829.stderr
vendored
@ -16,17 +16,12 @@ LL | | }
|
||||
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/issue-95829.rs:4:14
|
||||
--> $DIR/issue-95829.rs:4:5
|
||||
|
|
||||
LL | extern {
|
||||
| ------ in this `extern` block
|
||||
LL | async fn L() {
|
||||
| ^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn L() {
|
||||
| ~~
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
//@ force-host
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::Literal;
|
||||
|
||||
fn test() {
|
||||
Literal::byte_character(b'a'); //~ ERROR use of unstable library feature 'proc_macro_byte_character'
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
error[E0658]: use of unstable library feature 'proc_macro_byte_character'
|
||||
--> $DIR/feature-gate-proc_macro_byte_character.rs:9:5
|
||||
|
|
||||
LL | Literal::byte_character(b'a');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #115268 <https://github.com/rust-lang/rust/issues/115268> for more information
|
||||
= help: add `#![feature(proc_macro_byte_character)]` 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 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -1,11 +0,0 @@
|
||||
//@ edition: 2021
|
||||
//@ force-host
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::Literal;
|
||||
|
||||
fn test() {
|
||||
Literal::c_string(c"a"); //~ ERROR use of unstable library feature 'proc_macro_c_str_literals'
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
error[E0658]: use of unstable library feature 'proc_macro_c_str_literals'
|
||||
--> $DIR/feature-gate-proc_macro_c_str_literals.rs:10:5
|
||||
|
|
||||
LL | Literal::c_string(c"a");
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #119750 <https://github.com/rust-lang/rust/issues/119750> for more information
|
||||
= help: add `#![feature(proc_macro_c_str_literals)]` 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 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
11
tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
Normal file
11
tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// Don't panic when iterating through the `hir::Map::parent_iter` of an RPITIT.
|
||||
|
||||
pub trait Foo {
|
||||
fn demo() -> impl Foo
|
||||
//~^ ERROR the trait bound `String: Copy` is not satisfied
|
||||
where
|
||||
String: Copy;
|
||||
//~^ ERROR the trait bound `String: Copy` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
27
tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
Normal file
27
tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/synthetic-hir-has-parent.rs:7:9
|
||||
|
|
||||
LL | String: Copy;
|
||||
| ^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
= help: see issue #48214
|
||||
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
||||
|
|
||||
LL + #![feature(trivial_bounds)]
|
||||
|
|
||||
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/synthetic-hir-has-parent.rs:4:18
|
||||
|
|
||||
LL | fn demo() -> impl Foo
|
||||
| ^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
= help: see issue #48214
|
||||
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
||||
|
|
||||
LL + #![feature(trivial_bounds)]
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
79
tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
Normal file
79
tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// Regression test for #121473
|
||||
// Checks that no ICE occurs when `size_of`
|
||||
// is applied to a struct that has an unsized
|
||||
// field which is not its last field
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
pub struct BadStruct {
|
||||
pub field1: i32,
|
||||
pub field2: str, // Unsized field that is not the last field
|
||||
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||
pub field3: [u8; 16],
|
||||
}
|
||||
|
||||
enum BadEnum1 {
|
||||
Variant1 {
|
||||
field1: i32,
|
||||
field2: str, // Unsized
|
||||
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||
field3: [u8; 16],
|
||||
},
|
||||
}
|
||||
|
||||
enum BadEnum2 {
|
||||
Variant1(
|
||||
i32,
|
||||
str, // Unsized
|
||||
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||
[u8; 16]
|
||||
),
|
||||
}
|
||||
|
||||
enum BadEnumMultiVariant {
|
||||
Variant1(i32),
|
||||
Variant2 {
|
||||
field1: i32,
|
||||
field2: str, // Unsized
|
||||
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||
field3: [u8; 16],
|
||||
},
|
||||
Variant3
|
||||
}
|
||||
|
||||
union BadUnion {
|
||||
field1: i32,
|
||||
field2: str, // Unsized
|
||||
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||
//~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
field3: [u8; 16],
|
||||
}
|
||||
|
||||
// Used to test that projection type fields that normalize
|
||||
// to a sized type do not cause problems
|
||||
struct StructWithProjections<'a>
|
||||
{
|
||||
field1: <&'a [i32] as IntoIterator>::IntoIter,
|
||||
field2: i32
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let _a = &size_of::<BadStruct>();
|
||||
assert_eq!(size_of::<BadStruct>(), 21);
|
||||
|
||||
let _a = &size_of::<BadEnum1>();
|
||||
assert_eq!(size_of::<BadEnum1>(), 21);
|
||||
|
||||
let _a = &size_of::<BadEnum2>();
|
||||
assert_eq!(size_of::<BadEnum2>(), 21);
|
||||
|
||||
let _a = &size_of::<BadEnumMultiVariant>();
|
||||
assert_eq!(size_of::<BadEnumMultiVariant>(), 21);
|
||||
|
||||
let _a = &size_of::<BadUnion>();
|
||||
assert_eq!(size_of::<BadUnion>(), 21);
|
||||
|
||||
let _a = &size_of::<StructWithProjections>();
|
||||
assert_eq!(size_of::<StructWithProjections>(), 21);
|
||||
let _a = StructWithProjections { field1: [1, 3].iter(), field2: 3 };
|
||||
}
|
106
tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
Normal file
106
tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
Normal file
@ -0,0 +1,106 @@
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/ice-non-last-unsized-field-issue-121473.rs:10:17
|
||||
|
|
||||
LL | pub field2: str, // Unsized field that is not the last field
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: only the last field of a struct may have a dynamically sized type
|
||||
= help: change the field's type to have a statically known size
|
||||
help: borrowed types always have a statically known size
|
||||
|
|
||||
LL | pub field2: &str, // Unsized field that is not the last field
|
||||
| +
|
||||
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
||||
|
|
||||
LL | pub field2: Box<str>, // Unsized field that is not the last field
|
||||
| ++++ +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/ice-non-last-unsized-field-issue-121473.rs:18:17
|
||||
|
|
||||
LL | field2: str, // Unsized
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: no field of an enum variant may have a dynamically sized type
|
||||
= help: change the field's type to have a statically known size
|
||||
help: borrowed types always have a statically known size
|
||||
|
|
||||
LL | field2: &str, // Unsized
|
||||
| +
|
||||
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
||||
|
|
||||
LL | field2: Box<str>, // Unsized
|
||||
| ++++ +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/ice-non-last-unsized-field-issue-121473.rs:27:9
|
||||
|
|
||||
LL | str, // Unsized
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: no field of an enum variant may have a dynamically sized type
|
||||
= help: change the field's type to have a statically known size
|
||||
help: borrowed types always have a statically known size
|
||||
|
|
||||
LL | &str, // Unsized
|
||||
| +
|
||||
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
||||
|
|
||||
LL | Box<str>, // Unsized
|
||||
| ++++ +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/ice-non-last-unsized-field-issue-121473.rs:37:17
|
||||
|
|
||||
LL | field2: str, // Unsized
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: no field of an enum variant may have a dynamically sized type
|
||||
= help: change the field's type to have a statically known size
|
||||
help: borrowed types always have a statically known size
|
||||
|
|
||||
LL | field2: &str, // Unsized
|
||||
| +
|
||||
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
||||
|
|
||||
LL | field2: Box<str>, // Unsized
|
||||
| ++++ +
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:13
|
||||
|
|
||||
LL | field2: str, // Unsized
|
||||
| ^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: no field of a union may have a dynamically sized type
|
||||
= help: change the field's type to have a statically known size
|
||||
help: borrowed types always have a statically known size
|
||||
|
|
||||
LL | field2: &str, // Unsized
|
||||
| +
|
||||
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
||||
|
|
||||
LL | field2: Box<str>, // Unsized
|
||||
| ++++ +
|
||||
|
||||
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
--> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:5
|
||||
|
|
||||
LL | field2: str, // Unsized
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
help: wrap the field type in `ManuallyDrop<...>`
|
||||
|
|
||||
LL | field2: std::mem::ManuallyDrop<str>, // Unsized
|
||||
| +++++++++++++++++++++++ +
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0740.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
@ -3,15 +3,57 @@
|
||||
|
||||
#![feature(if_let_guard)]
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn all_patterns_are_tested() {
|
||||
// Even though `x` is never actually moved out of, we don't want borrowck results to be based on
|
||||
// whether MIR lowering reveals which patterns are unreachable.
|
||||
let x = String::new();
|
||||
match true {
|
||||
_ => {},
|
||||
_ => drop(x),
|
||||
}
|
||||
// Borrowck must not know the second arm is never run.
|
||||
drop(x); //~ ERROR use of moved value
|
||||
|
||||
let x = String::new();
|
||||
if let _ = true { //~ WARN irrefutable
|
||||
} else {
|
||||
drop(x)
|
||||
}
|
||||
// Borrowck must not know the else branch is never run.
|
||||
drop(x); //~ ERROR use of moved value
|
||||
|
||||
let x = (String::new(), String::new());
|
||||
match x {
|
||||
(y, _) | (_, y) => (),
|
||||
}
|
||||
&x.0; //~ ERROR borrow of moved value
|
||||
// Borrowck must not know the second pattern never matches.
|
||||
&x.1; //~ ERROR borrow of moved value
|
||||
|
||||
let x = (String::new(), String::new());
|
||||
let ((y, _) | (_, y)) = x;
|
||||
&x.0; //~ ERROR borrow of moved value
|
||||
// Borrowck must not know the second pattern never matches.
|
||||
&x.1; //~ ERROR borrow of moved value
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn guard_always_precedes_arm(y: i32) {
|
||||
let mut x;
|
||||
// x should always be initialized, as the only way to reach the arm is
|
||||
// through the guard.
|
||||
let mut x;
|
||||
match y {
|
||||
0 | 2 if { x = 2; true } => x,
|
||||
_ => 2,
|
||||
};
|
||||
|
||||
let mut x;
|
||||
match y {
|
||||
_ => 2,
|
||||
0 | 2 if { x = 2; true } => x,
|
||||
};
|
||||
|
||||
let mut x;
|
||||
match y {
|
||||
0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
|
||||
@ -19,51 +61,58 @@ fn guard_always_precedes_arm(y: i32) {
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn guard_may_be_skipped(y: i32) {
|
||||
// Even though x *is* always initialized, we don't want to have borrowck results be based on
|
||||
// whether MIR lowering reveals which patterns are exhaustive.
|
||||
let x;
|
||||
match y {
|
||||
_ if { x = 2; true } => {},
|
||||
// Borrowck must not know the guard is always run.
|
||||
_ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
|
||||
};
|
||||
|
||||
let x;
|
||||
// Even though x *is* always initialized, we don't want to have borrowck
|
||||
// results be based on whether patterns are exhaustive.
|
||||
match y {
|
||||
_ if { x = 2; true } => 1,
|
||||
_ if {
|
||||
x; //~ ERROR E0381
|
||||
false
|
||||
} => 2,
|
||||
// Borrowck must not know the guard is always run.
|
||||
_ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized
|
||||
_ => 3,
|
||||
};
|
||||
|
||||
let x;
|
||||
match y {
|
||||
_ if let Some(()) = { x = 2; Some(()) } => 1,
|
||||
_ if let Some(()) = {
|
||||
x; //~ ERROR E0381
|
||||
None
|
||||
} => 2,
|
||||
_ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized
|
||||
_ => 3,
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn guard_may_be_taken(y: bool) {
|
||||
let x = String::new();
|
||||
// Even though x *is* never moved before the use, we don't want to have
|
||||
// borrowck results be based on whether patterns are disjoint.
|
||||
let x = String::new();
|
||||
match y {
|
||||
false if { drop(x); true } => 1,
|
||||
true => {
|
||||
x; //~ ERROR use of moved value: `x`
|
||||
2
|
||||
}
|
||||
false => 3,
|
||||
false if { drop(x); true } => {},
|
||||
// Borrowck must not know the guard is not run in the `true` case.
|
||||
true => drop(x), //~ ERROR use of moved value: `x`
|
||||
false => {},
|
||||
};
|
||||
|
||||
// Fine in the other order.
|
||||
let x = String::new();
|
||||
match y {
|
||||
true => drop(x),
|
||||
false if { drop(x); true } => {},
|
||||
false => {},
|
||||
};
|
||||
|
||||
let x = String::new();
|
||||
match y {
|
||||
false if let Some(()) = { drop(x); Some(()) } => 1,
|
||||
true => {
|
||||
x; //~ ERROR use of moved value: `x`
|
||||
2
|
||||
}
|
||||
false => 3,
|
||||
false if let Some(()) = { drop(x); Some(()) } => {},
|
||||
true => drop(x), //~ ERROR use of moved value: `x`
|
||||
false => {},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,128 @@
|
||||
error[E0381]: used binding `x` isn't initialized
|
||||
--> $DIR/match-cfg-fake-edges.rs:29:13
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/match-cfg-fake-edges.rs:19:8
|
||||
|
|
||||
LL | if let _ = true {
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/match-cfg-fake-edges.rs:16:10
|
||||
|
|
||||
LL | let x = String::new();
|
||||
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | _ => drop(x),
|
||||
| - value moved here
|
||||
...
|
||||
LL | drop(x);
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | _ => drop(x.clone()),
|
||||
| ++++++++
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/match-cfg-fake-edges.rs:24:10
|
||||
|
|
||||
LL | let x = String::new();
|
||||
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | drop(x)
|
||||
| - value moved here
|
||||
...
|
||||
LL | drop(x);
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | drop(x.clone())
|
||||
| ++++++++
|
||||
|
||||
error[E0382]: borrow of moved value: `x.0`
|
||||
--> $DIR/match-cfg-fake-edges.rs:30:5
|
||||
|
|
||||
LL | (y, _) | (_, y) => (),
|
||||
| - value moved here
|
||||
LL | }
|
||||
LL | &x.0;
|
||||
| ^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | (ref y, _) | (_, y) => (),
|
||||
| +++
|
||||
|
||||
error[E0382]: borrow of moved value: `x.1`
|
||||
--> $DIR/match-cfg-fake-edges.rs:32:5
|
||||
|
|
||||
LL | (y, _) | (_, y) => (),
|
||||
| - value moved here
|
||||
...
|
||||
LL | &x.1;
|
||||
| ^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | (y, _) | (_, ref y) => (),
|
||||
| +++
|
||||
|
||||
error[E0382]: borrow of moved value: `x.0`
|
||||
--> $DIR/match-cfg-fake-edges.rs:36:5
|
||||
|
|
||||
LL | let ((y, _) | (_, y)) = x;
|
||||
| - value moved here
|
||||
LL | &x.0;
|
||||
| ^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | let ((ref y, _) | (_, y)) = x;
|
||||
| +++
|
||||
|
||||
error[E0382]: borrow of moved value: `x.1`
|
||||
--> $DIR/match-cfg-fake-edges.rs:38:5
|
||||
|
|
||||
LL | let ((y, _) | (_, y)) = x;
|
||||
| - value moved here
|
||||
...
|
||||
LL | &x.1;
|
||||
| ^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | let ((y, _) | (_, ref y)) = x;
|
||||
| +++
|
||||
|
||||
error[E0381]: used binding `x` is possibly-uninitialized
|
||||
--> $DIR/match-cfg-fake-edges.rs:72:19
|
||||
|
|
||||
LL | let x;
|
||||
| - binding declared here but left uninitialized
|
||||
...
|
||||
LL | _ => drop(x),
|
||||
| - ^ `x` used here but it is possibly-uninitialized
|
||||
| |
|
||||
| if this pattern is matched, `x` is not initialized
|
||||
|
||||
error[E0381]: used binding `x` isn't initialized
|
||||
--> $DIR/match-cfg-fake-edges.rs:79:16
|
||||
|
|
||||
LL | let x;
|
||||
| - binding declared here but left uninitialized
|
||||
LL | match y {
|
||||
LL | _ if { x = 2; true } => 1,
|
||||
| ----- binding initialized here in some conditions
|
||||
LL | _ if {
|
||||
LL | x;
|
||||
| ^ `x` used here but it isn't initialized
|
||||
LL | // Borrowck must not know the guard is always run.
|
||||
LL | _ if { x; false } => 2,
|
||||
| ^ `x` used here but it isn't initialized
|
||||
|
|
||||
help: consider assigning a value
|
||||
|
|
||||
@ -16,16 +130,15 @@ LL | let x = 0;
|
||||
| +++
|
||||
|
||||
error[E0381]: used binding `x` isn't initialized
|
||||
--> $DIR/match-cfg-fake-edges.rs:39:13
|
||||
--> $DIR/match-cfg-fake-edges.rs:86:31
|
||||
|
|
||||
LL | let x;
|
||||
| - binding declared here but left uninitialized
|
||||
LL | match y {
|
||||
LL | _ if let Some(()) = { x = 2; Some(()) } => 1,
|
||||
| ----- binding initialized here in some conditions
|
||||
LL | _ if let Some(()) = {
|
||||
LL | x;
|
||||
| ^ `x` used here but it isn't initialized
|
||||
LL | _ if let Some(()) = { x; None } => 2,
|
||||
| ^ `x` used here but it isn't initialized
|
||||
|
|
||||
help: consider assigning a value
|
||||
|
|
||||
@ -33,40 +146,39 @@ LL | let x = 0;
|
||||
| +++
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/match-cfg-fake-edges.rs:53:13
|
||||
|
|
||||
LL | let x = String::new();
|
||||
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | false if { drop(x); true } => 1,
|
||||
| - value moved here
|
||||
LL | true => {
|
||||
LL | x;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | false if { drop(x.clone()); true } => 1,
|
||||
| ++++++++
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/match-cfg-fake-edges.rs:63:13
|
||||
--> $DIR/match-cfg-fake-edges.rs:99:22
|
||||
|
|
||||
LL | let x = String::new();
|
||||
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
|
||||
LL | match y {
|
||||
LL | false if let Some(()) = { drop(x); Some(()) } => 1,
|
||||
| - value moved here
|
||||
LL | true => {
|
||||
LL | x;
|
||||
| ^ value used here after move
|
||||
LL | false if { drop(x); true } => {},
|
||||
| - value moved here
|
||||
LL | // Borrowck must not know the guard is not run in the `true` case.
|
||||
LL | true => drop(x),
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
|
||||
LL | false if { drop(x.clone()); true } => {},
|
||||
| ++++++++
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/match-cfg-fake-edges.rs:114:22
|
||||
|
|
||||
LL | let x = String::new();
|
||||
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
|
||||
LL | match y {
|
||||
LL | false if let Some(()) = { drop(x); Some(()) } => {},
|
||||
| - value moved here
|
||||
LL | true => drop(x),
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | false if let Some(()) = { drop(x.clone()); Some(()) } => {},
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 11 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0381, E0382.
|
||||
For more information about an error, try `rustc --explain E0381`.
|
||||
|
@ -5,13 +5,20 @@ fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
|
||||
let r = &mut y.1;
|
||||
// We don't actually test y.1 to select the second arm, but we don't want
|
||||
// borrowck results to be based on the order we match patterns.
|
||||
match y { //~ ERROR cannot use `y.1` because it was mutably borrowed
|
||||
(false, true) => 1,
|
||||
(true, _) => {
|
||||
r;
|
||||
2
|
||||
}
|
||||
(false, _) => 3,
|
||||
match y {
|
||||
//~^ ERROR cannot use `y.1` because it was mutably borrowed
|
||||
(false, true) => {}
|
||||
// Borrowck must not know we don't test `y.1` when `y.0` is `true`.
|
||||
(true, _) => drop(r),
|
||||
(false, _) => {}
|
||||
};
|
||||
|
||||
// Fine in the other order.
|
||||
let r = &mut y.1;
|
||||
match y {
|
||||
(true, _) => drop(r),
|
||||
(false, true) => {}
|
||||
(false, _) => {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,8 @@ LL | let r = &mut y.1;
|
||||
LL | match y {
|
||||
| ^^^^^^^ use of borrowed `y.1`
|
||||
...
|
||||
LL | r;
|
||||
| - borrow later used here
|
||||
LL | (true, _) => drop(r),
|
||||
| - borrow later used here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -48,6 +48,9 @@ fn main() {
|
||||
const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks
|
||||
//~^ ERROR functions cannot be both `const` and `async`
|
||||
//~| ERROR functions in `extern` blocks
|
||||
//~| ERROR functions in `extern` blocks
|
||||
//~| ERROR functions in `extern` blocks
|
||||
//~| ERROR functions cannot be both `const` and `async`
|
||||
}
|
||||
}
|
||||
|
@ -71,73 +71,75 @@ LL | const async unsafe extern "C" fn fi5() {}
|
||||
| `const` because of this
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:46:18
|
||||
--> $DIR/fn-header-semantic-fail.rs:46:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
LL | async fn fe1();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn fe1();
|
||||
| ~~
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:47:19
|
||||
--> $DIR/fn-header-semantic-fail.rs:47:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
LL | async fn fe1();
|
||||
LL | unsafe fn fe2();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn fe2();
|
||||
| ~~
|
||||
| ^^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:18
|
||||
--> $DIR/fn-header-semantic-fail.rs:48:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const fn fe3();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn fe3();
|
||||
| ~~
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:49:23
|
||||
--> $DIR/fn-header-semantic-fail.rs:49:9
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | extern "C" fn fe4();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn fe4();
|
||||
| ~~
|
||||
| ^^^^^^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:42
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:21
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^
|
||||
| ^^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:15
|
||||
|
|
||||
help: remove the qualifiers
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:9
|
||||
|
|
||||
LL | fn fe5();
|
||||
| ~~
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:28
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const async unsafe extern "C" fn fe5();
|
||||
| ^^^^^^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions cannot be both `const` and `async`
|
||||
--> $DIR/fn-header-semantic-fail.rs:50:9
|
||||
@ -148,6 +150,6 @@ LL | const async unsafe extern "C" fn fe5();
|
||||
| | `async` because of this
|
||||
| `const` because of this
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0379`.
|
||||
|
@ -3,6 +3,7 @@ extern "C" {
|
||||
//~^ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
const unsafe fn bar();
|
||||
//~^ ERROR functions in `extern` blocks cannot have qualifiers
|
||||
//~| ERROR functions in `extern` blocks cannot have qualifiers
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,29 +1,28 @@
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:2:14
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:2:5
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
LL | const fn foo();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn foo();
|
||||
| ~~
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:4:21
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:4:11
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const unsafe fn bar();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn bar();
|
||||
| ~~
|
||||
| ^^^^^^ help: remove this qualifier
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/no-const-fn-in-extern-block.rs:4:5
|
||||
|
|
||||
LL | extern "C" {
|
||||
| ---------- in this `extern` block
|
||||
...
|
||||
LL | const unsafe fn bar();
|
||||
| ^^^^^ help: remove this qualifier
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -11,18 +11,13 @@ LL | extern "C" unsafe {
|
||||
| ^^^^^^
|
||||
|
||||
error: functions in `extern` blocks cannot have qualifiers
|
||||
--> $DIR/unsafe-foreign-mod-2.rs:4:15
|
||||
--> $DIR/unsafe-foreign-mod-2.rs:4:5
|
||||
|
|
||||
LL | extern "C" unsafe {
|
||||
| ----------------- in this `extern` block
|
||||
...
|
||||
LL | unsafe fn foo();
|
||||
| ^^^
|
||||
|
|
||||
help: remove the qualifiers
|
||||
|
|
||||
LL | fn foo();
|
||||
| ~~
|
||||
| ^^^^^^ help: remove this qualifier
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
#![crate_type = "proc-macro"]
|
||||
#![crate_name = "proc_macro_api_tests"]
|
||||
#![feature(proc_macro_span)]
|
||||
#![feature(proc_macro_byte_character)]
|
||||
#![feature(proc_macro_c_str_literals)]
|
||||
#![deny(dead_code)] // catch if a test function is never called
|
||||
|
||||
extern crate proc_macro;
|
||||
|
10
tests/ui/unpretty/hir-tree.rs
Normal file
10
tests/ui/unpretty/hir-tree.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ build-pass
|
||||
//@ compile-flags: -o - -Zunpretty=hir-tree
|
||||
//@ check-stdout
|
||||
//@ dont-check-compiler-stdout
|
||||
//@ dont-check-compiler-stderr
|
||||
//@ regex-error-pattern: Hello, Rustaceans!
|
||||
|
||||
fn main() {
|
||||
println!("Hello, Rustaceans!");
|
||||
}
|
Loading…
Reference in New Issue
Block a user