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:
bors 2024-04-04 13:10:22 +00:00
commit 96eaf553e5
42 changed files with 915 additions and 534 deletions

View File

@ -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 { .. })
}

View File

@ -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

View File

@ -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 {

View File

@ -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)]

View File

@ -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);
}

View File

@ -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.
///

View File

@ -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,
);

View File

@ -59,7 +59,7 @@ fn coverage_ids_info<'tcx>(
_ => None,
})
.max()
.unwrap_or(CounterId::START);
.unwrap_or(CounterId::ZERO);
CoverageIdsInfo { max_counter_id }
}

View File

@ -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));
}

View File

@ -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);

View File

@ -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)

View File

@ -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();
}

View File

@ -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() {}

View File

@ -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()>)();
}

View File

@ -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

View File

@ -48,7 +48,7 @@ fn main() -> () {
}
bb2: {
falseEdge -> [real: bb15, imaginary: bb6];
falseEdge -> [real: bb15, imaginary: bb3];
}
bb3: {

View File

@ -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: {

View File

@ -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: {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -1,3 +0,0 @@
fn main() {
println!("Hello, Rustaceans!");
}

View File

@ -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

View File

@ -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'
}

View File

@ -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`.

View File

@ -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'
}

View File

@ -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`.

View 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() {}

View 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`.

View 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 };
}

View 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`.

View File

@ -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 => {},
};
}

View File

@ -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`.

View File

@ -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, _) => {}
};
}

View File

@ -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

View File

@ -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`
}
}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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;

View 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!");
}