1
Fork 0

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 { 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 { pub fn is_async(self) -> bool {
matches!(self, CoroutineKind::Async { .. }) 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 ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
.label = in this `extern` block .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 ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
.label = in this `extern` block .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`. /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { fn check_foreign_fn_headerless(
if header.has_qualifiers() { &self,
// Deconstruct to ensure exhaustiveness
FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader,
) {
let report_err = |span| {
self.dcx().emit_err(errors::FnQualifierInExtern { self.dcx().emit_err(errors::FnQualifierInExtern {
span: ident.span, span: span,
block: self.current_extern_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, .. }) => { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
self.check_defaultness(fi.span, *defaultness); self.check_defaultness(fi.span, *defaultness);
self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); 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); self.check_foreign_item_ascii_only(fi.ident);
} }
ForeignItemKind::TyAlias(box TyAlias { ForeignItemKind::TyAlias(box TyAlias {

View file

@ -270,11 +270,10 @@ pub struct FnBodyInExtern {
#[diag(ast_passes_extern_fn_qualifiers)] #[diag(ast_passes_extern_fn_qualifiers)]
pub struct FnQualifierInExtern { pub struct FnQualifierInExtern {
#[primary_span] #[primary_span]
#[suggestion(code = "", applicability = "maybe-incorrect")]
pub span: Span, pub span: Span,
#[label] #[label]
pub block: Span, pub block: Span,
#[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")]
pub sugg_span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View file

@ -24,8 +24,6 @@ pub(crate) mod ffi;
pub(crate) mod map_data; pub(crate) mod map_data;
pub mod mapgen; pub mod mapgen;
const VAR_ALIGN: Align = Align::EIGHT;
/// A context object for maintaining all state needed by the coverageinfo module. /// A context object for maintaining all state needed by the coverageinfo module.
pub struct CrateCoverageContext<'ll, 'tcx> { pub struct CrateCoverageContext<'ll, 'tcx> {
/// Coverage data for each instrumented function identified by DefId. /// 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_global_constant(llglobal, true);
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::set_section(llglobal, &covmap_section_name); 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); 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_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
llvm::set_visibility(llglobal, llvm::Visibility::Hidden); llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
llvm::set_section(llglobal, covfun_section_name); 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); llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
cx.add_used_global(llglobal); cx.add_used_global(llglobal);
} }

View file

@ -33,10 +33,6 @@ rustc_index::newtype_index! {
pub struct CounterId {} pub struct CounterId {}
} }
impl CounterId {
pub const START: Self = Self::ZERO;
}
rustc_index::newtype_index! { rustc_index::newtype_index! {
/// ID of a coverage-counter expression. Values ascend from 0. /// ID of a coverage-counter expression. Values ascend from 0.
/// ///
@ -55,10 +51,6 @@ rustc_index::newtype_index! {
pub struct ExpressionId {} 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 /// Enum that can hold a constant zero value, the ID of an physical coverage
/// counter, or the ID of a coverage-counter expression. /// counter, or the ID of a coverage-counter expression.
/// ///

View file

@ -214,12 +214,77 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// ///
/// ## False edges /// ## False edges
/// ///
/// We don't want to have the exact structure of the decision tree be /// We don't want to have the exact structure of the decision tree be visible through borrow
/// visible through borrow checking. False edges ensure that the CFG as /// checking. Specifically we want borrowck to think that:
/// seen by borrow checking doesn't encode this. False edges are added: /// - 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. /// For example, all of these would fail to error if borrowck could see the real CFG (examples
/// * From each otherwise block to the next pre-binding block. /// 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))] #[instrument(level = "debug", skip(self, arms))]
pub(crate) fn match_expr( pub(crate) fn match_expr(
&mut self, &mut self,
@ -365,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
for candidate in candidates { for candidate in candidates {
candidate.visit_leaves(|leaf_candidate| { candidate.visit_leaves(|leaf_candidate| {
if let Some(ref mut prev) = previous_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); previous_candidate = Some(leaf_candidate);
}); });
@ -1010,8 +1076,12 @@ struct Candidate<'pat, 'tcx> {
/// The block before the `bindings` have been established. /// The block before the `bindings` have been established.
pre_binding_block: Option<BasicBlock>, 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> { impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
@ -1033,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
or_span: None, or_span: None,
otherwise_block: None, otherwise_block: None,
pre_binding_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, otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'_, 'tcx>], 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 { match candidates {
[] => { [] => {
// If there are no candidates that still need testing, we're done. Since all matches are // 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() .into_iter()
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
.collect(); .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 /// 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 any_matches = self.cfg.start_new_block();
let or_span = candidate.or_span.take().unwrap(); let or_span = candidate.or_span.take().unwrap();
let source_info = self.source_info(or_span); 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) { for subcandidate in mem::take(&mut candidate.subcandidates) {
let or_block = subcandidate.pre_binding_block.unwrap(); let or_block = subcandidate.pre_binding_block.unwrap();
self.cfg.goto(or_block, source_info, any_matches); 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(); 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(); let fresh_block = self.cfg.start_new_block();
self.false_edges( self.false_edges(
block, block,
fresh_block, fresh_block,
candidate.next_candidate_pre_binding_block, candidate.next_candidate_start_block,
candidate_source_info, candidate_source_info,
); );
block = fresh_block; block = fresh_block;
@ -2132,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.false_edges( self.false_edges(
otherwise_post_guard_block, otherwise_post_guard_block,
otherwise_block, otherwise_block,
candidate.next_candidate_pre_binding_block, candidate.next_candidate_start_block,
source_info, source_info,
); );

View file

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

View file

@ -11,13 +11,14 @@ use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind, self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
TermKind, Ty, TyCtxt, UintTy, TermKind, Ty, TyCtxt, UintTy,
}; };
use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::sym; use rustc_span::sym;
use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::abi::call::{Conv, FnAbi, PassMode};
@ -182,14 +183,15 @@ fn encode_fnsig<'tcx>(
// Encode the return type // Encode the return type
let transform_ty_options = TransformTyOptions::from_bits(options.bits()) let transform_ty_options = TransformTyOptions::from_bits(options.bits())
.unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", 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)); s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
// Encode the parameter types // Encode the parameter types
let tys = fn_sig.inputs(); let tys = fn_sig.inputs();
if !tys.is_empty() { if !tys.is_empty() {
for ty in tys { 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)); s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
} }
@ -523,15 +525,9 @@ fn encode_ty<'tcx>(
ty::Array(ty0, len) => { ty::Array(ty0, len) => {
// A<array-length><element-type> // A<array-length><element-type>
let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
let mut s = String::from("A"); let mut s = String::from("A");
let _ = write!( let _ = write!(s, "{}", &len);
s,
"{}",
&len.try_to_scalar()
.unwrap()
.to_target_usize(&tcx.data_layout)
.expect("Array lens are defined in usize")
);
s.push_str(&encode_ty(tcx, *ty0, dict, options)); s.push_str(&encode_ty(tcx, *ty0, dict, options));
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s); typeid.push_str(&s);
@ -756,278 +752,208 @@ fn encode_ty<'tcx>(
typeid typeid
} }
/// Transforms predicates for being encoded and used in the substitution dictionary. struct TransformTy<'tcx> {
fn transform_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
predicates: &List<ty::PolyExistentialPredicate<'tcx>>, options: TransformTyOptions,
) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> { parents: Vec<Ty<'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),
}
}))
} }
/// Transforms args for being encoded and used in the substitution dictionary. impl<'tcx> TransformTy<'tcx> {
fn transform_args<'tcx>( fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
tcx: TyCtxt<'tcx>, TransformTy { tcx, options, parents: Vec::new() }
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)
} }
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
// c_void types into unit types unconditionally, generalizes pointers if // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms
// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if // all c_void types into unit types unconditionally, generalizes pointers if
// TransformTyOptions::NORMALIZE_INTEGERS option is set. // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
fn transform_ty<'tcx>( // TransformTyOptions::NORMALIZE_INTEGERS option is set.
tcx: TyCtxt<'tcx>, fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
mut ty: Ty<'tcx>, match t.kind() {
parents: &mut Vec<Ty<'tcx>>, ty::Array(..)
options: TransformTyOptions, | ty::Closure(..)
) -> Ty<'tcx> { | ty::Coroutine(..)
match ty.kind() { | ty::CoroutineClosure(..)
ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {} | ty::CoroutineWitness(..)
| ty::Float(..)
| ty::FnDef(..)
| ty::Foreign(..)
| ty::Never
| ty::Slice(..)
| ty::Str
| ty::Tuple(..) => t.super_fold_with(self),
ty::Bool => { ty::Bool => {
if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
// Note: on all platforms that Rust's currently supports, its size and alignment are // Note: on all platforms that Rust's currently supports, its size and alignment
// 1, and its ABI class is INTEGER - see Rust Layout and ABIs. // 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.) // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
// //
// Clang represents bool as an 8-bit unsigned integer. // Clang represents bool as an 8-bit unsigned integer.
ty = tcx.types.u8; self.tcx.types.u8
} } else {
} t
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
),
},
_ => (),
} }
} }
}
_ if ty.is_unit() => {} ty::Char => {
if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
ty::Tuple(tys) => { // Since #118032, char is guaranteed to have the same size, alignment, and
ty = Ty::new_tup_from_iter( // function call ABI as u32 on all platforms.
tcx, self.tcx.types.u32
tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)), } else {
); t
}
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;
} }
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 ty::Int(..) | ty::Uint(..) => {
// to using `PhantomData`, need to skip normalizing it if we hit it again. if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
parents.push(ty); // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
if ty0.is_any_ptr() && ty0.contains(ty) { // wide. All platforms we currently support have a C platform, and as a
ty = transform_ty( // consequence, isize/usize are at least 16-bit wide for all of them.
tcx, //
ty0, // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
parents, match t.kind() {
options | TransformTyOptions::GENERALIZE_POINTERS, ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
); 16 => self.tcx.types.i16,
} else { 32 => self.tcx.types.i32,
ty = transform_ty(tcx, ty0, parents, options); 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 { } else {
// Transform repr(transparent) types without non-ZST field into () t
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));
} }
} }
}
ty::RawPtr(ptr_ty, _) => { ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
if ty.is_mutable_ptr() { ty::Adt(adt_def, args) => {
ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)); 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 { } else {
ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx)); t.super_fold_with(self)
}
} 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));
} }
} }
}
ty::FnPtr(fn_sig) => { ty::Ref(..) => {
if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx)); if t.is_mutable_ptr() {
} else { Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
let parameters: Vec<Ty<'tcx>> = fn_sig } else {
.skip_binder() Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
.inputs() }
.iter() } else {
.map(|ty| transform_ty(tcx, *ty, parents, options)) t.super_fold_with(self)
.collect(); }
let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options); }
ty = Ty::new_fn_ptr(
tcx, ty::RawPtr(..) => {
ty::Binder::bind_with_vars( if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
tcx.mk_fn_sig( if t.is_mutable_ptr() {
parameters, Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
output, } else {
fn_sig.c_variadic(), Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
fn_sig.unsafety(), }
fn_sig.abi(), } else {
), t.super_fold_with(self)
fn_sig.bound_vars(), }
), }
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::Alias(..) => {
ty = Ty::new_dynamic( self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
tcx, }
transform_predicates(tcx, predicates),
tcx.lifetimes.re_erased,
*kind,
);
}
ty::Alias(..) => { ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
ty = transform_ty( bug!("fold_ty: unexpected `{:?}`", t.kind());
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 fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
} }
/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor /// 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 // Encode the return type
let transform_ty_options = TransformTyOptions::from_bits(options.bits()) let transform_ty_options = TransformTyOptions::from_bits(options.bits())
.unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", 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)); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
// Encode the parameter types // Encode the parameter types
@ -1080,7 +1007,7 @@ pub fn typeid_for_fnabi<'tcx>(
let mut pushed_arg = false; let mut pushed_arg = false;
for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
pushed_arg = true; 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)); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
} }
if !pushed_arg { if !pushed_arg {
@ -1093,8 +1020,7 @@ pub fn typeid_for_fnabi<'tcx>(
if fn_abi.args[n].mode == PassMode::Ignore { if fn_abi.args[n].mode == PassMode::Ignore {
continue; continue;
} }
let ty = let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options);
typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); 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, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
}; };
use rustc_middle::ty::print::with_no_trimmed_paths; 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_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
use rustc_span::sym; use rustc_span::sym;
use rustc_span::symbol::Symbol; 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 = let get_discriminant_type =
|min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max); |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);

View file

@ -1360,7 +1360,7 @@ impl Literal {
} }
/// Byte character 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 { pub fn byte_character(byte: u8) -> Literal {
let string = [byte].escape_ascii().to_string(); let string = [byte].escape_ascii().to_string();
Literal::new(bridge::LitKind::Byte, &string, None) Literal::new(bridge::LitKind::Byte, &string, None)
@ -1374,7 +1374,7 @@ impl Literal {
} }
/// C string 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 { pub fn c_string(string: &CStr) -> Literal {
let string = string.to_bytes().escape_ascii().to_string(); let string = string.to_bytes().escape_ascii().to_string();
Literal::new(bridge::LitKind::CStr, &string, None) Literal::new(bridge::LitKind::CStr, &string, None)

View file

@ -3,21 +3,12 @@
use crate::sys::c; use crate::sys::c;
use crate::thread; use crate::thread;
use super::api; /// Reserve stack space for use in stack overflow exceptions.
pub unsafe fn reserve_stack() {
pub struct Handler; let result = c::SetThreadStackGuarantee(&mut 0x5000);
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
impl Handler { // We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
pub unsafe fn new() -> Handler { debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
// 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
}
} }
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG { 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() { pub unsafe fn init() {
if c::AddVectoredExceptionHandler(0, Some(vectored_handler)).is_null() { let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
panic!("failed to install exception 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. // 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))] #![cfg_attr(test, allow(dead_code))]
pub struct Handler; pub unsafe fn reserve_stack() {}
impl Handler {
pub fn new() -> Handler {
Handler
}
}
pub unsafe fn init() {} pub unsafe fn init() {}

View file

@ -48,9 +48,8 @@ impl Thread {
extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
unsafe { unsafe {
// Next, set up our stack overflow handler which may get triggered if we run // Next, reserve some stack space for if we otherwise run out of stack.
// out of stack. stack_overflow::reserve_stack();
let _handler = stack_overflow::Handler::new();
// Finally, let's run some code. // Finally, let's run some code.
Box::from_raw(main as *mut Box<dyn FnOnce()>)(); 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/foreign-rust-exceptions/Makefile
run-make/fpic/Makefile run-make/fpic/Makefile
run-make/glibc-staticlib-args/Makefile run-make/glibc-staticlib-args/Makefile
run-make/hir-tree/Makefile
run-make/inaccessible-temp-dir/Makefile run-make/inaccessible-temp-dir/Makefile
run-make/include_bytes_deps/Makefile run-make/include_bytes_deps/Makefile
run-make/incr-add-rust-src-component/Makefile run-make/incr-add-rust-src-component/Makefile

View file

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

View file

@ -40,7 +40,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
} }
bb4: { bb4: {
falseEdge -> [real: bb12, imaginary: bb9]; falseEdge -> [real: bb12, imaginary: bb7];
} }
bb5: { bb5: {
@ -48,7 +48,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
} }
bb6: { bb6: {
falseEdge -> [real: bb16, imaginary: bb3]; falseEdge -> [real: bb16, imaginary: bb1];
} }
bb7: { bb7: {
@ -60,7 +60,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
} }
bb9: { bb9: {
falseEdge -> [real: bb15, imaginary: bb6]; falseEdge -> [real: bb15, imaginary: bb5];
} }
bb10: { bb10: {
@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
bb14: { bb14: {
StorageDead(_10); StorageDead(_10);
falseEdge -> [real: bb5, imaginary: bb9]; falseEdge -> [real: bb5, imaginary: bb7];
} }
bb15: { bb15: {

View file

@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
} }
bb2: { bb2: {
falseEdge -> [real: bb9, imaginary: bb4]; falseEdge -> [real: bb9, imaginary: bb3];
} }
bb3: { bb3: {
@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
} }
bb4: { bb4: {
falseEdge -> [real: bb12, imaginary: bb6]; falseEdge -> [real: bb12, imaginary: bb5];
} }
bb5: { bb5: {
@ -69,7 +69,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {
bb11: { bb11: {
StorageDead(_8); StorageDead(_8);
falseEdge -> [real: bb1, imaginary: bb4]; falseEdge -> [real: bb1, imaginary: bb3];
} }
bb12: { bb12: {

View file

@ -60,11 +60,11 @@
} }
- bb5: { - bb5: {
- falseEdge -> [real: bb13, imaginary: bb3]; - falseEdge -> [real: bb13, imaginary: bb2];
- } - }
- -
- bb6: { - bb6: {
- falseEdge -> [real: bb8, imaginary: bb5]; - falseEdge -> [real: bb8, imaginary: bb1];
- } - }
- -
- bb7: { - bb7: {
@ -127,7 +127,7 @@
StorageDead(_9); StorageDead(_9);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb1, imaginary: bb5]; - falseEdge -> [real: bb1, imaginary: bb1];
+ goto -> bb1; + goto -> bb1;
} }
@ -184,7 +184,7 @@
StorageDead(_12); StorageDead(_12);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb3]; - falseEdge -> [real: bb2, imaginary: bb2];
+ goto -> bb2; + goto -> bb2;
} }

View file

@ -60,11 +60,11 @@
} }
- bb5: { - bb5: {
- falseEdge -> [real: bb13, imaginary: bb3]; - falseEdge -> [real: bb13, imaginary: bb2];
- } - }
- -
- bb6: { - bb6: {
- falseEdge -> [real: bb8, imaginary: bb5]; - falseEdge -> [real: bb8, imaginary: bb1];
- } - }
- -
- bb7: { - bb7: {
@ -127,7 +127,7 @@
StorageDead(_9); StorageDead(_9);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb1, imaginary: bb5]; - falseEdge -> [real: bb1, imaginary: bb1];
+ goto -> bb1; + goto -> bb1;
} }
@ -184,7 +184,7 @@
StorageDead(_12); StorageDead(_12);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb3]; - falseEdge -> [real: bb2, imaginary: bb2];
+ goto -> 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 = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: functions in `extern` blocks cannot have qualifiers error: functions in `extern` blocks cannot have qualifiers
--> $DIR/issue-95829.rs:4:14 --> $DIR/issue-95829.rs:4:5
| |
LL | extern { LL | extern {
| ------ in this `extern` block | ------ in this `extern` block
LL | async fn L() { LL | async fn L() {
| ^ | ^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn L() {
| ~~
error: aborting due to 2 previous errors 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)] #![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) { fn guard_always_precedes_arm(y: i32) {
let mut x;
// x should always be initialized, as the only way to reach the arm is // x should always be initialized, as the only way to reach the arm is
// through the guard. // through the guard.
let mut x;
match y { match y {
0 | 2 if { x = 2; true } => x, 0 | 2 if { x = 2; true } => x,
_ => 2, _ => 2,
}; };
let mut x;
match y {
_ => 2,
0 | 2 if { x = 2; true } => x,
};
let mut x; let mut x;
match y { match y {
0 | 2 if let Some(()) = { x = 2; Some(()) } => x, 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) { 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; 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 { match y {
_ if { x = 2; true } => 1, _ if { x = 2; true } => 1,
_ if { // Borrowck must not know the guard is always run.
x; //~ ERROR E0381 _ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized
false
} => 2,
_ => 3, _ => 3,
}; };
let x; let x;
match y { match y {
_ if let Some(()) = { x = 2; Some(()) } => 1, _ if let Some(()) = { x = 2; Some(()) } => 1,
_ if let Some(()) = { _ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized
x; //~ ERROR E0381
None
} => 2,
_ => 3, _ => 3,
}; };
} }
#[rustfmt::skip]
fn guard_may_be_taken(y: bool) { 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 // Even though x *is* never moved before the use, we don't want to have
// borrowck results be based on whether patterns are disjoint. // borrowck results be based on whether patterns are disjoint.
let x = String::new();
match y { match y {
false if { drop(x); true } => 1, false if { drop(x); true } => {},
true => { // Borrowck must not know the guard is not run in the `true` case.
x; //~ ERROR use of moved value: `x` true => drop(x), //~ ERROR use of moved value: `x`
2 false => {},
} };
false => 3,
// Fine in the other order.
let x = String::new();
match y {
true => drop(x),
false if { drop(x); true } => {},
false => {},
}; };
let x = String::new(); let x = String::new();
match y { match y {
false if let Some(()) = { drop(x); Some(()) } => 1, false if let Some(()) = { drop(x); Some(()) } => {},
true => { true => drop(x), //~ ERROR use of moved value: `x`
x; //~ ERROR use of moved value: `x` false => {},
2
}
false => 3,
}; };
} }

View file

@ -1,14 +1,128 @@
error[E0381]: used binding `x` isn't initialized warning: irrefutable `if let` pattern
--> $DIR/match-cfg-fake-edges.rs:29:13 --> $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; LL | let x;
| - binding declared here but left uninitialized | - 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, LL | _ if { x = 2; true } => 1,
| ----- binding initialized here in some conditions | ----- binding initialized here in some conditions
LL | _ if { LL | // Borrowck must not know the guard is always run.
LL | x; LL | _ if { x; false } => 2,
| ^ `x` used here but it isn't initialized | ^ `x` used here but it isn't initialized
| |
help: consider assigning a value help: consider assigning a value
| |
@ -16,16 +130,15 @@ LL | let x = 0;
| +++ | +++
error[E0381]: used binding `x` isn't initialized 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; LL | let x;
| - binding declared here but left uninitialized | - binding declared here but left uninitialized
LL | match y { LL | match y {
LL | _ if let Some(()) = { x = 2; Some(()) } => 1, LL | _ if let Some(()) = { x = 2; Some(()) } => 1,
| ----- binding initialized here in some conditions | ----- binding initialized here in some conditions
LL | _ if let Some(()) = { LL | _ if let Some(()) = { x; None } => 2,
LL | x; | ^ `x` used here but it isn't initialized
| ^ `x` used here but it isn't initialized
| |
help: consider assigning a value help: consider assigning a value
| |
@ -33,40 +146,39 @@ LL | let x = 0;
| +++ | +++
error[E0382]: use of moved value: `x` error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:53: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 | 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
| |
LL | let x = String::new(); LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | match y { LL | match y {
LL | false if let Some(()) = { drop(x); Some(()) } => 1, LL | false if { drop(x); true } => {},
| - value moved here | - value moved here
LL | true => { LL | // Borrowck must not know the guard is not run in the `true` case.
LL | x; LL | true => drop(x),
| ^ value used here after move | ^ value used here after move
| |
help: consider cloning the value if the performance cost is acceptable 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. Some errors have detailed explanations: E0381, E0382.
For more information about an error, try `rustc --explain E0381`. 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; let r = &mut y.1;
// We don't actually test y.1 to select the second arm, but we don't want // 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. // borrowck results to be based on the order we match patterns.
match y { //~ ERROR cannot use `y.1` because it was mutably borrowed match y {
(false, true) => 1, //~^ ERROR cannot use `y.1` because it was mutably borrowed
(true, _) => { (false, true) => {}
r; // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
2 (true, _) => drop(r),
} (false, _) => {}
(false, _) => 3, };
// 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 { LL | match y {
| ^^^^^^^ use of borrowed `y.1` | ^^^^^^^ use of borrowed `y.1`
... ...
LL | r; LL | (true, _) => drop(r),
| - borrow later used here | - borrow later used here
error: aborting due to 1 previous error 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 const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
extern "C" fn fe4(); //~ 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 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 | `const` because of this
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
LL | async fn fe1(); LL | async fn fe1();
| ^^^ | ^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn fe1();
| ~~
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
LL | async fn fe1(); LL | async fn fe1();
LL | unsafe fn fe2(); LL | unsafe fn fe2();
| ^^^ | ^^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn fe2();
| ~~
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
... ...
LL | const fn fe3(); LL | const fn fe3();
| ^^^ | ^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn fe3();
| ~~
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
... ...
LL | extern "C" fn fe4(); LL | extern "C" fn fe4();
| ^^^ | ^^^^^^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn fe4();
| ~~
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
... ...
LL | const async unsafe extern "C" fn fe5(); 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` error: functions cannot be both `const` and `async`
--> $DIR/fn-header-semantic-fail.rs:50:9 --> $DIR/fn-header-semantic-fail.rs:50:9
@ -148,6 +150,6 @@ LL | const async unsafe extern "C" fn fe5();
| | `async` because of this | | `async` because of this
| `const` 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`. 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 //~^ ERROR functions in `extern` blocks cannot have qualifiers
const unsafe fn bar(); const unsafe fn bar();
//~^ ERROR functions in `extern` blocks cannot have qualifiers //~^ ERROR functions in `extern` blocks cannot have qualifiers
//~| ERROR functions in `extern` blocks cannot have qualifiers
} }
fn main() {} fn main() {}

View file

@ -1,29 +1,28 @@
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
LL | const fn foo(); LL | const fn foo();
| ^^^ | ^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn foo();
| ~~
error: functions in `extern` blocks cannot have qualifiers 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" { LL | extern "C" {
| ---------- in this `extern` block | ---------- in this `extern` block
... ...
LL | const unsafe fn bar(); LL | const unsafe fn bar();
| ^^^ | ^^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn bar();
| ~~
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 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 { LL | extern "C" unsafe {
| ----------------- in this `extern` block | ----------------- in this `extern` block
... ...
LL | unsafe fn foo(); LL | unsafe fn foo();
| ^^^ | ^^^^^^ help: remove this qualifier
|
help: remove the qualifiers
|
LL | fn foo();
| ~~
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View file

@ -5,8 +5,6 @@
#![crate_type = "proc-macro"] #![crate_type = "proc-macro"]
#![crate_name = "proc_macro_api_tests"] #![crate_name = "proc_macro_api_tests"]
#![feature(proc_macro_span)] #![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 #![deny(dead_code)] // catch if a test function is never called
extern crate proc_macro; 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!");
}